From 7c430fd6df0672ca168ab2959168953d3117ba9a Mon Sep 17 00:00:00 2001 From: ykisialiou Date: Fri, 26 Jul 2019 01:56:34 +0300 Subject: [PATCH 1/5] portal plan added --- apigee-cf-service-broker/README.md | 3 + .../commands/bind-route-to-app.js | 32 + .../commands/run-cf-app-route-binding.js | 15 + .../commands/service-plans.js | 12 + .../config/environment/development.js | 19 + .../config/environment/index.js | 90 + .../config/environment/production.js | 19 + .../config/environment/test.js | 26 + apigee-cf-service-broker/env-example | 5 + .../json-sample/cf-create-route.txt | 564 ++ .../json-sample/service-binding-c2c.json | 20 + ...service-binding-portal-empty-docstore.json | 20 + .../lib/controllers/api/api.js | 41 + .../lib/controllers/api/catalog.js | 46 + .../api/service-instances/index.js | 33 + .../service-instance.controller.js | 182 + .../lib/errors/constants.js | 14 + .../lib/errors/service-error.js | 34 + apigee-cf-service-broker/lib/helpers/auth.js | 155 + apigee-cf-service-broker/lib/helpers/enums.js | 30 + .../lib/helpers/extractors.js | 52 + .../lib/helpers/http-methods.js | 12 + .../lib/helpers/http-status.js | 8 + .../lib/helpers/http-utils.js | 132 + .../lib/helpers/logger.js | 193 + .../lib/helpers/random.js | 34 + .../lib/helpers/string.js | 5 + .../lib/middleware/action.validator.js | 27 + .../lib/middleware/auth.validator.js | 22 + .../lib/middleware/config.validator.js | 43 + .../lib/middleware/protocol.validator.js | 19 + .../lib/providers/apigee-api/api-product.js | 64 + .../lib/providers/apigee-api/base.js | 39 + .../lib/providers/apigee-api/folders.js | 64 + .../lib/providers/apigee-api/portal.js | 127 + .../lib/providers/apigee-api/specs.js | 159 + .../lib/providers/catalog_data.js | 118 + .../lib/providers/cf-binder.js | 400 + .../lib/providers/cf-nodejs-client/index.js | 158 + .../model/cloudcontroller/Apps.js | 505 ++ .../model/cloudcontroller/BuildPacks.js | 40 + .../model/cloudcontroller/CloudController.js | 101 + .../cloudcontroller/CloudControllerBase.js | 44 + .../model/cloudcontroller/Domains.js | 61 + .../model/cloudcontroller/Events.js | 49 + .../model/cloudcontroller/Jobs.js | 42 + .../model/cloudcontroller/Networking.js | 62 + .../model/cloudcontroller/Organizations.js | 184 + .../cloudcontroller/OrganizationsQuota.js | 112 + .../model/cloudcontroller/Routes.js | 135 + .../model/cloudcontroller/ServiceBindings.js | 116 + .../model/cloudcontroller/ServiceInstances.js | 176 + .../model/cloudcontroller/ServicePlans.js | 111 + .../model/cloudcontroller/Services.js | 111 + .../model/cloudcontroller/Spaces.js | 189 + .../model/cloudcontroller/SpacesQuota.js | 41 + .../model/cloudcontroller/Stacks.js | 41 + .../cloudcontroller/UserProvidedServices.js | 139 + .../model/cloudcontroller/Users.js | 133 + .../cf-nodejs-client/model/metrics/Logs.js | 65 + .../cf-nodejs-client/model/uaa/UsersUAA.js | 199 + .../lib/providers/edge_proxy.js | 213 + .../lib/providers/mgmt_api.js | 261 + .../lib/providers/open_api.js | 278 + .../lib/providers/service-binding.js | 103 + .../lib/providers/service-plans/index.js | 108 + .../lib/providers/service-plans/micro-c2c.js | 79 + .../service-plans/micro-coresident.js | 30 + .../lib/providers/service-plans/micro.js | 54 + .../lib/providers/service-plans/org.js | 40 + .../lib/providers/service-plans/portal.js | 268 + apigee-cf-service-broker/manifest.yml | 48 +- apigee-cf-service-broker/npm-shrinkwrap.json | 7076 +++++++++++------ apigee-cf-service-broker/package.json | 40 +- .../policy_templates/cache/responseCache.js | 2 +- .../policy_templates/mediation/jsonToXml.js | 2 +- .../policy_templates/mediation/xmlToJson.js | 2 +- .../policy_templates/quota/quota.js | 2 +- .../policy_templates/security/apikey.js | 2 +- .../security/verifyAccessToken.js | 2 +- .../scripts/genCoverageBadge.js | 2 +- apigee-cf-service-broker/server.js | 52 +- apigee-cf-service-broker/test/coverage.svg | 2 +- .../test/helpers/api_mocks.js | 518 +- .../test/helpers/openApi.json | 264 + .../test/helpers/openApi.yaml | 176 + apigee-cf-service-broker/test/manifest.yml | 0 87 files changed, 12947 insertions(+), 2369 deletions(-) create mode 100644 apigee-cf-service-broker/commands/bind-route-to-app.js create mode 100644 apigee-cf-service-broker/commands/run-cf-app-route-binding.js create mode 100644 apigee-cf-service-broker/commands/service-plans.js create mode 100644 apigee-cf-service-broker/config/environment/development.js create mode 100644 apigee-cf-service-broker/config/environment/index.js create mode 100644 apigee-cf-service-broker/config/environment/production.js create mode 100644 apigee-cf-service-broker/config/environment/test.js create mode 100644 apigee-cf-service-broker/env-example create mode 100644 apigee-cf-service-broker/json-sample/cf-create-route.txt create mode 100644 apigee-cf-service-broker/json-sample/service-binding-c2c.json create mode 100644 apigee-cf-service-broker/json-sample/service-binding-portal-empty-docstore.json create mode 100644 apigee-cf-service-broker/lib/controllers/api/api.js create mode 100644 apigee-cf-service-broker/lib/controllers/api/catalog.js create mode 100644 apigee-cf-service-broker/lib/controllers/api/service-instances/index.js create mode 100644 apigee-cf-service-broker/lib/controllers/api/service-instances/service-instance.controller.js create mode 100644 apigee-cf-service-broker/lib/errors/constants.js create mode 100644 apigee-cf-service-broker/lib/errors/service-error.js create mode 100644 apigee-cf-service-broker/lib/helpers/auth.js create mode 100644 apigee-cf-service-broker/lib/helpers/enums.js create mode 100644 apigee-cf-service-broker/lib/helpers/extractors.js create mode 100644 apigee-cf-service-broker/lib/helpers/http-methods.js create mode 100644 apigee-cf-service-broker/lib/helpers/http-status.js create mode 100644 apigee-cf-service-broker/lib/helpers/http-utils.js create mode 100644 apigee-cf-service-broker/lib/helpers/logger.js create mode 100644 apigee-cf-service-broker/lib/helpers/random.js create mode 100644 apigee-cf-service-broker/lib/helpers/string.js create mode 100644 apigee-cf-service-broker/lib/middleware/action.validator.js create mode 100644 apigee-cf-service-broker/lib/middleware/auth.validator.js create mode 100644 apigee-cf-service-broker/lib/middleware/config.validator.js create mode 100644 apigee-cf-service-broker/lib/middleware/protocol.validator.js create mode 100644 apigee-cf-service-broker/lib/providers/apigee-api/api-product.js create mode 100644 apigee-cf-service-broker/lib/providers/apigee-api/base.js create mode 100644 apigee-cf-service-broker/lib/providers/apigee-api/folders.js create mode 100644 apigee-cf-service-broker/lib/providers/apigee-api/portal.js create mode 100644 apigee-cf-service-broker/lib/providers/apigee-api/specs.js create mode 100644 apigee-cf-service-broker/lib/providers/catalog_data.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-binder.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/index.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Apps.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/BuildPacks.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/CloudController.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/CloudControllerBase.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Domains.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Events.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Jobs.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Networking.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Organizations.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/OrganizationsQuota.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Routes.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServiceBindings.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServiceInstances.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServicePlans.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Services.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Spaces.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/SpacesQuota.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Stacks.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/UserProvidedServices.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Users.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/metrics/Logs.js create mode 100644 apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/uaa/UsersUAA.js create mode 100644 apigee-cf-service-broker/lib/providers/edge_proxy.js create mode 100644 apigee-cf-service-broker/lib/providers/mgmt_api.js create mode 100644 apigee-cf-service-broker/lib/providers/open_api.js create mode 100644 apigee-cf-service-broker/lib/providers/service-binding.js create mode 100644 apigee-cf-service-broker/lib/providers/service-plans/index.js create mode 100644 apigee-cf-service-broker/lib/providers/service-plans/micro-c2c.js create mode 100644 apigee-cf-service-broker/lib/providers/service-plans/micro-coresident.js create mode 100644 apigee-cf-service-broker/lib/providers/service-plans/micro.js create mode 100644 apigee-cf-service-broker/lib/providers/service-plans/org.js create mode 100644 apigee-cf-service-broker/lib/providers/service-plans/portal.js create mode 100644 apigee-cf-service-broker/test/helpers/openApi.json create mode 100644 apigee-cf-service-broker/test/helpers/openApi.yaml create mode 100644 apigee-cf-service-broker/test/manifest.yml diff --git a/apigee-cf-service-broker/README.md b/apigee-cf-service-broker/README.md index dc3f8db..5c57256 100644 --- a/apigee-cf-service-broker/README.md +++ b/apigee-cf-service-broker/README.md @@ -7,9 +7,12 @@ This plan uses `route-services` to redirect traffic coming into Cloud Foundry to This plan uses `route-services` to redirect traffic coming into Cloud Foundry to the Apigee Microgateway application before being directed to the target application -- reducing the network latency that occurs in the `org` plan. 3. The `microgateway-coresident` plan: The `microgateway-coresident` plan allows a user to launch Apigee Microgateway in the same container as their target application. This plan does not need to use `route-services` in that traffic will not need to be redirected to a separate container or cloud url. By using the `microgateway-coresident` plan, users will see the lowest latencies (as there are no extra network hops) as well as better scalability in that every new application instance will be started with Apigee Microgateway alongside it. +4. The `portal` plan: The `portal` plan allows for the use of the Apigee public or private cloud to proxy an application, creates proxy, portal, api-product in Apigee edge for the target application +This plan uses `route-services` to redirect traffic coming into Cloud Foundry to an Edge proxy in the cloud before being directed back down to the target application. ## Based on your chosen plan(s), follow the instructions below: * For the `org` plan, follow the instructions [here](../docs/setup-org.md) * For the `microgateway` plan, follow the instructions [here](../docs/setup-microgateway.md) * For the `microgateway-decorator` plan, follow the instructions [here](../docs/setup-microgateway-coresident.md) + * For the `portal` plan, follow the instructions [here](../docs/setup-portal.md) diff --git a/apigee-cf-service-broker/commands/bind-route-to-app.js b/apigee-cf-service-broker/commands/bind-route-to-app.js new file mode 100644 index 0000000..4232db4 --- /dev/null +++ b/apigee-cf-service-broker/commands/bind-route-to-app.js @@ -0,0 +1,32 @@ +const path = require('path') +const commandLineArgs = require('command-line-args') +const { CF_API_URL, CFBinder } = require('../lib/providers/cf-binder') +const Apps = require(path.resolve('./lib/providers/cf-nodejs-client/model/cloudcontroller/Apps')) + +const optionDefinitions = [ + { name: 'src', alias: 's', type: String }, + { name: 'dst', alias: 'd', type: String }, +]; + +const options = commandLineArgs(optionDefinitions); + +const run = async () => { + const client = new CFBinder() + await client.login() + + const apps = await client.getApps({ + space: { metadata: { guid: '15ecd7cf-42b0-439d-a009-57df23b9c400' } } + }) + const app = apps.resources.find(r => r.entity.name = options.src) + + const route = await client.getRoute({ target_app_route: options.dst } ) + + const appsService = new Apps(CF_API_URL) + appsService.setToken(client.loginResponse) + + const mappedResult = await appsService.associateRoute(app.metadata.guid, route.metadata.guid) + + console.info('new route', JSON.stringify(app, null, 2), route, mappedResult) +} + +run() \ No newline at end of file diff --git a/apigee-cf-service-broker/commands/run-cf-app-route-binding.js b/apigee-cf-service-broker/commands/run-cf-app-route-binding.js new file mode 100644 index 0000000..f4c2d89 --- /dev/null +++ b/apigee-cf-service-broker/commands/run-cf-app-route-binding.js @@ -0,0 +1,15 @@ +const { CFBinder } = require('../lib/providers/cf-binder') + +const run = async () => { + const client = new CFBinder() + await client.login() + const result = await client.runBinding({ + "target_app_port": 80, + "target_app_route": "sample", + "target_app_space_name": "dev" + }) + console.info('RES', result) + // console.info('new route', client.getAppInternalFullHostname()) +} + +run() \ No newline at end of file diff --git a/apigee-cf-service-broker/commands/service-plans.js b/apigee-cf-service-broker/commands/service-plans.js new file mode 100644 index 0000000..3a9b307 --- /dev/null +++ b/apigee-cf-service-broker/commands/service-plans.js @@ -0,0 +1,12 @@ +const ServicePlans = require('../lib/providers/service-plans') + +const plan = new ServicePlans() +const microc2c = plan.getProvider('micro_c2c') +const microc2c = plan.getProvider('micro') + +console.info('microc2c.getUrlFromProxyToApp', microc2c.getUrlFromProxyToApp({})) +console.info('microc2c.deriveParams', microc2c.deriveParams({ + target_app_port: 20, + target_app_route: 'dev', + target_app_space_name: 'space' +})) diff --git a/apigee-cf-service-broker/config/environment/development.js b/apigee-cf-service-broker/config/environment/development.js new file mode 100644 index 0000000..54e96a0 --- /dev/null +++ b/apigee-cf-service-broker/config/environment/development.js @@ -0,0 +1,19 @@ +const path = require('path'); +require('dotenv').config(); + +// Development specific configuration +// ================================== +module.exports = { + cf: { + user: process.env.CF_LOGIN, + password: process.env.CF_LOGIN_PASSWORD, + appsBaseDomain: process.env.APPS_BASE_DOMAIN, + microgatewayAppName: process.env.MICROGATEWAY_APP_NAME, + brokerAppName: process.env.BROKER_APP_NAME + }, + auth: { + securityUserName: process.env.SECURITY_USER_NAME, + securityUserPassword: process.env.SECURITY_USER_PASSWORD, + type: 'staticauth' + } +}; diff --git a/apigee-cf-service-broker/config/environment/index.js b/apigee-cf-service-broker/config/environment/index.js new file mode 100644 index 0000000..b7ff5ad --- /dev/null +++ b/apigee-cf-service-broker/config/environment/index.js @@ -0,0 +1,90 @@ +const path = require('path') +const nconf = require('nconf') +const _ = require('lodash') +const logger = require(path.resolve('./lib/helpers/logger')) + +let vcapApplicationConfig + +Object.prototype.toString.call(process.env.VCAP_APPLICATION) === '[object String]' + ? vcapApplicationConfig = JSON.parse(process.env.VCAP_APPLICATION) + : vcapApplicationConfig = { + // for tests and local usage + application_name: 'cf-broker-name' + } + +// All configurations will extend these options +// ============================================ +const all = { + vcapApplication: vcapApplicationConfig, + env: process.env.NODE_ENV || 'development', + // Server port + port: process.env.PORT || 8888, + // Server IP + ip: process.env.IP || '0.0.0.0', + defaults: { + APIGEE_DASHBOARD_URL: 'https://enterprise.apigee.com/platform/#/', + APIGEE_MGMT_API_URL: 'https://api.enterprise.apigee.com/v1', + APIGEE_PROXY_DOMAIN: 'apigee.net', + APIGEE_PROXY_HOST_TEMPLATE: '${org}-${env}.${domain}', + APIGEE_PROXY_NAME_TEMPLATE: 'cf-${route}', + auth: 'staticauth' + } +}; + +// read in specific apigee configurations +all.getApigeeConfiguration = (userOrg, userEnv, callback) => { + const configString = nconf.get('APIGEE_CONFIGURATIONS') + + let configurations + + if (configString) { + try { + configurations = JSON.parse(configString) + } catch (e) { + logger.log.error(e) + + const loggerError = logger.ERR_CONFIG_PARSE( + null, + null, + `${configString}. With ERROR message: "${e.message}". Please make sure your configuration is in the correct JSON format` + ) + return callback(loggerError) + } + + for (var i = 0; i < configurations.length; i++) { + if (configurations[i].org === userOrg && configurations[i].env === userEnv) { + Object.keys(configurations[i]).forEach(function (key) { + nconf.set(key.toUpperCase(), configurations[i][key]) + logger.log.info('Config key: ', key.toUpperCase(), ' = ', configurations[i][key]) + }) + return callback(null, nconf) + } + } + const loggerError = logger.ERR_ORG_ENV_NOT_FOUND( + null, + null, + `Specified "org" = "${userOrg}" with "env" = "${userEnv}" do not exist in your Tile or Open Source Cloud Foundry configuration. Please contact your Cloud Foundry administrator for more assistance`) + return callback(loggerError) + } + const loggerError = logger.ERR_NO_CONFIGURATION() + callback(loggerError) +} + +// arguments, environment vars +nconf.use('memory') + .argv() + .env() + .defaults(all.defaults) + +all.default = nconf + +// Export the config object based on the NODE_ENV +// ============================================== +/* eslint-disable */ +const mod = require(`./${all.env.toLowerCase()}.js`) || {}; +/* eslint-enable */ + +module.exports = _.merge( + all, + mod, +); diff --git a/apigee-cf-service-broker/config/environment/production.js b/apigee-cf-service-broker/config/environment/production.js new file mode 100644 index 0000000..54e96a0 --- /dev/null +++ b/apigee-cf-service-broker/config/environment/production.js @@ -0,0 +1,19 @@ +const path = require('path'); +require('dotenv').config(); + +// Development specific configuration +// ================================== +module.exports = { + cf: { + user: process.env.CF_LOGIN, + password: process.env.CF_LOGIN_PASSWORD, + appsBaseDomain: process.env.APPS_BASE_DOMAIN, + microgatewayAppName: process.env.MICROGATEWAY_APP_NAME, + brokerAppName: process.env.BROKER_APP_NAME + }, + auth: { + securityUserName: process.env.SECURITY_USER_NAME, + securityUserPassword: process.env.SECURITY_USER_PASSWORD, + type: 'staticauth' + } +}; diff --git a/apigee-cf-service-broker/config/environment/test.js b/apigee-cf-service-broker/config/environment/test.js new file mode 100644 index 0000000..c67d259 --- /dev/null +++ b/apigee-cf-service-broker/config/environment/test.js @@ -0,0 +1,26 @@ +const path = require('path') +require('dotenv').config() + +const yaml = require('js-yaml') +const fs = require('fs') +const fromManifest = yaml.safeLoad(fs.readFileSync(path.resolve('./manifest.yml'), 'utf8')) + +// nconf.defaults(Object.assign({}, defaults, fromManifest.env)) + +// Development specific configuration +// ================================== +module.exports = { + defaults: fromManifest.env, + cf: { + user: 'cftester', + password: 'cftesting', + appsBaseDomain: 'cf-base-domain', + microgatewayAppName: 'c2c-mg-name', + brokerAppName: 'cf-broker-name' + }, + auth: { + securityUserName: 'tester', + securityUserPassword: 'testing', + type: 'staticauth' + } +}; diff --git a/apigee-cf-service-broker/env-example b/apigee-cf-service-broker/env-example new file mode 100644 index 0000000..67bc383 --- /dev/null +++ b/apigee-cf-service-broker/env-example @@ -0,0 +1,5 @@ +CF_LOGIN= +CF_LOGIN_PASSWORD= +MICRO_C2C_APP_NAME= +BROKER_APP_NAME= +APPS_BASE_DOMAIN= \ No newline at end of file diff --git a/apigee-cf-service-broker/json-sample/cf-create-route.txt b/apigee-cf-service-broker/json-sample/cf-create-route.txt new file mode 100644 index 0000000..129d6ce --- /dev/null +++ b/apigee-cf-service-broker/json-sample/cf-create-route.txt @@ -0,0 +1,564 @@ +cf -v create-route dev apps.pcf24.apigee.xyz --hostname edgemicro-app-harper +REQUEST: [2019-05-31T17:41:47+03:00] +GET /v2/info HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:41:47+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 741 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:41:47 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: 79f4fcaa-4b4b-47be-4e19-bc367fce7032::9249ef92-3e3b-4b9a-a5ab-1770c5d20a32 +{ + "api_version": "2.125.0", + "app_ssh_endpoint": "ssh.system.pcf24.apigee.xyz:2222", + "app_ssh_host_key_fingerprint": "ef:5a:7f:72:24:1e:18:9c:e0:cc:39:21:a1:47:9a:cf", + "app_ssh_oauth_client": "ssh-proxy", + "authorization_endpoint": "https://login.system.pcf24.apigee.xyz", + "build": "2.4.1-build.1", + "description": "https://docs.pivotal.io/pivotalcf/2-3/pcf-release-notes/runtime-rn.html", + "doppler_logging_endpoint": "wss://doppler.system.pcf24.apigee.xyz:443", + "min_cli_version": "6.23.0", + "min_recommended_cli_version": "6.23.0", + "name": "Pivotal Application Service", + "osbapi_version": "2.14", + "routing_endpoint": "https://api.system.pcf24.apigee.xyz/routing", + "support": "https://support.pivotal.io", + "token_endpoint": "https://uaa.system.pcf24.apigee.xyz", + "version": 0 +} + + +REQUEST: [2019-05-31T17:41:47+03:00] +GET /login HTTP/1.1 +Host: login.system.pcf24.apigee.xyz +Accept: application/json +Connection: close +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:41:48+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Cache-Control: no-store +Content-Language: en-US +Content-Length: 411 +Content-Type: application/json;charset=UTF-8 +Date: Fri, 31 May 2019 14:41:47 GMT +Set-Cookie: X-Uaa-Csrf=gL1oNY6HMNxEucJCLXWTxr; Max-Age=86400; Expires=Sat, 01-Jun-2019 14:41:48 GMT; Path=/; Secure; HttpOnly +Strict-Transport-Security: max-age=31536000 ; includeSubDomains +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Frame-Options: DENY +X-Vcap-Request-Id: 1927171e-dd90-4efe-7a48-968f94a8d23d +X-Xss-Protection: 1; mode=block +{ + "app": { + "version": "4.24.0" + }, + "commit_id": "16d9900", + "entityID": "http://login.system.pcf24.apigee.xyz", + "idpDefinitions": {}, + "links": { + "login": "https://login.system.pcf24.apigee.xyz", + "passwd": "/forgot_password", + "register": "/create_account", + "uaa": "https://uaa.system.pcf24.apigee.xyz" + }, + "prompts": { + "password": "[PRIVATE DATA HIDDEN]", + "username": [ + "text", + "Email" + ] + }, + "timestamp": "2018-11-06T01:20:26+0000", + "zone_name": "uaa" +} + + +Creating route edgemicro-app-harper.apps.pcf24.apigee.xyz for org dev / space dev as brokeruser... +REQUEST: [2019-05-31T17:41:48+03:00] +GET /v2/spaces?order-by=name&q=name%3Adev&q=organization_guid%3Ad90cc2e5-3517-4504-aa87-6e68bbd15da6 HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:41:48+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 1651 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:41:48 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: fd944f2b-9ea9-41b8-5931-68d0f36eebee::dde506c2-8028-44b5-ae4d-00f66ad36722 +{ + "next_url": null, + "prev_url": null, + "resources": [ + { + "entity": { + "allow_ssh": true, + "app_events_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/app_events", + "apps_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/apps", + "auditors_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/auditors", + "developers_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/developers", + "domains_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/domains", + "events_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/events", + "isolation_segment_guid": null, + "managers_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/managers", + "name": "dev", + "organization_guid": "d90cc2e5-3517-4504-aa87-6e68bbd15da6", + "organization_url": "/v2/organizations/d90cc2e5-3517-4504-aa87-6e68bbd15da6", + "routes_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/routes", + "security_groups_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/security_groups", + "service_instances_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/service_instances", + "space_quota_definition_guid": null, + "staging_security_groups_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/staging_security_groups" + }, + "metadata": { + "created_at": "2019-04-19T14:08:18Z", + "guid": "15ecd7cf-42b0-439d-a009-57df23b9c400", + "updated_at": "2019-04-19T14:08:18Z", + "url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400" + } + } + ], + "total_pages": 1, + "total_results": 1 +} + + +REQUEST: [2019-05-31T17:41:48+03:00] +GET /v2/shared_domains?q=name+IN+apps.pcf24.apigee.xyz HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:41:48+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 531 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:41:48 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: ed779c12-aae3-4533-5ca7-9860fb05831f::794fd15d-7f7f-4f5b-bb32-34ca237eb499 +{ + "next_url": null, + "prev_url": null, + "resources": [ + { + "entity": { + "internal": false, + "name": "apps.pcf24.apigee.xyz", + "router_group_guid": null, + "router_group_type": null + }, + "metadata": { + "created_at": "2018-12-21T12:27:12Z", + "guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", + "updated_at": "2019-05-04T10:21:01Z", + "url": "/v2/shared_domains/bb8dec35-6535-4ca9-8bca-5b84230f394d" + } + } + ], + "total_pages": 1, + "total_results": 1 +} + + +REQUEST: [2019-05-31T17:41:48+03:00] +GET /v2/organizations/d90cc2e5-3517-4504-aa87-6e68bbd15da6/private_domains?q=name+IN+apps.pcf24.apigee.xyz HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:41:48+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 107 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:41:48 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: 205e7bc9-92bf-42c5-5976-baedc98a697d::a5b0e48e-6759-46e2-a780-de016c970556 +{ + "next_url": null, + "prev_url": null, + "resources": null, + "total_pages": 1, + "total_results": 0 +} + + +REQUEST: [2019-05-31T17:41:48+03:00] +GET /v2/routes?q=domain_guid%3Abb8dec35-6535-4ca9-8bca-5b84230f394d&q=host%3Aedgemicro-app-harper&q=path%3A HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:41:48+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 107 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:41:48 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: 77ff6d08-bc72-4da4-4d83-3d69e2248979::c78139c9-41f9-406e-acdf-06e75758c5c0 +{ + "next_url": null, + "prev_url": null, + "resources": null, + "total_pages": 1, + "total_results": 0 +} + + +REQUEST: [2019-05-31T17:41:48+03:00] +GET /v2/routes/reserved/domain/bb8dec35-6535-4ca9-8bca-5b84230f394d?host=edgemicro-app-harper HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:41:48+03:00] +HTTP/1.1 404 Not Found +Alt-Svc: clear +Content-Length: 86 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:41:48 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: 69b34b75-ab61-4ff3-57a6-ec48a5ca5d07::b680c427-dc73-471c-8ea7-71ff3a72c968 +{ + "code": 10000, + "description": "Unknown request", + "error_code": "CF-NotFound" +} + + +REQUEST: [2019-05-31T17:41:48+03:00] +POST /v2/routes HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +Content-Type: application/json +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) +{ + "domain_guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", + "host": "edgemicro-app-harper", + "port": null, + "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400" +} + + +RESPONSE: [2019-05-31T17:41:49+03:00] +HTTP/1.1 201 Created +Alt-Svc: clear +Content-Length: 769 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:41:49 GMT +Location: /v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295 +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: 6adb9799-0b0b-40ea-63ff-995728fb1417::f58e88ca-75cc-4117-a010-b4018f0ff75f +{ + "entity": { + "apps_url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295/apps", + "domain_guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", + "domain_url": "/v2/shared_domains/bb8dec35-6535-4ca9-8bca-5b84230f394d", + "host": "edgemicro-app-harper", + "path": "", + "port": null, + "route_mappings_url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295/route_mappings", + "service_instance_guid": null, + "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400", + "space_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400" + }, + "metadata": { + "created_at": "2019-05-31T14:41:49Z", + "guid": "1094e037-3f74-48db-a8ba-a8e71ab39295", + "updated_at": "2019-05-31T14:41:49Z", + "url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295" + } +} + + +Route edgemicro-app-harper.apps.pcf24.apigee.xyz has been created. +OK + + +cf -v create-route dev apps.pcf24.apigee.xyz --hostname edgemicro-app-harper +REQUEST: [2019-05-31T17:51:57+03:00] +GET /v2/info HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:51:58+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 741 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:51:57 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: d79df8b0-994d-473f-75b9-6c389858cf85::de2c8c08-567b-4160-890d-95839226d721 +{ + "api_version": "2.125.0", + "app_ssh_endpoint": "ssh.system.pcf24.apigee.xyz:2222", + "app_ssh_host_key_fingerprint": "ef:5a:7f:72:24:1e:18:9c:e0:cc:39:21:a1:47:9a:cf", + "app_ssh_oauth_client": "ssh-proxy", + "authorization_endpoint": "https://login.system.pcf24.apigee.xyz", + "build": "2.4.1-build.1", + "description": "https://docs.pivotal.io/pivotalcf/2-3/pcf-release-notes/runtime-rn.html", + "doppler_logging_endpoint": "wss://doppler.system.pcf24.apigee.xyz:443", + "min_cli_version": "6.23.0", + "min_recommended_cli_version": "6.23.0", + "name": "Pivotal Application Service", + "osbapi_version": "2.14", + "routing_endpoint": "https://api.system.pcf24.apigee.xyz/routing", + "support": "https://support.pivotal.io", + "token_endpoint": "https://uaa.system.pcf24.apigee.xyz", + "version": 0 +} + + +REQUEST: [2019-05-31T17:51:58+03:00] +GET /login HTTP/1.1 +Host: login.system.pcf24.apigee.xyz +Accept: application/json +Connection: close +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:51:58+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Cache-Control: no-store +Content-Language: en-US +Content-Length: 411 +Content-Type: application/json;charset=UTF-8 +Date: Fri, 31 May 2019 14:51:57 GMT +Set-Cookie: X-Uaa-Csrf=eeC7q2JU4o6gP4ziWKWNij; Max-Age=86400; Expires=Sat, 01-Jun-2019 14:51:58 GMT; Path=/; Secure; HttpOnly +Strict-Transport-Security: max-age=31536000 ; includeSubDomains +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Frame-Options: DENY +X-Vcap-Request-Id: 80ced4fc-126f-44f1-59af-76abb7b133fc +X-Xss-Protection: 1; mode=block +{ + "app": { + "version": "4.24.0" + }, + "commit_id": "16d9900", + "entityID": "http://login.system.pcf24.apigee.xyz", + "idpDefinitions": {}, + "links": { + "login": "https://login.system.pcf24.apigee.xyz", + "passwd": "/forgot_password", + "register": "/create_account", + "uaa": "https://uaa.system.pcf24.apigee.xyz" + }, + "prompts": { + "password": "[PRIVATE DATA HIDDEN]", + "username": [ + "text", + "Email" + ] + }, + "timestamp": "2018-11-06T01:20:26+0000", + "zone_name": "uaa" +} + + +Creating route edgemicro-app-harper.apps.pcf24.apigee.xyz for org dev / space dev as brokeruser... +REQUEST: [2019-05-31T17:51:58+03:00] +GET /v2/spaces?order-by=name&q=name%3Adev&q=organization_guid%3Ad90cc2e5-3517-4504-aa87-6e68bbd15da6 HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:51:58+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 1651 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:51:58 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: e47b0fd5-862e-4035-6538-74d3a91347c2::04af1293-4e62-405c-ac0e-21e6b8083e36 +{ + "next_url": null, + "prev_url": null, + "resources": [ + { + "entity": { + "allow_ssh": true, + "app_events_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/app_events", + "apps_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/apps", + "auditors_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/auditors", + "developers_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/developers", + "domains_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/domains", + "events_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/events", + "isolation_segment_guid": null, + "managers_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/managers", + "name": "dev", + "organization_guid": "d90cc2e5-3517-4504-aa87-6e68bbd15da6", + "organization_url": "/v2/organizations/d90cc2e5-3517-4504-aa87-6e68bbd15da6", + "routes_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/routes", + "security_groups_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/security_groups", + "service_instances_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/service_instances", + "space_quota_definition_guid": null, + "staging_security_groups_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/staging_security_groups" + }, + "metadata": { + "created_at": "2019-04-19T14:08:18Z", + "guid": "15ecd7cf-42b0-439d-a009-57df23b9c400", + "updated_at": "2019-04-19T14:08:18Z", + "url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400" + } + } + ], + "total_pages": 1, + "total_results": 1 +} + + +REQUEST: [2019-05-31T17:51:58+03:00] +GET /v2/shared_domains?q=name+IN+apps.pcf24.apigee.xyz HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:51:58+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 531 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:51:58 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: f5392969-f180-4278-5b59-3526f28be7db::cebb0407-42a5-4779-9efc-8784966720d8 +{ + "next_url": null, + "prev_url": null, + "resources": [ + { + "entity": { + "internal": false, + "name": "apps.pcf24.apigee.xyz", + "router_group_guid": null, + "router_group_type": null + }, + "metadata": { + "created_at": "2018-12-21T12:27:12Z", + "guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", + "updated_at": "2019-05-04T10:21:01Z", + "url": "/v2/shared_domains/bb8dec35-6535-4ca9-8bca-5b84230f394d" + } + } + ], + "total_pages": 1, + "total_results": 1 +} + + +REQUEST: [2019-05-31T17:51:58+03:00] +GET /v2/organizations/d90cc2e5-3517-4504-aa87-6e68bbd15da6/private_domains?q=name+IN+apps.pcf24.apigee.xyz HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:51:58+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 107 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:51:58 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: bb493b94-833c-4c9a-6217-01a4acce8c81::5c98f3bc-e401-4e54-945f-8abeeb8634b0 +{ + "next_url": null, + "prev_url": null, + "resources": null, + "total_pages": 1, + "total_results": 0 +} + + +REQUEST: [2019-05-31T17:51:58+03:00] +GET /v2/routes?q=domain_guid%3Abb8dec35-6535-4ca9-8bca-5b84230f394d&q=host%3Aedgemicro-app-harper&q=path%3A HTTP/1.1 +Host: api.system.pcf24.apigee.xyz +Accept: application/json +Authorization: [PRIVATE DATA HIDDEN] +User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + +RESPONSE: [2019-05-31T17:51:59+03:00] +HTTP/1.1 200 OK +Alt-Svc: clear +Content-Length: 956 +Content-Type: application/json;charset=utf-8 +Date: Fri, 31 May 2019 14:51:58 GMT +Server: nginx +Via: 1.1 google +X-Content-Type-Options: nosniff +X-Vcap-Request-Id: 98560c58-72fa-4a97-4f96-785017f82668::7d405fa9-0e37-4098-8f59-986424a6c707 +{ + "next_url": null, + "prev_url": null, + "resources": [ + { + "entity": { + "apps_url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295/apps", + "domain_guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", + "domain_url": "/v2/shared_domains/bb8dec35-6535-4ca9-8bca-5b84230f394d", + "host": "edgemicro-app-harper", + "path": "", + "port": null, + "route_mappings_url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295/route_mappings", + "service_instance_guid": null, + "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400", + "space_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400" + }, + "metadata": { + "created_at": "2019-05-31T14:41:49Z", + "guid": "1094e037-3f74-48db-a8ba-a8e71ab39295", + "updated_at": "2019-05-31T14:41:49Z", + "url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295" + } + } + ], + "total_pages": 1, + "total_results": 1 +} + + +Route edgemicro-app-harper.apps.pcf24.apigee.xyz already exists. + +OK diff --git a/apigee-cf-service-broker/json-sample/service-binding-c2c.json b/apigee-cf-service-broker/json-sample/service-binding-c2c.json new file mode 100644 index 0000000..5307c5c --- /dev/null +++ b/apigee-cf-service-broker/json-sample/service-binding-c2c.json @@ -0,0 +1,20 @@ +{ + "service_id": "5E3F917B-9225-4BE4-802F-8F1491F714C0", + "plan_id": "2A7D9A35-1CB3-4E05-8085-CC0100331A96", + "bind_resource": { "route": "sample-4.apps.pcf24.apigee.xyz" }, + "context": { + "platform": "cloudfoundry", + "organization_guid": "d90cc2e5-3517-4504-aa87-6e68bbd15da6", + "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400" + }, + "parameters": { + "org": "yauhenikisialiou-eval", + "env": "test", + "micro_c2c": "c2c-test-service", + "target_app_route": "sample", + "target_app_port": "8080", + "action": "bind proxy", + "protocol": "http", + "bearer": "" + } +} \ No newline at end of file diff --git a/apigee-cf-service-broker/json-sample/service-binding-portal-empty-docstore.json b/apigee-cf-service-broker/json-sample/service-binding-portal-empty-docstore.json new file mode 100644 index 0000000..9681c98 --- /dev/null +++ b/apigee-cf-service-broker/json-sample/service-binding-portal-empty-docstore.json @@ -0,0 +1,20 @@ +{ + "comment": "Sample to create serivce binding - portal", + "service_id": "5E3F917B-9225-4BE4-802F-8F1491F714C0", + "plan_id": "04B7CC7F-EE5D-4BF4-A5D7-1C637651F545", + "bind_resource": { + "route": "sample-1.apps.pcf24.apigee.xyz" + }, + "context": { + "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400" + }, + "parameters": { + "env": "test", + "org": "yauhenikisialiou-eval", + "bearer": "", + "action": "bind proxy", + "protocol": "http", + "target_app_route": "sample", + "target_app_port": 8080 + } +} \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/controllers/api/api.js b/apigee-cf-service-broker/lib/controllers/api/api.js new file mode 100644 index 0000000..baf775e --- /dev/null +++ b/apigee-cf-service-broker/lib/controllers/api/api.js @@ -0,0 +1,41 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Dump out version info, hosting location, etc. + * @module + */ + +const path = require('path') + +const config = require(path.resolve('./config/environment')) +const express = require('express') +const router = express.Router() + +const auth = require(path.resolve('./lib/helpers/auth'))(config) + +router.use(auth) + +router.get('/', (req, res) => { + res.json({ message: 'This is the cf-apigee-broker CF Service Broker API.', configuration: 'Blocked' }) +}) + +/** + * Router for misc API + * @type express.Router + */ +module.exports = router diff --git a/apigee-cf-service-broker/lib/controllers/api/catalog.js b/apigee-cf-service-broker/lib/controllers/api/catalog.js new file mode 100644 index 0000000..13a7e9b --- /dev/null +++ b/apigee-cf-service-broker/lib/controllers/api/catalog.js @@ -0,0 +1,46 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Implementation of [catalog API for CF](http://docs.cloudfoundry.org/services/api.html) + * @module + */ + +const path = require('path') +const config = require(path.resolve('./config/environment')) +const express = require('express') +const router = express.Router() +const auth = require(path.resolve('./lib/helpers/auth'))(config) +const catalogData = require(path.resolve('./lib/providers/catalog_data')) + +// TODO - populate services object from a data store.. CPS? +// TODO - this catalog will be different for private cloud + +const services = catalogData.getServiceCatalog() + +// basic auth on this +router.use(auth) + +router.get('/', (req, res) => { + res.json({services: services}) +}) + +/** + * Router for `/catalog` + * @type express.Router + */ +module.exports = router diff --git a/apigee-cf-service-broker/lib/controllers/api/service-instances/index.js b/apigee-cf-service-broker/lib/controllers/api/service-instances/index.js new file mode 100644 index 0000000..82e7cf0 --- /dev/null +++ b/apigee-cf-service-broker/lib/controllers/api/service-instances/index.js @@ -0,0 +1,33 @@ +const express = require('express') +const path = require('path') +const validate = require('express-jsonschema').validate +const config = require(path.resolve('./config/environment')) +const auth = require(path.resolve('./lib/helpers/auth'))(config) +const bindingSchema = require(path.resolve('./schemas/service_binding')) +const { configValidate } = require(path.resolve('./lib/middleware/config.validator')) +const { authValidate } = require(path.resolve('./lib/middleware/auth.validator')) +const { actionValidate } = require(path.resolve('./lib/middleware/action.validator')) +const { protocolValidate } = require(path.resolve('./lib/middleware/protocol.validator')) + +const controller = require(path.resolve('./lib/controllers/api/service-instances/service-instance.controller')) + +const router = express.Router(); + +router.use(auth) + +router.put('/:instance_id', configValidate, controller.proviseServiceInstance) +router.patch('/:instance_id', controller.updateServiceInstance) +router.delete('/:instance_id', controller.removeServiceInstance) +router.put( + '/:instance_id/service_bindings/:binding_id', + validate({body: bindingSchema.bind}), + authValidate, + actionValidate, + protocolValidate, + configValidate, + controller.runResourceBinding +) + +router.delete('/:instance_id/service_bindings/:binding_id', controller.removeServiceBinding) + +module.exports = router; diff --git a/apigee-cf-service-broker/lib/controllers/api/service-instances/service-instance.controller.js b/apigee-cf-service-broker/lib/controllers/api/service-instances/service-instance.controller.js new file mode 100644 index 0000000..b527f04 --- /dev/null +++ b/apigee-cf-service-broker/lib/controllers/api/service-instances/service-instance.controller.js @@ -0,0 +1,182 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Implementation of [service broker API for CF](http://docs.cloudfoundry.org/services/api.html) + * + * @module + */ + +const path = require('path') +const config = require(path.resolve('./config/environment')) +const catalogData = require(path.resolve('./lib/providers/catalog_data')) +const serviceBinding = require(path.resolve('./lib/providers/service-binding')) +const logger = require(path.resolve('./lib/helpers/logger')) +const ServicePlans = require(path.resolve('./lib/providers/service-plans')) +const { derivePort, deriveAction, deriveProtocol } = require(path.resolve('./lib/helpers/extractors')) + +function deriveMicroParams(params) { + const microParams = { + target_app_port: derivePort(params), + target_app_route: params.target_app_route.toString().trim(), + edgemicro_key: params.edgemicro_key.toString().trim(), + edgemicro_secret: params.edgemicro_secret.toString().trim() + } + return microParams +} + +function deriveC2CParams (params, req) { + const c2cParams = { + target_app_port: derivePort(params), + target_app_route: params.target_app_route.toString().trim(), + bind_resource: req.body.bind_resource.route + + } + if (params.off_c2c_binding) { + c2cParams.off_c2c_binding = true + } + return c2cParams +} + +/* +* { +* with_docstore: Boolean, false by default, +* target_app_route: String, app name in cf +* target_app_port: Number, app port +* target_app_space_name: String, app space name in cf +* } +* */ +const derivePortalParams = (params = {}) => { + const portalParams = {} + + const keys = [ 'with_docstore', 'target_app_route' ] + + keys.forEach((key) => { + if (params[key]) { + portalParams[key] = params[key] + } + }) + if (!params.with_docstore) { + portalParams.with_docstore = false + } + portalParams.target_app_port = derivePort(params) + + return portalParams +} + +// provising a service instance +const proviseServiceInstance = (req, res) => { + const org = req.body.parameters.org.toString().trim() + const env = req.body.parameters.env.toString().trim() + const result = { + dashboard_url: config.getApigeeConfiguration(org, env, (err, data) => { + return data.get('APIGEE_DASHBOARD_URL') + }) + } + return res.status(201).json(result) +} +module.exports.proviseServiceInstance = proviseServiceInstance + +// update a service instance +const updateServiceInstance = (req, res) => { + res.status(422).json({ + description: 'Automatic plan changes are not supported today. Please contact Apigee Support.' + }) +} +module.exports.updateServiceInstance = updateServiceInstance + +// deprovision a service instance +const removeServiceInstance = (req, res) => { + res.json({}) +} +module.exports.removeServiceInstance = removeServiceInstance + +const runResourceBinding = async (req, res) => { + // use instance_id to retrieve org and environment for proxy + const bindReq = { + instance_id: req.params.instance_id, + binding_id: req.params.binding_id, + service_id: req.body.service_id, + org_id: req.body.context ? req.body.context.organization_guid : false, + space_guid: req.body.context ? req.body.context.space_guid : false, + plan_id: req.body.plan_id, + bind_resource: req.body.parameters.bind_resource || req.body.bind_resource, + // TODO refactor me - move to base plan object.deriveActions + action: deriveAction(req.body.parameters), + org: req.body.parameters.org, + env: req.body.parameters.env, + user: req.body.parameters.user, + pass: req.body.parameters.pass, + basic: req.body.parameters.basic, + bearer: req.body.parameters.bearer, + micro: req.body.parameters.micro, + // TODO refactor me - move to concrete planObject.derivePlanParameters + portal: (req.body.plan_id === catalogData.guid.portal) ? derivePortalParams(req.body.parameters) : {}, + // TODO refactor me - move to planObject.derivePlanParameters + micro_coresident: (req.body.plan_id === catalogData.guid.micro_coresident) ? deriveMicroParams(req.body.parameters) : {}, + micro_c2c: (req.body.plan_id === catalogData.guid.micro_c2c) ? deriveC2CParams(req.body.parameters, req) : {}, + host: req.body.parameters.host, + // TODO refactor me - move to base plan object.deriveProtocol + protocol: deriveProtocol(req.body.parameters).protocol, + configuration: config.getApigeeConfiguration( + req.body.parameters.org, + req.body.parameters.env, + function (err, data) { return data } + ) + } + + try { + // console.info('REQ.BODY', req.body) + // console.info('BIND.REQ', bindReq) + const plans = new ServicePlans() + // we can skip proxy creating process if no proxy in parameters.action + if (!bindReq.action.proxy) { + const error = plans.validate(req.body) + + if (error) { + return res.status(400).json(error) + } + const outputParam = plans.getOutputParam(req.body) + + return res.status(201).json(outputParam) + } + + bindReq.plan = plans.getProvider(bindReq) + + if (bindReq.plan && bindReq.plan.error) { + return res.status(400).json(bindReq.plan.error) + } + + const bindRes = await serviceBinding.createAsync(bindReq) + + const outputParam = bindReq.plan.getOutputParam(bindRes) + + logger.log.info('runResourceBinding.%o', outputParam) + + return res.status(201).json(outputParam) + } catch (error) { + logger.log.error('runResourceBinding.%o', error) + + return res.status(500).json(error) + } +} +module.exports.runResourceBinding = runResourceBinding + +// delete binding +const removeServiceBinding = (req, res) => { + res.json({}) +} +module.exports.removeServiceBinding = removeServiceBinding diff --git a/apigee-cf-service-broker/lib/errors/constants.js b/apigee-cf-service-broker/lib/errors/constants.js new file mode 100644 index 0000000..ea7f3b3 --- /dev/null +++ b/apigee-cf-service-broker/lib/errors/constants.js @@ -0,0 +1,14 @@ +module.exports = { + INTERNAL_ERROR: { + code: 500, + message: 'Server error', + }, + BAD_PARAMS: { + code: 400, + message: 'Bad params', + }, + NOT_FOUND: { + code: 404, + message: 'Resource not found', + }, +}; diff --git a/apigee-cf-service-broker/lib/errors/service-error.js b/apigee-cf-service-broker/lib/errors/service-error.js new file mode 100644 index 0000000..34ec824 --- /dev/null +++ b/apigee-cf-service-broker/lib/errors/service-error.js @@ -0,0 +1,34 @@ +/** + * @module errors + */ +const errors = require('./constants') + +const DEFAULT_ERROR = errors.INTERNAL_ERROR; + +class ServiceError extends Error { + constructor(error, causedByError, message) { + super(error); + /* eslint-disable */ + if (!error) { + error = DEFAULT_ERROR; + } + + if (causedByError && !(causedByError instanceof Error)) { + message = causedByError; + causedByError = undefined; + } + /* eslint-enable */ + + // super helper method to include stack trace in error object + Error.captureStackTrace(this, this.constructor); + + // set our function’s name as error name. + this.name = this.constructor.name; + + this.code = error.code; + this.causedBy = causedByError; + this.message = message || error.message; + } +} + +module.exports = ServiceError; diff --git a/apigee-cf-service-broker/lib/helpers/auth.js b/apigee-cf-service-broker/lib/helpers/auth.js new file mode 100644 index 0000000..f452306 --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/auth.js @@ -0,0 +1,155 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Authentication middleware + * + * @example + * var auth = require('../helpers/auth')(config) + * router.use(auth) + * + * @module + */ + +// CF sends basic auth with every request +var basicAuth = require('basic-auth') +var request = require('request') +var mgmt_api = require('../providers/mgmt_api') +var config = require('../../config/environment') + +// hardcoded admin/password - testing only +var staticauth = function (req, res, next) { + function unauthorized (res) { + res.set('WWW-Authenticate', 'Basic realm=Authorization Required') + return res.sendStatus(401) + } + + var user = basicAuth(req) + if (!user || !user.name || !user.pass) { + return unauthorized(res) + } + + if (user.name === config.auth.securityUserName && user.pass === config.auth.securityUserPassword) { + return next() + } else { + return unauthorized(res) + } +} + +// any user/pass as basic auth +// simply enforce basic auth header but not validate user/pass +// Not using below code anywhere +/* istanbul ignore next */ +var anybasicauth = function (req, res, next) { + function unauthorized (res) { + res.set('WWW-Authenticate', 'Basic realm=Authorization Required') + return res.sendStatus(401) + } + var user = basicAuth(req) + if (!user || !user.name || !user.pass) { + return unauthorized(res) + } else { + return next() + } +} + +// apigee user auth +// basic auth will be apigee user/pass to validate against target org +// Not using below code anywhere +/* istanbul ignore next */ +var apigeeuserauth = function (req, res, next) { + function unauthorized (res) { + res.set('WWW-Authenticate', 'Basic realm=Authorization Required') + return res.sendStatus(401) + } + var user = basicAuth(req) + if (!user || !user.name || !user.pass) { + return unauthorized(res) + } else { + // validate user and pass against target edge org + mgmt_api.authenticate({org: 'needorg', user: user.name, pass: user.pass}, function (err, data) { + if (err) { + return unauthorized(res) + } else { + return next() + } + }) + } +} + +// validate client_id/secret against edge (url dictates which org) +// Not using below code anywhere +/* istanbul ignore next */ +var clientcredentials = function (req, res, next) { + function unauthorized (res) { + res.set('WWW-Authenticate', 'Basic realm=Authorization Required') + return res.sendStatus(401) + } + + if (!req.header('Authorization')) { + return unauthorized(res) + } + var options = { + url: 'https://amer-demo6-test.apigee.net/cf-clientcredentials', + form: {grant_type: 'client_credentials'}, + headers: {Authorization: req.header('Authorization')} + } + request.post(options, function (err, httpResponse, body) { + if (!err && httpResponse.statusCode === 200) { + return next() + } else { + return unauthorized(res) + } + }) +} +// basic auth proxy call +var basicauth = function (req, res, next) { + function unauthorized (res) { + res.set('WWW-Authenticate', 'Basic realm=Authorization Required') + return res.sendStatus(401) + } + if (!req.header('Authorization')) { + return unauthorized(res) + } + var options = { + url: 'https://amer-demo6-test.apigee.net/cf-basicauth', + headers: {Authorization: req.header('Authorization')} + } + request.post(options, function (err, httpResponse, body) { + if (!err && httpResponse.statusCode === 200) { + return next() + } else { + return unauthorized(res) + } + }) +} + +module.exports = function (options) { + var auths = { + staticauth, + clientcredentials, + basicauth, + anybasicauth, + apigeeuserauth + } + + if (options === config) { + options = config.auth.type + } + + return auths[options] +} diff --git a/apigee-cf-service-broker/lib/helpers/enums.js b/apigee-cf-service-broker/lib/helpers/enums.js new file mode 100644 index 0000000..b7a61c9 --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/enums.js @@ -0,0 +1,30 @@ +module.exports = { + SERVICE_PLANS: { + org: 'org', + micro: 'micro', + microc2c: 'micro_c2c', + microCoresident: 'micro_coresident', + portal: 'portal' + }, + API_PRODUCT: { + defaults: { + quota: 1, + quotaInterval: 1, + quotaTimeUnit: 'second' + }, + approvalType: { + manual: 'manual', + auto: 'auto' + }, + attributes: { + access: { + private: 'private', + public: 'public' + } + } + }, + SPEC_KINDS: { + doc: 'Doc' + }, + VERBS: ['proxy', 'bind'] +} \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/helpers/extractors.js b/apigee-cf-service-broker/lib/helpers/extractors.js new file mode 100644 index 0000000..5246ccd --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/extractors.js @@ -0,0 +1,52 @@ +const path = require('path') + +const { VERBS } = require(path.resolve('./lib/helpers/enums')) + +const deriveProtocol = (params) => { + const proto = params.protocol ? params.protocol.toString().trim().toLowerCase() : 'http' + const ret = {} + + if (proto === 'http' || proto === 'https') { + ret.protocol = proto + } else if (params.protocol) { + ret.error = params.protocol.toString() + } + return ret +} + +const deriveAction = (params) => { + const action = params.action ? params.action.toString() : '' + + const ret = { + any: false, + errors: [] + } + + VERBS.forEach((verb) => { + ret[verb] = false + }) + + action.split(/[\s,]+/).forEach((value) => { + const lower = value.toLowerCase() + if (VERBS.indexOf(lower) >= 0) { + ret.any = true + ret[lower] = true + } else if (value) { + ret.errors.push(value) + } + }) + + return ret +} + +const derivePort = (params) => { + const port = params.target_app_port ? params.target_app_port : 80 + + return port +} + +module.exports = { + deriveProtocol, + deriveAction, + derivePort +} diff --git a/apigee-cf-service-broker/lib/helpers/http-methods.js b/apigee-cf-service-broker/lib/helpers/http-methods.js new file mode 100644 index 0000000..083d589 --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/http-methods.js @@ -0,0 +1,12 @@ +"use strict"; + +//https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/HttpMethod.html + +exports.DELETE = "DELETE"; +exports.GET = "GET"; +exports.HEAD = "HEAD"; +exports.OPTIONS = "OPTIONS"; +exports.PATCH = "PATCH"; +exports.POST = "POST"; +exports.PUT = "PUT"; +exports.TRACE = "TRACE"; diff --git a/apigee-cf-service-broker/lib/helpers/http-status.js b/apigee-cf-service-broker/lib/helpers/http-status.js new file mode 100644 index 0000000..e7464a4 --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/http-status.js @@ -0,0 +1,8 @@ +//http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html +//https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/HttpStatus.html + +module.exports = { + OK: 200, + CREATED: 201, + NO_CONTENT: 204 +} diff --git a/apigee-cf-service-broker/lib/helpers/http-utils.js b/apigee-cf-service-broker/lib/helpers/http-utils.js new file mode 100644 index 0000000..93aa394 --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/http-utils.js @@ -0,0 +1,132 @@ +'use strict' + +const Promise = require('bluebird') +const request = require('request') +const rest = require('restler') +const HttpStatus = require('./http-status') + +/** + * HttpUtils is a private class designed manage REST operations with + * Cloud Foundry components (Cloud controller, UAA, Metrics). + * It is used by all classes of project. + */ +class HttpUtils { + + /** + * Empty constructor + * @constructor + * @returns {void} + */ + constructor () { + + } + + /** + * Stablish a http communications using REST Verbs: GET/POST/PUT/DELETE + * + * @param {json} options [define options to make the request with the CF component] + * @param {number} httpStatusAssert [set expected http status code (200,201,204, etc...)] + * @param {boolan} jsonOutput [if the REST method retuns a String or a JSON representation] + * @return {string} [JSON/String] + * + * @example + * var url = "https://api.run.pivotal.io/v2/info"; + * var options = { + * method: 'GET', + * url: url + * }; + * HttpUtils.request(options, "200", true); + */ + request (options, httpStatusAssert, jsonOutput) { + let result = null + + //process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; + const requestWithDefaults = request.defaults({ + rejectUnauthorized: false + }) + + return new Promise(function (resolve, reject) { + let localResponse + try { + requestWithDefaults(options, function (error, response, body) { + localResponse = response + if (error) { + return reject(error) + } + + if (jsonOutput) { + try { + Object.prototype.toString.call(body) === '[object String]' + ? result = JSON.parse(body) + : result = body + } catch (errorJSON) { + console.info('errorJSON', errorJSON, body) + return reject(body) + } + } else { + result = body + } + + if (!error && response.statusCode === httpStatusAssert) { + return resolve(result) + } + + //Defensive code. + if (body.length === 0) { + return reject('EMPTY_BODY') + } + + if (!error && options.method === 'POST') { + if (response.statusCode === HttpStatus.CREATED && /networking\/v1\/external\/policies/.test(options.url)) { + return resolve(response) + } + } + + return reject(body) + }) + } catch (error) { + return reject(error) + } + }) + } + + /** + * Method designed to upload zip file to Cloud Controller. + * It is the unique usage of Restler dependency. + * + * @param {string} url [url] + * @param {json} options [options] + * @param {number} httpStatusAssert [set expected http status code (200,201,204, etc...)] + * @param {boolan} jsonOutput [if the REST method retuns a String or a JSON representation] + * @return {string} [JSON/String] + */ + upload (url, options, httpStatusAssert, jsonOutput) { + + return new Promise(function (resolve, reject) { + + try { + + rest.put(url, options).on('complete', function (result, response) { + if (result instanceof Error) { + reject(result) + } + + if (response.statusCode === httpStatusAssert) { + + if (jsonOutput) { + return resolve(JSON.parse(result)) + } + + return resolve(result) + } + }) + + } catch (error) { + return reject(error) + } + + }) + } +} + +module.exports = HttpUtils diff --git a/apigee-cf-service-broker/lib/helpers/logger.js b/apigee-cf-service-broker/lib/helpers/logger.js new file mode 100644 index 0000000..5c5af64 --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/logger.js @@ -0,0 +1,193 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Log messages/errors + * @module + */ + +var log = require('bunyan').createLogger({name: 'apigee'}) +var util = require('util') + +var codes = { + ERR_UAE: 'E0000', + ERR_CODE_COVERAGE_BADGE: 'E0001', + ERR_REQ_JSON_SCHEMA_FAIL: 'E0010', + ERR_REQ_INVALID_PROTOCOL: 'E0011', + ERR_PROXY_CREATION_FAILED: 'E0020', + ERR_PROXY_UPLOAD_FAILED: 'E0021', + ERR_PROXY_ZIP: 'E0022', + ERR_PROXY_READ_FAILED: 'E0023', + ERR_PROXY_VHOSTS_NON200_RES: 'E0024', + ERR_APIGEE_AUTH: 'E0030', + ERR_APIGEE_REQ_FAILED: 'E0031', + ERR_APIGEE_PROXY_UPLOAD: 'E0032', + ERR_APIGEE_GET_PROXY_REV_FAILED: 'E0033', + ERR_APIGEE_DEPLOY_PROXY: 'E0034', + ERR_APIGEE_UNDEPLOY_PROXY_FAILED: 'E0035', + ERR_APIGEE_PROXY_NOT_FOUND: 'E0036', + ERR_OPENAPI_PARSE_FAIL: 'E0060', + ERR_POLICIES_NOT_FOUND: 'E0061', + ERR_INVALID_OPENAPI_SPEC: 'E0062', + ERR_NOT_MICRO_PLAN: 'E0080', + ERR_MISSING_SUPPORTED_ACTION: 'E0081', + ERR_SPECIFIED_UNSUPPORTED_ACTION: 'E0082', + ERR_INVALID_SERVICE_PLAN: 'E0083', + ERR_ORG_PLAN_REQUIRES_HOST: 'E0084', + ERR_MICRO_PLAN_REQUIRES_MICRO: 'E0085', + ERR_MISSING_AUTH: 'E0086', + ERR_APIGEE_AUTH_BEARER_FAILED: 'E0087', + ERR_INVALID_TARGET_PROTOCOL: 'E0088', + ERR_MISSING_ORG: 'E0089', + ERR_MISSING_ENV: 'E0090', + ERR_MISSING_ENV_ORG: 'E0091', + ERR_ORG_ENV_NOT_FOUND: 'E0092', + ERR_NO_CONFIGURATION: 'E0093', + ERR_CONFIG_PARSE: 'E0094', + ERR_MISSING_MICRO_CORES_PARAMETER: 'E0095', + ERR_NOT_MICRO_CORES_PLAN: 'E0096', + ERR_BAD_BIND_COMMAND: 'E0097', + ERR_MISSING_MICRO_C2C_PARAMETER: 'E0098', + INFO_PROXY_CREATED_STOP: 'I0001', + ERR_CF_AUTH: 'E1010', + ERR_PROXY_BIND_FAILED: 'E1011', + ERR_CF_BINDING_ROUTE: 'E1012', + ERR_CF_EMPTY_SPACE: 'E1013', + ERR_CF_GET_SPACE: 'E1014', + ERR_CF_EMPTY_DOMAIN: 'E1015', + ERR_CF_INTERNAL_DOMAIN: 'E1016', + ERR_CF_ROUTES: 'E1017', + ERR_CF_BIND_APP_TO_ROUTE: 'E1018', + ERR_CF_CANT_GET_APP: 'E1019', + ERR_CF_EMPTY_APP: 'E1020', + ERR_CF_ADD_NETWORKING_POLICY: 'E1021', + ERR_BIND_RESOURCE_REQURED: 'E1022', + ERR_CF_EMPTY_BROKER_APP: 'E1023', + ERR_CF_EMPTY_APP_DOMAIN: 'E1024', + ERR_CF_BRS_FAILED: 'E1025', + ERR_PORTAL_PLAN_RUN_BINDING: 'E1026', + ERR_BIND_RESOURCE_APP_NAME_REQURED: 'E1027', + ERR_BIND_RESOURCE_TARGET_APP_NAME_REQURED: 'E1028', + ERR_MISSING_TARGET_APP_ROUTE: 'E1029' +} + +var messages = { + E0000: 'Unexpected Application Error', + E0001: 'Error generating code coverage badge', + E0010: 'Invalid JSON Sent to the server', + E0011: 'Invalid protocol, needs to be TLS enabled. Send req over https', + E0020: 'Proxy Creation Failed', + E0021: 'Proxy Upload Failed', + E0022: 'Error in zipping proxy bundle', + E0023: 'Error in reading proxy template', + E0024: 'Apigee returned non-200 response while fetching Virtual Hosts', + E0030: 'Error Authenticating to Apigee, Please check Apigee credentials', + E0031: 'Error making request to Apigee', + E0032: 'Error uploading proxy to Apigee', + E0033: 'Error Retrieving proxy revision details from Apigee', + E0034: 'Error deploying proxy to Apigee', + E0035: 'Error undeploying proxy from Apigee', + E0036: 'Error proxy not found in Apigee', + E0060: 'Error getting OpenAPI interface file', + E0061: 'Unable to find policies in Open API spec', + E0062: 'Invalid Open API Spec, Check policy attachment', + E0080: 'Not a "microgateway" plan, "micro" parameter is invalid', + E0081: 'Missing at least one supported "action"', + E0082: 'Unsupported "action"(s)', + E0083: 'Unrecognized Service Plan', + E0084: 'Org plan requires "host" parameter', + E0085: 'Microgateway plan requires "micro" parameter', + E0086: 'Missing authorization ("bearer" or "basic" or "user"&"pass")', + E0087: 'Error Authenticating to Apigee. Try refreshing Bearer token', + E0088: 'Invalid target web "protocol"', + E0089: 'Missing or empty "org" parameter', + E0090: 'Missing or empty "env" parameter', + E0091: 'Missing or empty "org" and "env" parameters', + E0092: 'Inorrect "org" and "env" mapping', + E0093: 'No configuration was found in your service broker environment. Please contact your Cloud Foundry administrator for more assistance', + E0094: 'Error parsing "APIGEE_CONFIGURATIONS"', + E0095: '"microgateway-coresident" plan requires the following parameter', + E0096: 'Not a microgateway-coresident plan', + E0097: 'Looks like a "bind-route-service" was run instead of "bind-service". Please use "bind-service" with the "microgateway-coresident" plan instead', + I0001: 'Proxy created; as requested, no binding attempted', + E1010: 'Unsuccessfull login to Cloud Foundry', + E1011: 'Proxy binding failed', + E1012: 'Create route in CF failed', + E1013: 'Empty space', + E1014: 'Error to get spaces list', + E1015: 'Domain apps.internal not found', + E1016: 'Cant get shared domains list', + E1017: 'Cant get routes for app', + E1018: 'Cant bind app to apps.internal', + E1019: 'Cant get app', + E1020: 'No such app', + E1021: 'Cant add networking policy', + E1022: 'Param "bind_resource" required', + E1023: 'Broker app name required in manifest', + E1024: 'Apps domain should be set in env', + E1025: 'Bind-route-service failed with errors', + E1026: 'Portal plan binding failed with errors', + E1027: 'For portal plan param target_app_name required', + E1028: 'Parameter "target_app_name" required', + E1029: 'Parameter "target_app_route" required' +} + +var getMessage = function (code) { + return util.format('[%s] - %s', code, messages[code]) +} + +function LoggerError (code, statusCode, detailMessage) { + Error.captureStackTrace(this, handle_error) + let line = this.stack.split('\n')[1] + this.topOfStack = line ? line.trim() : line + this.code = code + this.description = getMessage(code) // 'description' expected in CF response + if (detailMessage) { + this.description += ': ' + detailMessage + } + this.statusCode = statusCode || 500 +} + +util.inherits(LoggerError, Error) + +var handle_error = function (code, originalErr, statusCode, detailMessage) { + if (originalErr instanceof LoggerError) { + if (statusCode) { + originalErr.statusCode = statusCode + } + return originalErr + } + + const error = new LoggerError(code, statusCode, detailMessage) + + log.error({ + errAt: error.topOfStack, + errStatusCode: statusCode, // undefined if used default 500 + errDetails: originalErr, + errDescription: error.description + }, error.description) + return error +} + +module.exports.log = log + +for (let name in codes) { + const code = codes[name] + const fn = handle_error.bind(this, code) + fn.code = code + module.exports[name] = fn +} diff --git a/apigee-cf-service-broker/lib/helpers/random.js b/apigee-cf-service-broker/lib/helpers/random.js new file mode 100644 index 0000000..6a50627 --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/random.js @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min)) + min; +} + +function randomText () { + var text = '' + var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + for (var i = 0; i < 10; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)) + } + return text +} + +module.exports = { + randomText, + getRandomInt +} + diff --git a/apigee-cf-service-broker/lib/helpers/string.js b/apigee-cf-service-broker/lib/helpers/string.js new file mode 100644 index 0000000..4b0dfd2 --- /dev/null +++ b/apigee-cf-service-broker/lib/helpers/string.js @@ -0,0 +1,5 @@ +const quote = (value) => '"' + value + '"' + +module.exports = { + quote +} \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/middleware/action.validator.js b/apigee-cf-service-broker/lib/middleware/action.validator.js new file mode 100644 index 0000000..65f63c4 --- /dev/null +++ b/apigee-cf-service-broker/lib/middleware/action.validator.js @@ -0,0 +1,27 @@ +const path = require('path') +const logger = require(path.resolve('./lib/helpers/logger')) +const { quote } = require(path.resolve('./lib/helpers/string')) +const { deriveAction } = require(path.resolve('./lib/helpers/extractors')) +const { VERBS } = require(path.resolve('./lib/helpers/enums')) + +const actionValidate = (req, res, next) => { + const action = deriveAction(req.body.parameters) + + if (action.errors.length) { + const loggerError = logger.ERR_SPECIFIED_UNSUPPORTED_ACTION(null, null, action.errors.map(quote).join(', ')) + + return res.status(400).json(loggerError) + } + else if (action.any) { + return next() + } + else { + const loggerError = logger.ERR_MISSING_SUPPORTED_ACTION(null, null, VERBS.map(quote).join(' or ')) + + return res.status(400).json(loggerError) + } +} + +module.exports = { + actionValidate +} \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/middleware/auth.validator.js b/apigee-cf-service-broker/lib/middleware/auth.validator.js new file mode 100644 index 0000000..8c940de --- /dev/null +++ b/apigee-cf-service-broker/lib/middleware/auth.validator.js @@ -0,0 +1,22 @@ +const path = require('path') +const logger = require(path.resolve('./lib/helpers/logger')) + +const authValidate = (req, res, next) => { + const params = req.body.parameters + + if (params.user && params.pass) { + next() + } else if (params.basic) { + next() + } else if (params.bearer) { + next() + } else { + res.status(400) + const loggerError = logger.ERR_MISSING_AUTH() + res.json(loggerError) + } +} + +module.exports = { + authValidate +} \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/middleware/config.validator.js b/apigee-cf-service-broker/lib/middleware/config.validator.js new file mode 100644 index 0000000..66e0e31 --- /dev/null +++ b/apigee-cf-service-broker/lib/middleware/config.validator.js @@ -0,0 +1,43 @@ +const path = require('path') +const config = require(path.resolve('./config/environment')) +const logger = require(path.resolve('./lib/helpers/logger')) + +const configValidate = (req, res, next) => { + const org = (req.body.parameters && req.body.parameters.org) ? req.body.parameters.org.toString().trim() : '' + const env = (req.body.parameters && req.body.parameters.env) ? req.body.parameters.env.toString().trim() : '' + + let loggerError + if (org && env) { + config.getApigeeConfiguration(org, env, function(err, data){ + if (err){ + loggerError = err + } + }) + if (loggerError){ + res.status(400) + return res.json(loggerError) + } + else { + return next() + } + } + else if (org){ + res.status(400) + loggerError = logger.ERR_MISSING_ENV() + return res.json(loggerError) + } + else if (env){ + res.status(400) + loggerError = logger.ERR_MISSING_ORG() + return res.json(loggerError) + } + else{ + res.status(400) + loggerError = logger.ERR_MISSING_ENV_ORG() + return res.json(loggerError) + } +} + +module.exports = { + configValidate +} \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/middleware/protocol.validator.js b/apigee-cf-service-broker/lib/middleware/protocol.validator.js new file mode 100644 index 0000000..4669e79 --- /dev/null +++ b/apigee-cf-service-broker/lib/middleware/protocol.validator.js @@ -0,0 +1,19 @@ +const path = require('path') +const logger = require(path.resolve('./lib/helpers/logger')) +const { deriveProtocol } = require(path.resolve('./lib/helpers/extractors')) + +const protocolValidate = (req, res, next) => { + const proto = deriveProtocol(req.body.parameters) + + if ("error" in proto) { + const loggerError = logger.ERR_INVALID_TARGET_PROTOCOL(null, null, '"' + proto.error + '". A valid "protocol" is either "http" or "https".') + res.status(400).json(loggerError) + } + else { + next() + } +} + +module.exports = { + protocolValidate +} \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/providers/apigee-api/api-product.js b/apigee-cf-service-broker/lib/providers/apigee-api/api-product.js new file mode 100644 index 0000000..35700cc --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/apigee-api/api-product.js @@ -0,0 +1,64 @@ +const ApigeeControllerBase = require('./base') + +/** + * Manage API products on Apigee + */ +class ApiProduct extends ApigeeControllerBase { + + /** + * Get api product list from apigee + * {@link http://apidocs.cloudfoundry.org/214/events/list_all_events.html} + * + * @param {JSON} filter [Query String Parameters] + * @return {JSON} [return a JSON response] + */ + async getList (filter) { + const { org } = filter + + const url = `${this.getApiUrl(false)}/organizations/${org}/apiproducts?expand=true`; + + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + useQuerystring: true + }; + + const result = this.REST.request(options, this.HttpStatus.OK, true); + + return result + } + + /* + * @description + * + * {@link http://apidocs.cloudfoundry.org/214/events/list_all_events.html} + * + * @param + * + * @returns + * + * */ + add (param) { + const { org } = param + + const url = `${this.getApiUrl(false)}/organizations/${org}/apiproducts` + + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + json: param + }; + + const result = this.REST.request(options, this.HttpStatus.CREATED, true) + + return result + } +} + +module.exports = ApiProduct; diff --git a/apigee-cf-service-broker/lib/providers/apigee-api/base.js b/apigee-cf-service-broker/lib/providers/apigee-api/base.js new file mode 100644 index 0000000..8446aab --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/apigee-api/base.js @@ -0,0 +1,39 @@ +const path = require('path') +const config = require(path.resolve('./config/environment')) +const HttpUtils = require(path.resolve('./lib/helpers/http-utils')) +const HttpStatus = require(path.resolve('./lib/helpers/http-status')) + +/** + * + */ +class ApigeeControllerBase { + + /** + * @constructor + * @returns {void} + */ + constructor() { + this.API_URL = config.defaults.APIGEE_MGMT_API_URL + this.REST = new HttpUtils(); + this.HttpStatus = HttpStatus; + } + + getApiUrl (unoficial = false) { + // TODO investigate me - unoficial way for development only + if (unoficial) return 'https://apigee.com' + + return this.API_URL + } + + /** + * Set token + * @param {JSON} token [Oauth token from get_token apigee cli] + * { token_type: String, access_token: String } + * + */ + setToken (token) { + this.AUTH_TOKEN = token; + } +} + +module.exports = ApigeeControllerBase \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/providers/apigee-api/folders.js b/apigee-cf-service-broker/lib/providers/apigee-api/folders.js new file mode 100644 index 0000000..352f57a --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/apigee-api/folders.js @@ -0,0 +1,64 @@ +const ApigeeControllerBase = require("./base"); + +/** + * + * @description Manage API folders on Apigee + * + */ +class ApigeeForlders extends ApigeeControllerBase { + /* + * @description + * + * @param + * + * @returns + * + * */ + getName (param) { + return `${param.portal.target_app_name}-spec` + } + + /** + * + * @description Add new folder + * + */ + async add (param) { + const url = `${this.getApiUrl(true)}/organizations/${param.org}/specs/folder` + + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + json: param + } + + return this.REST.request(options, this.HttpStatus.OK, true) + } + + /** + * + * @description List of folders for organisation + * + */ + async getList (param) { + const url = `${this.getApiUrl(true)}/organizations/${param.org}/specs/folder/home` + + const options = { + method: 'GET', + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + useQuerystring: true + } + + const result = this.REST.request(options, this.HttpStatus.OK, true); + + return result + } +} + +module.exports = ApigeeForlders diff --git a/apigee-cf-service-broker/lib/providers/apigee-api/portal.js b/apigee-cf-service-broker/lib/providers/apigee-api/portal.js new file mode 100644 index 0000000..ba38a72 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/apigee-api/portal.js @@ -0,0 +1,127 @@ +"use strict"; + +const ApigeeControllerBase = require("./base"); + +/** + * Manage API products on Apigee + */ +class ApigeePortalPlan extends ApigeeControllerBase { + generateName (param) { + return `Portal for ${param.portal.target_app_route}` + } + /* + * @description + * + * @param + * + * @returns + * + * */ + generatePortalId (name, orgname) { + const clearedRoute = name.replace(/[\W\s]/gi,'').toLowerCase() + + return `${orgname}-${clearedRoute}` + } + + /* + * @description + * + * @param + * + * @returns + * + * */ + async addApiProductToPortalWithSpec (param) { + const { apiProduct, portal, spec } = param + + const url = `${this.getApiUrl(true)}/portals/api/sites/${portal.data.id}/apidocs` + + const portalParams = { + orgname: portal.data.orgname, + anonAllowed: null, + description: 'Default description', + specContent: spec.id, + specId: spec.name, + title: apiProduct.displayName, + edgeAPIProductName: apiProduct.name, + visibility: true + } + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + json: portalParams + }; + + return this.REST.request(options, this.HttpStatus.OK, true) + } + + /** + * Create portal + * + * @param {JSON} filter [Body Parameters] + * @return {JSON} [return a JSON response] + */ + async add (param) { + const url = `${this.getApiUrl(true)}/portals/api/sites` + const { orgname, name } = param + const portalId = this.generatePortalId(name, orgname) + + const portalParams = { + id: portalId, + orgName: orgname, + orgname, + name, + portalVersion: 2, + teams: [], + idpEnabled: false, + migrationDestSiteId: '', + migrationSrcSiteId: '', + zoneId: '', + analyticsScript: '', + analyticsTrackingId: '', + currentDomain: '', + customDomain: '', + description: '' + } + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + json: portalParams + }; + + return this.REST.request(options, this.HttpStatus.OK, true) + } + + /* + * @description + * + * @param + * + * @returns + * + * */ + async getList (param) { + const url = `${this.getApiUrl(true)}/portals/api/sites?orgname=${param.org}` + + const options = { + method: 'GET', + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + useQuerystring: true + } + + const result = this.REST.request(options, this.HttpStatus.OK, true); + + return result + } +} + +module.exports = ApigeePortalPlan diff --git a/apigee-cf-service-broker/lib/providers/apigee-api/specs.js b/apigee-cf-service-broker/lib/providers/apigee-api/specs.js new file mode 100644 index 0000000..07dad6f --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/apigee-api/specs.js @@ -0,0 +1,159 @@ +const path = require('path') +const url = require('url') +const YAML = require('json-to-pretty-yaml') +const ApigeeControllerBase = require('./base') +const { SPEC_KINDS } = require(path.resolve('./lib/helpers/enums')) +const logger = require(path.resolve('./lib/helpers/logger')) + +/** + * Manage API products on Apigee + */ +class ApigeeSpecs extends ApigeeControllerBase { + /* + * @description + * + * @param + * + * @returns + * + * */ + generateName (param) { + // ",", ".", "-", "_" + const result = `Spec for ${param.proxyname.replace(/[,.-]/gi, '')}` + + return result + } + + /* + * @description + * + * @param + * + * @returns + * + * */ + async getSpecFromAppAsYaml (url, proxyURL) { + const urlObject = new URL(proxyURL) + + logger.log.info(`ApigeeSpecs.getSpecFromAppAsYaml url: ${url}`) + + const options = { + method: 'GET', + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + } + }; + const result = await this.REST.request(options, this.HttpStatus.OK, true) + + result.host = urlObject.host + result.basePath = `/${urlObject.pathname.trim().split('/')[1]}` + + const yaml = YAML.stringify(result) + + return yaml + } + /* + * https://apigee.com/organizations//specs/doc + * + * kind: "Doc" + * name: "sample-doc" + * folder: FOLDER-ID + * */ + async add (param) { + const { org, folderId, name } = param + + const url = `${this.getApiUrl(true)}/organizations/${org}/specs/doc` + + const specParams = { + kind: SPEC_KINDS.doc, + folder: folderId, + name + } + + const options = { + method: 'POST', + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + json: specParams + }; + + const result = this.REST.request(options, this.HttpStatus.CREATED, true) + + return result + } + + /* + * @description + * + * @param + * + * @returns + * + * */ + async update (param) { + const { org, specId, body } = param + + const url = `${this.getApiUrl(true)}/organizations/${org}/specs/doc/${specId}/content` + + const options = { + method: 'PUT', + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}`, + 'Content-type': 'text/plain' + }, + body + } + + return this.REST.request(options, this.HttpStatus.OK, false) + } + /* + * { + "id":147770, + "folder":147770, + "kind":"Folder", + "name":"/orgs/yauhenikisialiou-eval root", + "created":"2019-02-26T17:07:45.805Z", + "modified":"2019-02-26T17:07:45.805Z", + "content":[ + { + "id":174245, + "folder":147770, + "kind":"Folder", + "name":"test", + "created":"2019-06-11T11:13:38.612Z", + "modified":"2019-06-11T11:13:38.612Z" + } + ] + } + * */ + /* + * @description + * + * @param + * + * @returns + * + * */ + async getList (param) { + const url = `${this.getApiUrl(true)}/organizations/${param.org}/specs/folder/home` + + const options = { + method: 'GET', + url: url, + headers: { + Authorization: `${this.AUTH_TOKEN.token_type} ${this.AUTH_TOKEN.access_token}` + }, + useQuerystring: true + } + + const result = this.REST.request(options, this.HttpStatus.OK, true); + + return result + } +} + +module.exports = ApigeeSpecs diff --git a/apigee-cf-service-broker/lib/providers/catalog_data.js b/apigee-cf-service-broker/lib/providers/catalog_data.js new file mode 100644 index 0000000..ab354d3 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/catalog_data.js @@ -0,0 +1,118 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Catalog data and GUIDs + * @module + */ + +// cf-cli sets to req.body.plan_id from service_plan.entity.unique_id +// all info about service-plans can get from command +// # CF_LOGIN= CF_LOGIN_PASSWORD= node commands/service-plans +// or +// # cf -v service-access +const ORG_GUID = 'D45A55FE-9576-427A-A0B7-B09E56BCB5C7' +const MICRO_CORESIDENT_GUID = '0E1FFDCC-88E1-4AE3-8ED1-889689212F98' +const MICRO_GUID = '0D41E763-E48C-4CF4-BE21-5772A219D624' +const MICRO_C2C_GUID = '2A7D9A35-1CB3-4E05-8085-CC0100331A96' +const PORTAL_UUID = '04B7CC7F-EE5D-4BF4-A5D7-1C637651F545' + +// service catalog - TODO: this should be configurable +const getServiceCatalog = () => { + return [ + { + id: '5E3F917B-9225-4BE4-802F-8F1491F714C0', + name: 'apigee-edge', + description: 'Apigee Edge API Platform', + bindable: true, + tags: ['api', 'api management', 'api platform'], + metadata: { + displayName: 'Apigee Edge API Platform', + imageUrl: 'http://apigee.com/about/sites/all/themes/apigee_themes/apigee_bootstrap/ApigeeLogo@2x.png', + longDescription: 'Apigee Edge enables digital business acceleration with a unified and complete platform, purpose-built for the digital economy. Edge simplifies managing the entire digital value chain with API Services, Developer Services, and Analytics Services.', + providerDisplayName: 'Apigee', + documentationUrl: 'http://apigee.com/docs/', + supportUrl: 'http://community.apigee.com/' + }, + requires: ['route_forwarding'], + plan_updateable: true, + plans: [ + { + id: ORG_GUID, + name: 'org', + description: 'Apigee Edge for Route Services', + metadata: { + displayName: 'Apigee Edge for Route Services' + }, + free: true + }, + { + id: MICRO_GUID, + name: 'microgateway', + description: 'Apigee Edge Microgateway for Route Services. This plan requires launching Microgateway as a separate Cloud Foundry application', + metadata: { + displayName: 'Apigee Edge Microgateway for Route Services as its own Cloud Foundry application' + }, + free: true + }, + { + id: MICRO_CORESIDENT_GUID, + name: 'microgateway-coresident', + description: 'Apigee Edge Microgateway coresident plan. Coresident means Microgateway will be on the same container as the target application', + metadata: { + displayName: 'Apigee Edge Microgateway coresident plan for running Microgateway on the same container as the target application' + }, + free: true + }, + { + id: MICRO_C2C_GUID, + name: 'microgateway-c2c', + description: 'Apigee Edge Microgateway C2C plan. C2C means Microgateway will use CloudFounry container to container networking to access backend APP. Backend app will not have a route', + metadata: { + displayName: 'Apigee Edge Microgateway C2C plan for running Microgateway and backend app in the same CloudFounry internal domain' + }, + free: true + }, + { + id: PORTAL_UUID, + name: 'portal', + description: 'Apigee Edge Portal plan. Creates portal for org plan', + metadata: { + displayName: 'Apigee Edge Portal plan creates proxy, portal, api product for app' + }, + free: true + } + ], + dashboard_client: { + id: 'apigee-dashboard-client-id', + secret: 'secret code phrase', + redirect_uri: 'https://enterprise.apigee.com' + } + } + ] +} + +module.exports = { + guid: Object.freeze({ + org: ORG_GUID, + micro: MICRO_GUID, + micro_coresident: MICRO_CORESIDENT_GUID, + micro_c2c: MICRO_C2C_GUID, + portal: PORTAL_UUID + }), + getServiceCatalog +} diff --git a/apigee-cf-service-broker/lib/providers/cf-binder.js b/apigee-cf-service-broker/lib/providers/cf-binder.js new file mode 100644 index 0000000..4960800 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-binder.js @@ -0,0 +1,400 @@ +const label = 'CFClient' +const path = require('path') +const config = require(path.resolve('./config/environment')) +const CloudFoundryRoutes = require(path.resolve('./lib/providers/cf-nodejs-client/model/cloudcontroller/Routes')) +const CloudFoundryUsersUAA = require(path.resolve('./lib/providers/cf-nodejs-client/model/uaa/UsersUAA')) +const Domains = require(path.resolve('./lib/providers/cf-nodejs-client/model/cloudcontroller/Domains')) +const ServicePlans = require(path.resolve('./lib/providers/cf-nodejs-client/model/cloudcontroller/ServicePlans')) +const Apps = require(path.resolve('./lib/providers/cf-nodejs-client/model/cloudcontroller/Apps')) +const Networking = require(path.resolve('./lib/providers/cf-nodejs-client/model/cloudcontroller/Networking')) +const logger = require(path.resolve('./lib/helpers/logger')) + +const LOGIN_ENDPOINT = 'https://login.system.pcf24.apigee.xyz' +const CF_API_URL = 'https://api.system.pcf24.apigee.xyz' +const APPS_INTERNAL_DOMAIN = 'apps.internal' + +const uaaService = new CloudFoundryUsersUAA(LOGIN_ENDPOINT) +const routesService = new CloudFoundryRoutes(CF_API_URL) +const domainsService = new Domains(CF_API_URL) +const appsService = new Apps(CF_API_URL) +const networkingService = new Networking(CF_API_URL) +const servicePlansService = new ServicePlans(CF_API_URL) +/* +* @description CF Binder for calls REST cf api +* +* */ +class CFBinder { + constructor () { + this.loginResponse = false + this.appRoute = false + } + /** + * Method to authenticate with Cloud Foundry UAA. All params from process.env.CF_LOGIN, CF_LOGIN_PASSWORD + * @return {Object} [UAA Response] + * { + * access_token: {String} + * token_type: {String} + * id_token: {String} + * refresh_token: {String} + * expires_in: {Number} + * scope: {String} + * jti: {String} + * } + */ + async login () { + const login = config.cf.user + const password = config.cf.password + + try { + this.loginResponse = await uaaService.login(login, password) + + return this.loginResponse + } catch (err) { + console.error(`${label}.login error`, err) + + const error = logger.ERR_CF_AUTH(err) + + return { error } + } + } + + getAppInternalFullHostname () { + const result = `${this.appRoute.entity.host}.${APPS_INTERNAL_DOMAIN}` + + return result + } + + async getServicePlans () { + servicePlansService.setToken(this.loginResponse) + try { + const result = await servicePlansService.getServicePlans() + + return result + } catch (err) { + logger.log.error(`${label}.getServicePlans error`, err) + + const error = logger.ERR_CF_CANT_GET_APP(err) + + return { error } + } + } + + async getApps (param) { + appsService.setToken(this.loginResponse) + + let spaceGuid = false + if (param.space) { + spaceGuid = param.space.metadata.guid + } + try { + const apps = await appsService.getApps({}, spaceGuid) + + if (!apps) { + const error = logger.ERR_CF_EMPTY_APP() + + return { error } + } + return apps + } catch (err) { + const error = logger.ERR_CF_CANT_GET_APP(err) + + return { error } + } + } + + async getSharedDomains () { + domainsService.setToken(this.loginResponse) + try { + const domains = await domainsService.getSharedDomains() + + return domains + } catch (err) { + console.error(`${label}.getSharedDomains error`, err) + + const error = logger.ERR_CF_INTERNAL_DOMAIN(err) + + return { error } + } + } + + async getRoutes () { + routesService.setToken(this.loginResponse) + try { + const routes = await routesService.getRoutes({}) + + return routes + } catch (err) { + console.error(`${label}.getRoutes error`, err) + + const error = logger.ERR_CF_ROUTES(err) + + return { error } + } + } + + async associateRoute (param) { + appsService.setToken(this.loginResponse) + try { + const { route, app } = param + + const mappedResult = await appsService.associateRoute(app.metadata.guid, route.metadata.guid) + + return mappedResult + } catch (err) { + console.error(`${label}.associateRoute error`, err) + + return { error: err } + } + } + + async addRoute (param) { + routesService.setToken(this.loginResponse) + try { + const result = await routesService.add(param) + + return result + } catch (err) { + console.error(`${label}.associateRoute error`. err) + + return { error: err } + } + } + /* + * Method to give access for created proxy to *.apps.internal resources + * + * @param {Object} + * + * @return {Object} + * + * @usage + * const API_URL = 'url-to-any-apigee-or-cf-app-api + * const service = new Networking(API_URL) + * const options = { + * destination: { + * guid: '' + * }, + * source: { + * guid: '' + * } + * } + * const run = async () => { + * await service.login() + * await service.addNetworkingPolicy(options) + * } + * + * run() + * */ + async addNetworkingPolicy (param) { + networkingService.setToken(this.loginResponse) + + const { destination, source, port } = param + + try { + /* + * + * { + * "policies": [ + * { + * "destination": { + * "id": "destination app guid", + * "ports": { + * "end": 8080, + * "start": 8080 + * }, + * "protocol": "tcp" + * }, + * "source": { + * "id": "source app guid" + * } + * } + * ] + * } + */ + + const result = await networkingService.add({ + policies: [ + { + destination: { + id: destination.guid, + ports: { + start: +(port), + end: +(port) + }, + protocol: 'tcp' + }, + source: { + id: source.guid + } + } + ] + }) + + return result + } catch (err) { + if (!err) return {} + + console.error(`${label}.addNetworkingPolicy error`, err) + + const error = logger.ERR_CF_ADD_NETWORKING_POLICY(err, 400, err.description) + + return { error } + } + } + /* + * @param { + * targetAppRoute: String + * spaceGuid: GUID, + * targetAppPort: Number + * domainForSearch: String + * } + * */ + async runBinding (param) { + const label = 'CFBinder.runBinding' + + logger.log.info(`${label}.start with domainForSearch:${param.domainForSearch}`) + + try { + const loginResponse = await this.login() + if (loginResponse.error) { + return loginResponse + } + + const domains = await this.getSharedDomains() + if (domains && domains.error) { + return domains + } + + const domain = domains.resources.find(s => s.entity.name === param.domainForSearch) + + if (!domain) { + const error = logger.ERR_CF_EMPTY_DOMAIN() + + return { error } + } + logger.log.info(`${label} base domain got`) + + const apps = await this.getApps({ space: { metadata: { guid: param.spaceGuid } } }) + + if (apps && apps.error) { + return apps + } + + logger.log.info(`${label} app got`) + + let appname = param.targetAppRoute.split('.')[0] + + const app = apps.resources.find(a => a.entity.name === appname) + + if (!app) { + const error = logger.ERR_CF_EMPTY_APP() + + return { error } + } + + const routeHostName = param.targetAppRoute.split('.')[0] + const routes = await this.getRoutes() + if (routes && routes.error) { + return routes + } + let route = routes.resources.find(r => r.entity.host === routeHostName && r.entity.domain_guid === domain.metadata.guid) + if (!route) { + route = await this.addRoute({ + domain_guid: domain.metadata.guid, + space_guid: param.spaceGuid, + host: routeHostName + }) + logger.log.info(`${label} route created`) + } + + logger.log.info(`${label} route got`) + + this.appRoute = route + + const mapRouteToApp = await this.associateRoute({ + route, + app + }) + + if (mapRouteToApp.error) { + return mapRouteToApp + } + + logger.log.info(`${label} route mapped to app`) + + const microcgatewayApp = apps.resources.find(a => a.entity.name === config.cf.microgatewayAppName) + + if (!microcgatewayApp) { + const error = logger.ERR_CF_EMPTY_APP() + + return { error } + } + + logger.log.info(`${label} microcgateway-app got`) + + const netPolicyResult = await this.addNetworkingPolicy({ + destination: { + guid: app.metadata.guid + }, + source: { + guid: microcgatewayApp.metadata.guid + }, + port: param.targetAppPort + }) + if (netPolicyResult.error) { + return netPolicyResult + } + + logger.log.info(`${label} netpolicy for microc2c-app created`) + + const brokerApp = apps.resources.find(a => a.entity.name === config.cf.brokerAppName) + if (!brokerApp) { + const error = logger.ERR_CF_EMPTY_BROKER_APP() + + return { error } + } + + logger.log.info(`${label} brokerapp got`) + + const netPolicyResultForBroker = await this.addNetworkingPolicy({ + destination: { + guid: app.metadata.guid + }, + source: { + guid: brokerApp.metadata.guid + }, + port: param.targetAppPort + }) + + if (netPolicyResultForBroker.error) { + return netPolicyResultForBroker + } + + const appsInternalFullHostName = this.getAppInternalFullHostname() + + logger.log.info(`${label} brokerapp netpolicy ready with appsInternalFullHostName: %s`, appsInternalFullHostName) + + // all data returned for debug purposes + return { + appsDomain: domain, + route, + mapRouteToApp, + appsInternalFullHostName, + netPolicyResultForBroker, + netPolicyResult + } + } catch (err) { + logger.log.error(`${label}.runBinding error`, err) + + const error = logger.ERR_CF_BINDING_ROUTE(err) + + return { error } + } + } +} + +module.exports = { + CFBinder, + LOGIN_ENDPOINT, + CF_API_URL, + APPS_INTERNAL_DOMAIN +} diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/index.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/index.js new file mode 100644 index 0000000..7c35646 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/index.js @@ -0,0 +1,158 @@ +'use strict'; + +var used = [], + exports = module.exports = {}; + +/** + * Library Version + * @type {String} + */ +exports.version = '0.13.0'; + +/** + * Support for Apps + * @type {[type]} + */ +var Apps = require('./model/cloudcontroller/Apps'); +exports.Apps = Apps; + +/** + * Support for Buildpacks + * @type {[type]} + */ +var BuildPacks = require('./model/cloudcontroller/BuildPacks'); +exports.BuildPacks = BuildPacks; + +/** + * Support for Cloud Controller + * @type {[type]} + */ +var CloudController = require('./model/cloudcontroller/CloudController'); +exports.CloudController = CloudController; + + +/** + * Support for Domains + * @type {[type]} + */ +var Domains = require('./model/cloudcontroller/Domains'); +exports.Domains = Domains; + +/** + * Support for Events + * @type {[type]} + */ +var Events = require('./model/cloudcontroller/Events'); +exports.Events = Events; + +/** + * Support for Jobs + * @type {[type]} + */ +var Jobs = require('./model/cloudcontroller/Jobs'); +exports.Jobs = Jobs; + +/** + * Support for Logs + * @type {[type]} + */ +var Logs = require('./model/metrics/Logs'); +exports.Logs = Logs; + +/** + * Support for Organizations + * @type {[type]} + */ +var Organizations = require('./model/cloudcontroller/Organizations'); +exports.Organizations = Organizations; + +/** + * Support for Organizations Quota + * @type {[type]} + */ +var OrganizationsQuota = require('./model/cloudcontroller/OrganizationsQuota'); +exports.OrganizationsQuota = OrganizationsQuota; + +/** + * Support for Routes + * @type {[type]} + */ +var Routes = require('./model/cloudcontroller/Routes'); +exports.Routes = Routes; + +/** + * Support for Services + * @type {[type]} + */ +var Services = require('./model/cloudcontroller/Services'); +exports.Services = Services; + +/** + * Support for ServiceBindings + * @type {[type]} + */ +var ServiceBindings = require('./model/cloudcontroller/ServiceBindings'); +exports.ServiceBindings = ServiceBindings; + +/** + * Support for ServiceInstances + * @type {[type]} + */ +var ServiceInstances = require('./model/cloudcontroller/ServiceInstances'); +exports.ServiceInstances = ServiceInstances; + +/** + * Support for ServicePlans + * @type {[type]} + */ +var ServicePlans = require('./model/cloudcontroller/ServicePlans'); +exports.ServicePlans = ServicePlans; + +/** + * Support for Spaces + * @type {[type]} + */ +var Spaces = require('./model/cloudcontroller/Spaces'); +exports.Spaces = Spaces; + +/** + * Support for Spaces Quota + * @type {[type]} + */ +var SpacesQuota = require('./model/cloudcontroller/SpacesQuota'); +exports.SpacesQuota = SpacesQuota; + +/** + * Support for Stacks + * @type {[type]} + */ +var Stacks = require('./model/cloudcontroller/Stacks'); +exports.Stacks = Stacks; + +/** + * Support for User Provided Services + * @type {[type]} + */ +var UserProvidedServices = require('./model/cloudcontroller/UserProvidedServices'); +exports.UserProvidedServices = UserProvidedServices; + +/** + * Support for Users + * @type {[type]} + */ +var Users = require('./model/cloudcontroller/Users'); +exports.Users = Users; + +/** + * Support for Users UAA + * @type {[type]} + */ +var UsersUAA = require('./model/uaa/UsersUAA'); +exports.UsersUAA = UsersUAA; + +/** + * Support for Network policies + * @type {[type]} + */ +var Networking = require('./model/cloudcontroller/Networking'); +exports.Networking = Networking; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Apps.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Apps.js new file mode 100644 index 0000000..70ff13a --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Apps.js @@ -0,0 +1,505 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); +const rest = require("restler");//TODO: Analyze a way to remove this dependency +const fs = require("fs"); + +/** + * This public class manages the operations related with Applications on Cloud Controller. + */ +class Apps extends CloudControllerBase { + + /** + * Returns all applications. + * {@link http://apidocs.cloudfoundry.org/213/apps/list_all_apps.html} + * + * @example + * PENDING + * + * @param {JSON} filter [Search options] + * @return {JSON} [return a JSON response] + */ + getApps (filter, spaceGuid) { + + let url = `${this.API_URL}/v2/apps`; + if (spaceGuid) { + url = `${this.API_URL}/v2/spaces/${spaceGuid}/apps`; + } + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Creates a new application on Cloud Controller. + * {@link http://apidocs.cloudfoundry.org/214/apps/creating_an_app.html} + * + * @example + * var appOptions = { + * "name": name, + * "space_guid": space_guid, + * "buildpack" : buildPack + * } + * + * @param {JSON} appOptions [options to create the application] + * @return {JSON} [information about the application] + */ + add (appOptions) { + + const url = `${this.API_URL}/v2/apps`; + const options = { + method: "POST", + url: url, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(appOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Update an App + * {@link http://apidocs.cloudfoundry.org/217/apps/updating_an_app.html} + * + * @param {String} appGuid [App guid] + * @param {JSON} appOptions [options to create the application] + * @return {JSON} [information about the application] + */ + update (appGuid, appOptions) { + + const url = `${this.API_URL}/v2/apps/${appGuid}`; + const options = { + method: "PUT", + url: url, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(appOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Stop an App + * {@link http://apidocs.cloudfoundry.org/217/apps/updating_an_app.html} + * + * @param {String} appGuid [App guid] + * @return {JSON} [information about the application] + */ + stop (appGuid) { + + const appOptions = { + state: "STOPPED" + }; + + return this.update(appGuid, appOptions); + } + + /** + * Start an App + * {@link http://apidocs.cloudfoundry.org/217/apps/updating_an_app.html} + * + * @param {String} appGuid [App guid] + * @return {JSON} [information about the application] + */ + start (appGuid) { + + const appOptions = { + state: "STARTED" + }; + + return this.update(appGuid, appOptions); + } + + /** + * Get summary about an application + * {@link http://apidocs.cloudfoundry.org/214/apps/get_app_summary.html} + * + * @param {String} appGuid [App guid] + * @return {JSON} [information about the application] + */ + getSummary (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/summary`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Delete an App + * {@link http://apidocs.cloudfoundry.org/214/apps/delete_a_particular_app.html} + * + * @param {String} appGuid [App guid] + * @return {JSON} [information about the application] + */ + remove (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}`; + const options = { + method: "DELETE", + url: url, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + + /** + * Get stats from an App + * {@link http://apidocs.cloudfoundry.org/214/apps/get_detailed_stats_for_a_started_app.html} + * + * @param {String} appGuid [App guid] + * @return {JSON} [information about the application] + */ + getStats (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/stats`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Associate an Application with a Route. + * {@link http://apidocs.cloudfoundry.org/214/apps/associate_route_with_the_app.html} + * + * @param {String} appGuid [App guid] + * @param {String} routeGuid [Route guid] + * @return {JSON} [description] + */ + associateRoute (appGuid, routeGuid) { + const url = `${this.API_URL}/v2/apps/${appGuid}/routes/${routeGuid}`; + const options = { + method: "PUT", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + const result = this.REST.request(options, this.HttpStatus.CREATED, true); + + return result + } + + /** + * Check resources + * {@link http://apidocs.cloudfoundry.org/214/resource_match/list_all_matching_resources.html} + * {@link https://github.com/cloudfoundry/cf-release/issues/761#issuecomment-128386896} + * + * You only need to call the resources_match endpoint to figure out the correct value + * to enter in the resources parameter in the app-bits-upload request + * if you want to take advantage of the optimization of not uploading already-uploaded bits. + * + * @param {String} token_type [description] + * @param {String} access_token [description] + * @param {JSON} zipResources [description] + * @return {JSON} [description] + + Apps.prototype.checkResources = function (token_type, access_token, zipResources) { + var url = this.API_URL + "/v2/resource_match"; + var options = { + method: 'PUT', + url: url, + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization': token_type + " " + access_token + }, + form : JSON.stringify(zipResources) + }; + + return this.REST.request(options, "200", false); + }; + */ + + /** + * Upload source code + * {@link http://apidocs.cloudfoundry.org/214/apps/uploads_the_bits_for_an_app.html} + * + * function File(path, filename, fileSize, encoding, contentType) + * 'application': rest.file(path, null, fileSizeInBytes, null, 'application/zip') + * + * @param {String} appGuid [App guid] + * @param {String} filePath [file path to upload] + * @param {Boolean} async [Sync/Async] + * @return {JSON/String} [{}/Job information] + */ + upload (appGuid, filePath, async) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/bits`; + const stats = fs.statSync(filePath); + const fileSizeInBytes = stats.size; + const zipResources = []; + let asyncFlag = false; + + if (typeof async === "boolean") { + if (async) { + asyncFlag = true; + } + } + const options = { + multipart: true, + accessToken: this.UAA_TOKEN.access_token, + query: { + guid: appGuid, + async: asyncFlag + }, + data: { + resources: JSON.stringify(zipResources), + application: rest.file(filePath, null, fileSizeInBytes, null, "application/zip") + } + }; + + return this.REST.upload(url, options, this.HttpStatus.CREATED, false); + } + + + /** + * Get Instances + * {@link http://apidocs.cloudfoundry.org/215/apps/get_the_instance_information_for_a_started_app.html} + * + * @param {String} appGuid [App guid] + * @return {JSON} [App Info] + */ + getInstances (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/instances`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get routes from an App + * {@link http://apidocs.cloudfoundry.org/214/apps/list_all_routes_for_the_app.html} + * + * @param {String} appGuid [App guid] + * @return {JSON} [App Info] + */ + getAppRoutes (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/routes`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get Service Binding from an App + * {@link http://apidocs.cloudfoundry.org/221/apps/list_all_service_bindings_for_the_app.html} + * + * @param {String} appGuid [App guid] + * @param {String} filter [description] + * @return {JSON} [Service Bindings] + */ + getServiceBindings (appGuid, filter) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/service_bindings`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Remove a Service Binding from an App. + * http://apidocs.cloudfoundry.org/226/apps/remove_service_binding_from_the_app.html + * + * This method only run in CC version >= 2.42 + * + * This method has another alternative: + * {@link http://apidocs.cloudfoundry.org/217/service_bindings/delete_a_particular_service_binding.html} + * + * @param {String} appGuid [App guid] + * @param {String} serviceGindingGuid [Service Binding guid] + * @return {JSON} [Response] + */ + removeServiceBindings (appGuid, serviceGindingGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/service_bindings/${serviceGindingGuid}`; + const options = { + method: "DELETE", + url: url, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + + + /** + * Get environment variables + * {@link http://apidocs.cloudfoundry.org/222/apps/get_the_env_for_an_app.html} + * + * @param {String} appGuid [App guid] + * @param {String} filter [description] + * @return {JSON} [Service Bindings] + */ + getEnvironmentVariables (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/env`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Restage an Application + * {@link http://apidocs.cloudfoundry.org/222/apps/restage_an_app.html} + * + * @param {String} appGuid [App guid] + * @return {JSON} [Service Bindings] + */ + restage (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/restage`; + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Downloads the bits for an App + * http://apidocs.cloudfoundry.org/226/apps/downloads_the_bits_for_an_app.html + * + * @param {String} appGuid [App guid] + * @return {Bytes[]} [description] + downloadBits (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/download`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, false); + } + */ + + /** + * Downloads the staged droplet for an App + * http://apidocs.cloudfoundry.org/226/apps/downloads_the_staged_droplet_for_an_app.html + * + * @param {String} appGuid [App guid] + * @return {Bytes[]} [description] + downloadDroplet (appGuid) { + + const url = `${this.API_URL}/v2/apps/${appGuid}/droplet/download`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, false); + } + */ + + /** + * Get the content of a path or a file deployed in CF. + * It is necessary that the app is staged and running + * {@link http://apidocs.cloudfoundry.org/226/files/retrieve_file.html} + * + * @param {String} appGuid [App guid] + * @param {String} path [A relative path of a file or folder] + * @return {String} [Content of a path or a file] + + getFile (appGuid, path) { + + let url = `${this.API_URL}/v2/apps/${appGuid}/instances/0/files/`; + + if (path) { + url += path; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, false); + } + */ + +} + +module.exports = Apps; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/BuildPacks.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/BuildPacks.js new file mode 100644 index 0000000..fb6da86 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/BuildPacks.js @@ -0,0 +1,40 @@ +"use strict"; + +/** + * This class handles Cloud Foundry buildpacks. + * {@link https://docs.cloudfoundry.org/buildpacks/} + */ +class BuildPacks { + + /** + * Empty constructor + * @constructor + * @returns {void} + */ + constructor() { + //Buildpacks tested + this.buildpackMap = {}; + this.buildpackMap.static = "https://github.com/cloudfoundry/staticfile-buildpack"; + this.buildpackMap.nodejs = "https://github.com/cloudfoundry/nodejs-buildpack"; + this.buildpackMap.java = "https://github.com/cloudfoundry/java-buildpack"; + this.buildpackMap.php = "https://github.com/cloudfoundry/php-buildpack"; + this.buildpackMap.python = "https://github.com/cloudfoundry/python-buildpack"; + } + + /** + * Returns the address to use a buildpack + * @param {String} key [Buildpack key] + * @return {String} [Address about selected buildpack] + * @throws {Error} This exception is throwed if the key is unknown + */ + get (key) { + + if (this.buildpackMap[key]) { + return this.buildpackMap[key]; + } + throw new Error("This Buildpack is not supported"); + } + +} + +module.exports = BuildPacks; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/CloudController.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/CloudController.js new file mode 100644 index 0000000..af76491 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/CloudController.js @@ -0,0 +1,101 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * This class manages the entry point with the Cloud Foundry Controller. + * {@link https://github.com/cloudfoundry/cloud_controller_ng} + */ +class CloudController extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @returns {void} + * @constructor + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get information from Cloud Controller + * {@link http://apidocs.cloudfoundry.org/214/info/get_info.html} + * + * @return {JSON} [Return all enabled services to use] + */ + getInfo () { + + const url = `${this.API_URL}/v2/info`; + const options = { + method: "GET", + url: url + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get information about all featured flags. + * {@link http://apidocs.cloudfoundry.org/214/feature_flags/get_all_feature_flags.html} + * + * @return {JSON} [Response] + */ + getFeaturedFlags() { + + const url = `${this.API_URL}/v2/config/feature_flags`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get information about a determinated featured flag. + * {@link http://apidocs.cloudfoundry.org/214/feature_flags/get_the_diego_docker_feature_flag.html} + * + * @param {String} flag [flag] + * @return {JSON} [Response] + */ + getFeaturedFlag(flag) { + + const url = `${this.API_URL}/v2/config/feature_flags/${flag}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Enable a feature flag + * {@link http://apidocs.cloudfoundry.org/214/feature_flags/set_a_feature_flag.html } + * + * @param {String} flag [flag to make the request] + * @return {JSON} [Response] + */ + setFeaturedFlag(flag) { + + const url = `${this.API_URL}/v2/config/feature_flags/${flag}`; + const options = { + method: "PUT", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = CloudController; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/CloudControllerBase.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/CloudControllerBase.js new file mode 100644 index 0000000..0006c39 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/CloudControllerBase.js @@ -0,0 +1,44 @@ +"use strict"; + +const HttpUtils = require("../../../../helpers/http-utils"); +const HttpStatus = require("../../../../helpers/http-status"); + +/** + * + */ +class CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + + this.API_URL = endPoint; + this.REST = new HttpUtils(); + this.HttpStatus = HttpStatus; + } + + /** + * Set endpoint + * @param {String} endPoint [CC endpoint] + * @returns {void} + */ + setEndPoint (endPoint) { + + this.API_URL = endPoint; + } + + /** + * Set token + * @param {JSON} token [Oauth token from UAA] + * @returns {void} + */ + setToken (token) { + + this.UAA_TOKEN = token; + } +} + +module.exports = CloudControllerBase; \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Domains.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Domains.js new file mode 100644 index 0000000..c7ec730 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Domains.js @@ -0,0 +1,61 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage Domains on Cloud Foundry + */ +class Domains extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Domains + * {@link http://apidocs.cloudfoundry.org/214/domains_(deprecated)/list_all_domains_(deprecated).html} + * + * @return {JSON} [return a JSON response] + */ + getDomains () { + + const url = `${this.API_URL}/v2/domains`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get shared domains + * {@link http://apidocs.cloudfoundry.org/214/shared_domains/list_all_shared_domains.html} + * + * @return {JSON} [return a JSON response] + */ + getSharedDomains () { + + const url = `${this.API_URL}/v2/shared_domains`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = Domains; \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Events.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Events.js new file mode 100644 index 0000000..2ae2f1f --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Events.js @@ -0,0 +1,49 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage Events on Cloud Foundry + */ +class Events extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get events from CC + * {@link http://apidocs.cloudfoundry.org/214/events/list_all_events.html} + * + * @param {JSON} filter [Query String Parameters] + * @return {JSON} [return a JSON response] + */ + getEvents (filter) { + + const url = `${this.API_URL}/v2/events`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs, + useQuerystring: true + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = Events; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Jobs.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Jobs.js new file mode 100644 index 0000000..2f95f18 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Jobs.js @@ -0,0 +1,42 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage Jobs on Cloud Foundry + */ +class Jobs extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get a determinated Job + * {@link http://apidocs.cloudfoundry.org/214/jobs/retrieve_job_that_is_queued.html} + * + * @param {String} guid [job guid] + * @return {JSON} [return a JSON response] + */ + getJob (guid) { + + const url = `${this.API_URL}/v2/jobs/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = Jobs; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Networking.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Networking.js new file mode 100644 index 0000000..45d6446 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Networking.js @@ -0,0 +1,62 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); +const rest = require("restler");//TODO: Analyze a way to remove this dependency +const fs = require("fs"); + +/** + * This public class manages the operations related with Networking on Cloud Controller. + */ +class Networking extends CloudControllerBase { + + /** + * Creates a new network policy on Cloud Controller. + * {@link http://apidocs.cloudfoundry.org/214/apps/creating_an_app.html} + * + * @example REST - from cf -v add-network-policy edgemicro-app-harper --destination-app sample --protocol tcp --port 8080 + * REQUEST: [2019-05-30T15:59:47+03:00] + * POST /networking/v1/external/policies HTTP/1.1 + * Host: api.system.pcf24.apigee.xyz + * Accept: application/json + * Authorization: [PRIVATE DATA HIDDEN] + * Content-Type: application/json + * User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) + * { + * "policies": [ + * { + * "destination": { + * "id": "destination app guid", + * "ports": { + * "end": 8080, + * "start": 8080 + * }, + * "protocol": "tcp" + * }, + * "source": { + * "id": "source app guid" + * } + * } + * ] + * } + * + */ + add (netOptions) { + const url = `${this.API_URL}/networking/v1/external/policies` + const options = { + method: 'POST', + url: url, + headers: { + 'Content-Type': 'application/json', + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + // form is here because cf-networking api cant read application/json + form: JSON.stringify(netOptions) + } + // this.HttpStatus.OK - deprecated status from cf api v1 + const result = this.REST.request(options, this.HttpStatus.OK, true) + + return result + } +} + +module.exports = Networking diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Organizations.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Organizations.js new file mode 100644 index 0000000..099af15 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Organizations.js @@ -0,0 +1,184 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage Organizations in Cloud Foundry + */ +class Organizations extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Organizations + * {@link http://apidocs.cloudfoundry.org/213/organizations/list_all_organizations.html} + * + * @param {String} token_type [Authentication type] + * @param {String} access_token [Authentication token] + * @return {JSON} [return a JSON response] + */ + getOrganizations () { + + const url = `${this.API_URL}/v2/organizations`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get memory usage from an Organization + * {@link http://apidocs.cloudfoundry.org/222/organizations/retrieving_organization_memory_usage.html} + * + * @param {String} guid [org guid] + * @return {JSON} [return a JSON response] + */ + getMemoryUsage (guid) { + + const url = `${this.API_URL}/v2/organizations/${guid}/memory_usage`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get summary from an Organization + * {@link http://apidocs.cloudfoundry.org/222/organizations/get_organization_summary.html} + * + * @param {String} guid [org guid] + * @return {JSON} [return a JSON response] + */ + getSummary (guid) { + + const url = `${this.API_URL}/v2/organizations/${guid}/summary`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get private domains from an Organizations + * {@link http://apidocs.cloudfoundry.org/214/organizations/list_all_private_domains_for_the_organization.html} + * + * @param {String} guid [org guid] + * @return {JSON} [return a JSON response] + */ + getPrivateDomains (guid) { + + const url = `${this.API_URL}/v2/organizations/${guid}/private_domains`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Add a new organization + * {@link http://apidocs.cloudfoundry.org/222/organizations/creating_an_organization.html} + * + * @param {JSon} orgOptions [org options] + * @return {JSON} [return a JSON response] + */ + add (orgOptions) { + + const url = `${this.API_URL}/v2/organizations`; + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(orgOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Remove an Organization + * {@link http://apidocs.cloudfoundry.org/222/organizations/delete_a_particular_organization.html} + * + * @param {String} guid [org guid] + * @param {JSon} orgOptions [org options] + * @return {String} [output] + */ + remove (guid, orgOptions) { + + const url = `${this.API_URL}/v2/organizations/${guid}`; + let qs = {}; + + if (orgOptions) { + qs = orgOptions; + } + const options = { + method: "DELETE", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + + /** + * Get users from an Organization + * {@link http://apidocs.cloudfoundry.org/222/organizations/list_all_users_for_the_organization.html} + * + * @param {String} guid [org guid] + * @param {Json} filter [filter to search] + * @return {Json} [output] + */ + getUsers (guid, filter) { + + const url = `${this.API_URL}/v2/organizations/${guid}/users`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = Organizations; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/OrganizationsQuota.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/OrganizationsQuota.js new file mode 100644 index 0000000..4b921ad --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/OrganizationsQuota.js @@ -0,0 +1,112 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage Quotas for an Organization + */ +class OrganizationsQuota extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Quotas for Organizations + * {@link http://apidocs.cloudfoundry.org/213/organization_quota_definitions/list_all_organization_quota_definitions.html} + * + * @return {JSON} [return a JSON response] + */ + getQuotaDefinitions () { + + const url = `${this.API_URL}/v2/quota_definitions`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a quota from an Organization + * {@link http://apidocs.cloudfoundry.org/213/organization_quota_definitions/retrieve_a_particular_organization_quota_definition.html} + * + * @param {String} guid [org guid] + * @return {JSON} [return a JSON response] + */ + getQuotaDefinition (guid) { + + const url = `${this.API_URL}/v2/quota_definitions/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Add a Quota + * {@link http://apidocs.cloudfoundry.org/222/organization_quota_definitions/creating_a_organization_quota_definition.html} + * + * @param {JSON} quotaOptions [org options] + * @return {JSON} [return a JSON response] + */ + add (quotaOptions) { + + const url = `${this.API_URL}/v2/quota_definitions`; + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(quotaOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Remove a Quota for an Organization + * {@link http://apidocs.cloudfoundry.org/222/organization_quota_definitions/delete_a_particular_organization_quota_definition.html} + * + * @param {String} guid [quota guid] + * @param {Boolean} async [description] + * @return {JSON} [return a JSON response] + */ + remove (guid, async) { + + const url = `${this.API_URL}/v2/quota_definitions/${guid}`; + let qs = {}; + + if (async) { + qs = async; + } + const options = { + method: "DELETE", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + +} + +module.exports = OrganizationsQuota; \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Routes.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Routes.js new file mode 100644 index 0000000..d98b741 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Routes.js @@ -0,0 +1,135 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manages Routes on Cloud Foundry + */ +class Routes extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Routes + * {@link http://apidocs.cloudfoundry.org/214/routes/list_all_routes.html} + * + * @example + * Paging: /v2/routes?order-direction=asc&page=2&results-per-page=50 + * + * qs: { + * 'page': page, + * 'results-per-page': 50 + * } + * + * @param {JSON} filter [Search options] + * @return {JSON} [return a JSON response] + */ + getRoutes (filter) { + + const url = `${this.API_URL}/v2/routes`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Route + * {@link http://apidocs.cloudfoundry.org/214/routes/retrieve_a_particular_route.html} + * + * @param {String} guid [route guid] + * @return {JSON} [return a JSON response] + */ + getRoute (guid) { + + const url = `${this.API_URL}/v2/routes/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Add a Route + * {@link http://apidocs.cloudfoundry.org/213/routes/creating_a_route.html} + * + * @param {JSON} routeOptions [route options] + * @return {JSON} [return a JSON response] + */ + add (routeOptions) { + + const url = `${this.API_URL}/v2/routes`; + const options = { + method: "POST", + url: url, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(routeOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Remove a Route + * {@link http://apidocs.cloudfoundry.org/214/routes/delete_a_particular_route.html} + * + * @param {String} guid [route guid] + * @return {String} [output] + */ + remove (guid) { + + const url = `${this.API_URL}/v2/routes/${guid}`; + const options = { + method: "DELETE", + url: url, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + + getRouteMappings (guid) { + // /v2/routes/fe114ea3-4bc3-45b1-9379-731da9e79d8e/route_mappings + const url = `${this.API_URL}/v2/routes/${guid}/route_mappings`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } +} + +module.exports = Routes; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServiceBindings.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServiceBindings.js new file mode 100644 index 0000000..484ceec --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServiceBindings.js @@ -0,0 +1,116 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manages Service Binding on Cloud Foundry + */ +class ServiceBindings extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Service Bindings + * {@link http://apidocs.cloudfoundry.org/217/service_bindings/list_all_service_bindings.html} + * + * @param {String} filter [Search option] + * @return {JSON} [return a JSON response] + */ + getServiceBindings (filter) { + + const url = `${this.API_URL}/v2/service_bindings`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Service Binding + * {@link http://apidocs.cloudfoundry.org/217/service_bindings/retrieve_a_particular_service_binding.html} + * + * @param {String} guid [serviceBinding guid] + * @return {JSON} [return a JSON response] + */ + getServiceBinding (guid) { + + const url = `${this.API_URL}/v2/service_bindings/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Associate Service with an App + * {@link http://apidocs.cloudfoundry.org/217/service_bindings/create_a_service_binding.html} + * + * @param {String} serviceGuid [service_guid] + * @param {String} appGuid [app_guid] + * @return {JSON} [return a JSON response] + */ + associateServiceWithApp (serviceGuid, appGuid) { + + const url = `${this.API_URL}/v2/service_bindings`; + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify({ + service_instance_guid: serviceGuid, + app_guid: appGuid + }) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Remove a Service Binding + * {@link http://apidocs.cloudfoundry.org/217/service_bindings/delete_a_particular_service_binding.html} + * + * @param {String} guid [service_guid] + * @return {JSON} [return a JSON response] + */ + remove (guid) { + + const url = `${this.API_URL}/v2/service_bindings/${guid}`; + const options = { + method: "DELETE", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + +} + +module.exports = ServiceBindings; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServiceInstances.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServiceInstances.js new file mode 100644 index 0000000..7a92e4b --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServiceInstances.js @@ -0,0 +1,176 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manages Service Instances on Cloud Foundry + */ +class ServiceInstances extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Service Instances + * {@link https://apidocs.cloudfoundry.org/226/service_instances/list_all_service_instances.html} + * + * @param {String} filter [query string] + * @return {JSON} [return a JSON response] + */ + getInstances (filter) { + + const url = `${this.API_URL}/v2/service_instances`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Service Instance + * {@link https://apidocs.cloudfoundry.org/226/service_instances/retrieve_a_particular_service_instance.html} + * + * @param {String} guid [servicePlan guid] + * @return {JSON} [return a JSON response] + */ + getInstance (guid) { + + const url = `${this.API_URL}/v2/service_instances/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Service Instance Permissions + * {@link https://apidocs.cloudfoundry.org/226/service_instances/retrieving_permissions_on_a_service_instance.html} + * + * @param {String} guid [servicePlan guid] + * @return {JSON} [return a JSON response] + */ + getInstancePermissions (guid) { + + const url = `${this.API_URL}/v2/service_instances/${guid}/permissions`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Service Instance Bindings + * {@link https://apidocs.cloudfoundry.org/226/service_instances/list_all_service_bindings_for_the_service_instance.html} + * + * @param {String} guid [servicePlan guid] + * @return {JSON} [return a JSON response] + */ + getInstanceBindings (guid) { + + const url = `${this.API_URL}/v2/service_instances/${guid}/service_bindings`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Service Instance Routes + * {@link https://apidocs.cloudfoundry.org/226/service_instances/list_all_routes_for_the_service_instance.html} + * + * @param {String} guid [servicePlan guid] + * @return {JSON} [return a JSON response] + */ + getInstanceRoutes (guid) { + + const url = `${this.API_URL}/v2/service_instances/${guid}/routes`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Create a Service Instance + * {@link https://apidocs.cloudfoundry.org/226/service_instances/delete_a_service_instance.html} + * + * @param {JSON} appOptions [options to create the application] + * @return {JSON} [return a JSON response] + */ + create (appOptions) { + + const url = `${this.API_URL}/v2/service_instances`; + const options = { + method: "POST", + url: url, + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(appOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Remove a Service Instance + * {@link https://apidocs.cloudfoundry.org/226/service_instances/delete_a_service_instance.html} + * + * @param {String} guid [Service Instance guid] + * @return {JSON} [return a JSON response] + */ + remove (guid) { + + const url = `${this.API_URL}/v2/service_instances/${guid}`; + const options = { + method: "DELETE", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + +} + +module.exports = ServiceInstances; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServicePlans.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServicePlans.js new file mode 100644 index 0000000..603d8b1 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/ServicePlans.js @@ -0,0 +1,111 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manages Service Plan on Cloud Foundry + */ +class ServicePlans extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Service Plans + * {@link https://apidocs.cloudfoundry.org/226/service_plans/list_all_service_plans.html} + * + * @param {String} filter [Search options] + * @return {JSON} [return a JSON response] + */ + getServicePlans (filter) { + + const url = `${this.API_URL}/v2/service_plans`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Service Plan + * {@link https://apidocs.cloudfoundry.org/226/service_plans/retrieve_a_particular_service_plan.html} + * + * @param {String} guid [servicePlan guid] + * @return {JSON} [return a JSON response] + */ + getServicePlan (guid) { + + const url = `${this.API_URL}/v2/service_plans/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * List all Service Instances for a Service Plan + * {@link https://apidocs.cloudfoundry.org/226/service_plans/list_all_service_instances_for_the_service_plan.html} + * + * @param {String} guid [servicePlan guid] + * @return {JSON} [return a JSON response] + */ + getServicePlanInstances (guid) { + + const url = `${this.API_URL}/v2/service_plans/${guid}/service_instances`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Remove a Service Plan + * {@link https://apidocs.cloudfoundry.org/226/service_plans/delete_a_particular_service_plans.html} + * + * @param {String} guid [servicePlan_guid] + * @return {JSON} [return a JSON response] + */ + remove (guid) { + + const url = `${this.API_URL}/v2/service_plans/${guid}`; + const options = { + method: "DELETE", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + +} + +module.exports = ServicePlans; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Services.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Services.js new file mode 100644 index 0000000..04abdb5 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Services.js @@ -0,0 +1,111 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manages Services on Cloud Foundry + */ +class Services extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Services + * {@link https://apidocs.cloudfoundry.org/226/services/list_all_services.html} + * + * @param {String} filter [query string] + * @return {JSON} [return a JSON response] + */ + getServices (filter) { + + const url = `${this.API_URL}/v2/services`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Service + * {@link https://apidocs.cloudfoundry.org/226/services/retrieve_a_particular_service.html} + * + * @param {String} guid [servicePlan guid] + * @return {JSON} [return a JSON response] + */ + getService (guid) { + + const url = `${this.API_URL}/v2/services/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * List all Service Plans for a Service + * {@link https://apidocs.cloudfoundry.org/226/services/list_all_service_plans_for_the_service.html} + * + * @param {String} guid [service guid] + * @return {JSON} [return a JSON response] + */ + getServicePlans (guid) { + + const url = `${this.API_URL}/v2/services/${guid}/service_plans`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Remove a Service + * {@link https://apidocs.cloudfoundry.org/226/services/delete_a_particular_service.html} + * + * @param {String} guid [service_guid] + * @return {String} [return REST response] + */ + remove (guid) { + + const url = `${this.API_URL}/v2/services/${guid}`; + const options = { + method: "DELETE", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + +} + +module.exports = Services; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Spaces.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Spaces.js new file mode 100644 index 0000000..769e104 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Spaces.js @@ -0,0 +1,189 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage Spaces on Cloud Foundry + */ +class Spaces extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Spaces + * {@link http://apidocs.cloudfoundry.org/214/spaces/list_all_spaces.html} + * + * @return {JSON} [return a JSON response] + */ + async getSpaces () { + const url = `${this.API_URL}/v2/spaces`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + const result = await this.REST.request(options, this.HttpStatus.OK, true); + + return result + } + + /** + * Get a Space + * {@link http://apidocs.cloudfoundry.org/214/spaces/retrieve_a_particular_space.html} + * + * @param {String} guid [Space guid] + * @return {JSON} [return a JSON response] + */ + getSpace (guid) { + + const url = `${this.API_URL}/v2/spaces/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get Apps in a Space + * {@link http://apidocs.cloudfoundry.org/214/spaces/list_all_apps_for_the_space.html} + * + * @example + * qs: { + 'q': 'name:' + params.appName, + 'inline-relations-depth': 1 + } + * + * @param {String} guid [Space guid] + * @param {JSON} filter [Filter] + * @return {JSON} [return a JSON response] + */ + getSpaceApps (guid, filter) { + + const url = `${this.API_URL}/v2/spaces/${guid}/apps`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get Space summary + * {@link http://apidocs.cloudfoundry.org/222/spaces/get_space_summary.html} + * + * @param {String} guid [Space guid] + * @return {JSON} [return a JSON response] + */ + getSummary (guid) { + + const url = `${this.API_URL}/v2/spaces/${guid}/summary`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get User Roles + * {@link http://apidocs.cloudfoundry.org/222/spaces/retrieving_the_roles_of_all_users_in_the_space.html} + * + * @param {String} guid [Space guid] + * @return {JSON} [return a JSON response] + */ + getUserRoles (guid) { + + const url = `${this.API_URL}/v2/spaces/${guid}/user_roles`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Create a Space + * {@link http://apidocs.cloudfoundry.org/222/spaces/creating_a_space.html} + * + * @param {JSON} spaceOptions [Space options] + * @return {JSON} [return a JSON response] + */ + add (spaceOptions) { + + const url = `${this.API_URL}/v2/spaces`; + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(spaceOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Delete a Space + * {@link http://apidocs.cloudfoundry.org/222/spaces/delete_a_particular_space.html} + * + * @param {String} guid [Space uid] + * @param {JSON} spaceOptions [Space options] + * @return {JSON} [return a JSON response] + */ + remove (guid, spaceOptions) { + + const url = `${this.API_URL}/v2/spaces/${guid}`; + let qs = {}; + + if (spaceOptions) { + qs = spaceOptions; + } + const options = { + method: "DELETE", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + +} + +module.exports = Spaces; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/SpacesQuota.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/SpacesQuota.js new file mode 100644 index 0000000..a06a0dc --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/SpacesQuota.js @@ -0,0 +1,41 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage SpacesQuota + */ +class SpacesQuota extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Quota Definitions + * {@link http://apidocs.cloudfoundry.org/214/space_quota_definitions/list_all_space_quota_definitions.html} + * + * @return {JSON} [return a JSON response] + */ + getQuotaDefinitions () { + + const url = `${this.API_URL}/v2/space_quota_definitions`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = SpacesQuota; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Stacks.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Stacks.js new file mode 100644 index 0000000..1b170b4 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Stacks.js @@ -0,0 +1,41 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage Stacks + */ +class Stacks extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Stacks + * {@link http://apidocs.cloudfoundry.org/214/stacks/list_all_stacks.html} + * + * @return {JSON} [return a JSON response] + */ + getStacks () { + + const url = `${this.API_URL}/v2/stacks`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = Stacks; \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/UserProvidedServices.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/UserProvidedServices.js new file mode 100644 index 0000000..596facf --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/UserProvidedServices.js @@ -0,0 +1,139 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage User Provided Services + * {@link https://docs.cloudfoundry.org/devguide/services/user-provided.html} + */ +class UserProvidedServices extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Get Services + * {@link http://apidocs.cloudfoundry.org/217/user_provided_service_instances/list_all_user_provided_service_instances.html} + * + * @return {JSON} [return a JSON response] + */ + getServices () { + + const url = `${this.API_URL}/v2/user_provided_service_instances`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Get a Service + * {@link http://apidocs.cloudfoundry.org/217/user_provided_service_instances/retrieve_a_particular_user_provided_service_instance.html} + * + * @param {String} guid [Service guid] + * @return {JSON} [return a JSON response] + */ + getService (guid) { + + const url = `${this.API_URL}/v2/user_provided_service_instances/${guid}`; + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Create an user Provided Service + * {@link http://apidocs.cloudfoundry.org/217/user_provided_service_instances/creating_a_user_provided_service_instance.html} + * + * @param {JSON} upsOptions [user_provided_service_options] + * @return {JSON} [return a JSON response] + */ + add (upsOptions) { + + const url = `${this.API_URL}/v2/user_provided_service_instances`; + const options = { + method: "POST", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(upsOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Remove an User provided service + * {@link http://apidocs.cloudfoundry.org/217/user_provided_service_instances/delete_a_particular_user_provided_service_instance.html} + * + * @param {String} guid [service_guid] + * @return {String} [output] + */ + remove (guid) { + + const url = `${this.API_URL}/v2/user_provided_service_instances/${guid}`; + const options = { + method: "DELETE", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + + /** + * Get service bindings from user provided services + * {@link http://apidocs.cloudfoundry.org/221/user_provided_service_instances/list_all_service_bindings_for_the_user_provided_service_instance.html} + * + * @example + * var filter = { + * q': 'app_guid:' + "65be2a2d-a643-4e01-b33d-8755d5934ae6" + * }; + * + * @param {String} guid [service_guid] + * @param {JSON} filter [search options] + * @return {JSON} [Output] + */ + getServiceBindings (guid, filter) { + + const url = `${this.API_URL}/v2/user_provided_service_instances/${guid}/service_bindings`; + let qs = {}; + + if (filter) { + qs = filter; + } + const options = { + method: "GET", + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + qs: qs + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = UserProvidedServices; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Users.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Users.js new file mode 100644 index 0000000..6714691 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/cloudcontroller/Users.js @@ -0,0 +1,133 @@ +"use strict"; + +const CloudControllerBase = require("./CloudControllerBase"); + +/** + * Manage Users + */ +class Users extends CloudControllerBase { + + /** + * @param {String} endPoint [CC endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + super(endPoint); + } + + /** + * Add a User + * {@link http://apidocs.cloudfoundry.org/222/users/creating_a_user.html} + * + * @param {JSON} userOptions [user options] + * @return {JSON} [return a JSON response] + */ + add (userOptions) { + + const url = `${this.API_URL}/v2/users`; + const options = { + method: "POST", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + form: JSON.stringify(userOptions) + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Delete an User + * {@link http://apidocs.cloudfoundry.org/222/users/delete_a_particular_user.html} + * + * @param {String} guid [user guid] + * @return {JSON} [return a JSON response] + */ + remove (guid) { + + const url = `${this.API_URL}/v2/users/${guid}`; + const options = { + method: "DELETE", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.NO_CONTENT, false); + } + + /** + * Get Users + * {@link http://apidocs.cloudfoundry.org/222/users/list_all_users.html} + * + * @return {JSON} [return a JSON response] + */ + getUsers () { + + const url = `${this.API_URL}/v2/users`; + const options = { + method: "GET", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Associate User with a Space + * {@link http://apidocs.cloudfoundry.org/222/users/associate_space_with_the_user.html} + * + * @param {String} userGuid [user guid] + * @param {String} spaceGuid [space guid] + * @return {JSON} [return a JSON response] + */ + associateSpace (userGuid, spaceGuid) { + + const url = `${this.API_URL}/v2/users/${userGuid}/spaces/${spaceGuid}`; + const options = { + method: "PUT", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + + /** + * Associate User with an Organization + * {@link http://apidocs.cloudfoundry.org/222/users/associate_organization_with_the_user.html} + * + * @param {String} userGuid [user guid] + * @param {String} orgGuid [space guid] + * @return {JSON} [return a JSON response] + */ + associateOrganization (userGuid, orgGuid) { + + const url = `${this.API_URL}/v2/users/${userGuid}/organizations/${orgGuid}`; + const options = { + method: "PUT", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.CREATED, true); + } + +} + +module.exports = Users; diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/metrics/Logs.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/metrics/Logs.js new file mode 100644 index 0000000..11b7f11 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/metrics/Logs.js @@ -0,0 +1,65 @@ +"use strict"; + +const HttpUtils = require("../../utils/HttpUtils"); +const HttpStatus = require("../../utils/HttpStatus"); + +/** + * Manage Logs in Cloud Foundry + * {@link https://docs.pivotal.io/pivotalcf/devguide/deploy-apps/streaming-logs.html} + * @constructor + */ +class Logs { + + /** + * Constructor + * @constructor + * @returns {void} + */ + constructor() { + this.REST = new HttpUtils(); + this.HttpStatus = HttpStatus; + } + + /** + * Set endpoint + * @param {String} endPoint [Logging endpoint] + * @returns {void} + */ + setEndPoint (endPoint) { + + this.LOG_API_URL = endPoint; + } + + /** + * Set token + * @param {JSON} token [Oauth token from UAA] + * @returns {void} + */ + setToken (token) { + + this.UAA_TOKEN = token; + } + + /** + * Method used to return data from CF log services. + * {@link http://docs.run.pivotal.io/devguide/deploy-apps/streaming-logs.html} + * + * @param {String} appGuid [app guid] + * @return {JSon} [UAA Response] + */ + getRecent (appGuid) { + + const url = `${this.LOG_API_URL}/recent?app=${appGuid}`; + const options = { + url: url, + headers: { + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, false); + } + +} + +module.exports = Logs; \ No newline at end of file diff --git a/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/uaa/UsersUAA.js b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/uaa/UsersUAA.js new file mode 100644 index 0000000..4093438 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/cf-nodejs-client/model/uaa/UsersUAA.js @@ -0,0 +1,199 @@ +"use strict"; + +const HttpUtils = require("../../../../helpers/http-utils"); +const HttpStatus = require("../../../../helpers/http-status"); + +/** + * Manage Users on Cloud Foundry UAA + */ +class UsersUAA { + + /** + * Constructor + * @param {String} endPoint [UAA endpoint] + * @constructor + * @returns {void} + */ + constructor(endPoint) { + this.UAA_API_URL = endPoint; + this.REST = new HttpUtils(); + this.HttpStatus = HttpStatus; + } + + /** + * Set endpoint + * @param {String} endPoint [UAA endpoint] + * @returns {void} + */ + setEndPoint (endPoint) { + + this.UAA_API_URL = endPoint; + } + + /** + * Set token + * @param {JSON} token [Oauth token from UAA] + * @returns {void} + */ + setToken (token) { + + this.UAA_TOKEN = token; + } + + /** + * Add an User on UAA + * {@link https://github.com/cloudfoundry/uaa/blob/master/docs/UAA-APIs.rst#create-a-user-post-users} + * {@link http://www.simplecloud.info/specs/draft-scim-api-01.html#create-resource} + * + * @param {JSON} uaaOptions [user options] + * @return {JSON} [return a JSON response] + */ + add (uaaOptions) { + + const url = `${this.UAA_API_URL}/Users`; + const options = { + method: "POST", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + json: uaaOptions + }; + + return this.REST.request(options, this.HttpStatus.CREATED, false); + } + + /** + * Update Password [PENDING] + * {@link https://github.com/cloudfoundry/uaa/blob/master/docs/UAA-APIs.rst#create-a-user-post-users} + * {@link http://www.simplecloud.info/specs/draft-scim-api-01.html#create-resource} + * + * @param {JSON} uaaGuid [uaa guid] + * @param {JSON} uaaOptions [user options] + * @return {JSON} [return a JSON response] + */ + updatePassword (uaaGuid, uaaOptions) { + + const url = `${this.UAA_API_URL}/Users/${uaaGuid}/password`; + const options = { + method: "PUT", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + }, + json: uaaOptions + }; + + return this.REST.request(options, this.HttpStatus.OK, false); + } + + /** + * Remove an User + * {@link http://www.simplecloud.info/specs/draft-scim-api-01.html#delete-resource} + * + * @param {String} uaaGuid [uaa guid] + * @return {JSON} [return a JSON response] + */ + remove (uaaGuid) { + + const url = `${this.UAA_API_URL}/Users/${uaaGuid}`; + const options = { + method: "DELETE", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, false); + } + + /** + * Get users + * {@link http://www.simplecloud.info/specs/draft-scim-api-01.html#get-resources-ops} + * + * @example + * ?filter=userName eq 'demo4'" + * + * @param {JSON} searchOptions [searchOptions] + * @return {JSON} [return a JSON response] + */ + getUsers (searchOptions) { + + let url = `${this.UAA_API_URL}/Users`; + + if (searchOptions) { + url += searchOptions; + } + const options = { + method: "GET", + url: url, + headers: { + Accept: "application/json", + Authorization: `${this.UAA_TOKEN.token_type} ${this.UAA_TOKEN.access_token}` + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Method to authenticate with Cloud Foundry UAA + * @param {String} username [username] + * @param {String} password [password] + * @return {JSon} [UAA Response] + */ + login (username, password) { + + const url = `${this.UAA_API_URL}/oauth/token`; + const options = { + method: "POST", + url: url, + headers: { + Authorization: "Basic Y2Y6", + "Content-Type": "application/x-www-form-urlencoded" + }, + form: { + grant_type: "password", + client_id: "cf", + username: username, + password: password + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + + /** + * Method to refresh a Token + * https://github.com/cloudfoundry/uaa/blob/master/docs/UAA-Tokens.md + * + * @param {String} refreshToken [Oauth refresh token] + * @return {JSON} [Response] + */ + refreshToken () { + + const url = `${this.UAA_API_URL}/oauth/token`; + const options = { + method: "POST", + url: url, + headers: { + Accept: "application/json", + Authorization: "Basic Y2Y6", + "Content-Type": "application/x-www-form-urlencoded" + }, + form: { + grant_type: "refresh_token", + refresh_token: this.UAA_TOKEN.refresh_token + } + }; + + return this.REST.request(options, this.HttpStatus.OK, true); + } + +} + +module.exports = UsersUAA; diff --git a/apigee-cf-service-broker/lib/providers/edge_proxy.js b/apigee-cf-service-broker/lib/providers/edge_proxy.js new file mode 100644 index 0000000..4630d7c --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/edge_proxy.js @@ -0,0 +1,213 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Create proxy on Edge + * @module + */ + +var JSZip = require('jszip') +var fs = require('fs') +var importProxy = require('./mgmt_api').importProxy +var getVirtualHosts = require('./mgmt_api').getVirtualHosts +var logger = require('../helpers/logger') +var template = require('es6-template-strings') +var openApi = require('./open_api.js') + +const config = require('../../config/environment') + +// create proxy in edge org +function createProxy (bindReq, callback) { + var proxyHostTemplate = bindReq.host || bindReq.configuration.get('APIGEE_PROXY_HOST_TEMPLATE') + var mangledName = bindReq.proxyname || template(bindReq.configuration.get('APIGEE_PROXY_NAME_TEMPLATE'), { + route: bindReq.bind_resource.route + || bindReq.micro_coresident.target_app_route + || bindReq.micro_c2c.target_app_route + || bindReq.portal.target_app_name + }) + // Regex of allowed characters (obviously case insensitive) according to API docs + mangledName = mangledName.replace(/[^A-Z0-9._\-$ %]+/ig, '_') // route can be host.domain/path + + var union = {} + if (Object.getOwnPropertyNames(bindReq.micro_coresident).length > 0) { + mangledName = 'edgemicro_' + mangledName + union = Object.assign({ + domain: bindReq.configuration.get('APIGEE_PROXY_DOMAIN'), + proxyname: mangledName, + basepath: '/' + bindReq.micro_coresident.target_app_route, + credentials: { + edgemicro_key: bindReq.micro_coresident.edgemicro_key, + edgemicro_secret: bindReq.micro_coresident.edgemicro_secret, + apigee_org: bindReq.org, + apigee_env: bindReq.env, + apigee_proxy: mangledName + } + }, bindReq) + } else if (Object.getOwnPropertyNames(bindReq.micro_c2c).length > 0) { + var backendAppName = bindReq.micro_c2c.target_app_route.split(".")[0] + mangledName = 'edgemicro_' + bindReq.micro_c2c.target_app_route + union = Object.assign({ + domain: bindReq.configuration.get('APIGEE_PROXY_DOMAIN'), + proxyname: mangledName, + basepath: '/' + backendAppName, + credentials: { + apigee_org: bindReq.org, + apigee_env: bindReq.env, + apigee_proxy: mangledName + } + }, bindReq) + } else if (Object.getOwnPropertyNames(bindReq.portal).length > 0) { + var backendAppName = bindReq.portal.target_app_route.split(".")[0] + + mangledName = 'edgemicro_' + bindReq.portal.target_app_route + union = Object.assign({ + domain: bindReq.configuration.get('APIGEE_PROXY_DOMAIN'), + proxyname: mangledName, + basepath: '/' + backendAppName, + credentials: { + apigee_org: bindReq.org, + apigee_env: bindReq.env, + apigee_proxy: mangledName + } + }, bindReq) + } + else { + if (bindReq.micro){ + proxyHostTemplate = bindReq.micro + mangledName = 'edgemicro_' + mangledName + } + union = Object.assign({ + domain: bindReq.configuration.get('APIGEE_PROXY_DOMAIN'), + proxyname: mangledName, + basepath: '/' + bindReq.bind_resource.route, + credentials: {} + }, bindReq) + } + + logger.log.info('domain: ', union.domain, ' proxyname: ', union.proxyname, ' basepath: ', union.basepath) + + var bindResponse = function(deployRes) { + if (bindReq.action.bind) { + var proxyUrlRoot = template(proxyHostTemplate, union) + bindReq.proxyURL = 'https://' + proxyUrlRoot + union.basepath + bindReq.proxyname = union.proxyname + bindReq.credentials = union.credentials + logger.log.info('route proxy url:', bindReq.proxyURL, '->', bindReq.proxyname) + callback(null, bindReq) // bindReq request plus added results becomes bindRes response + } + else { + var detail = "proxy name: " + union.proxyname + ", revision: " + deployRes.revision + if (deployRes.statusCode != 200 && deployRes.statusCode != 201) { + detail += ", detail: " + deployRes.body.message + } + var loggerError = logger.INFO_PROXY_CREATED_STOP(null, null, detail) + callback(loggerError) + } + } + + if (bindReq.action.proxy) { + uploadProxy(union, function (err, deployRes) { + if (err) { + var loggerError = logger.ERR_PROXY_UPLOAD_FAILED(err) + callback(loggerError) + } else { + logger.log.info("created proxy") + logger.log.info(deployRes) + bindResponse(deployRes) + } + }) + } + else { + bindResponse() + } +} + +// should just get route details here, so we have access to parameters (add features) +function uploadProxy (proxyData, callback) { + getZip(proxyData, function (err, zipBuffer) { + if (err) { + var loggerError = logger.ERR_PROXY_ZIP(err) + callback(loggerError) + } else { + importProxy(proxyData, zipBuffer, callback) + } + }) +} + +/** + * @param proxyData - Union of properties required for this function, and `mgmt_api.getVirtualHosts` + * @param proxyData.proxyname + * @param proxyData.basepath + * @param proxyData.bind_resource.route + */ +function getZip (proxyData, callback) { + fs.readFile('./proxy-resources/apiproxy.zip', function (err, data) { + if (err) { + var loggerError = logger.ERR_PROXY_READ_FAILED(err) + callback(loggerError) + } else { + var zip = new JSZip(data) + var re1 = /%BASEPATH%/g + var re2 = /%PROXYNAME%/g + var re3 = /%VIRTUALHOSTS%/g + var re4 = /%TARGETURL%/g + // get virtual hosts for org/env + getVirtualHosts(proxyData, function (err, data) { + if (err) { + var loggerError = logger.ERR_UAE(err) + callback(loggerError) + } else { + var dummyTargetUrl + if(Object.getOwnPropertyNames(proxyData.micro_coresident).length > 0){ + dummyTargetUrl = "http://localhost:" + proxyData.micro_coresident.target_app_port + } else if (Object.getOwnPropertyNames(proxyData.micro_c2c).length > 0) { + dummyTargetUrl = proxyData.protocol + "://" + proxyData.micro_c2c.target_app_internal_route + ":" + proxyData.micro_c2c.target_app_port + // dummyTargetUrl = proxyData.protocol + "://" + proxyData.bind_resource.route + ":" + proxyData.micro_c2c.target_app_port + } else if (Object.getOwnPropertyNames(proxyData.portal).length > 0) { + const protocol = proxyData.protocol ? proxyData.protocol : 'http' + const port = proxyData.portal.port ? proxyData.portal.port : '' + dummyTargetUrl = `${protocol}://${proxyData.portal.target_app_route}.${config.cf.appsBaseDomain}${port ? ':'+port : ''}` + } else { + dummyTargetUrl = proxyData.protocol + "://" + proxyData.bind_resource.route // Actual is X-Cf-Forwarded-Url header + } + var vHostString = JSON.parse(data).map(function (val) { return '' + val + '' }).join('\n') + var proxyDefTemplate = zip.folder('apiproxy/proxies').file('default.xml') + var proxyDefValue = proxyDefTemplate.asText().replace(re1, proxyData.basepath) + proxyDefValue = proxyDefValue.replace(re3, vHostString) + zip.folder('apiproxy/proxies').file('default.xml', proxyDefValue) + var proxyNameTemplate = zip.file('apiproxy/cf-proxy.xml').asText() + zip.file('apiproxy/cf-proxy.xml', proxyNameTemplate.replace(re2, proxyData.proxyname)) + var targetNameTemplate = zip.file('apiproxy/targets/default.xml').asText() + zip.file('apiproxy/targets/default.xml', targetNameTemplate.replace(re4, dummyTargetUrl)) + // Check for open Api & add policy support + openApi.generatePolicy(dummyTargetUrl, zip, function(err, updatedZip) { + if (err) { + callback(null, this.zip.generate({type: 'nodebuffer'})) + } + else { + callback(null, updatedZip.generate({type: 'nodebuffer'})) + } + }.bind({ zip: zip })) + } + }) + } + }) +} + +module.exports = { + create: createProxy +} diff --git a/apigee-cf-service-broker/lib/providers/mgmt_api.js b/apigee-cf-service-broker/lib/providers/mgmt_api.js new file mode 100644 index 0000000..80fe175 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/mgmt_api.js @@ -0,0 +1,261 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Edge Management API calls + * + * @param proxyData + * @param proxyData.org + * @param proxyData.env + * @param proxyData.user + * @param proxyData.pass + * @param proxyData.proxyname + * + * @module + */ + +var request = require('request') +var logger = require('../helpers/logger') + +/* Destructure, spread operator: Node 6 +function auth(obj) { + const {user, pass} = obj + return {user, pass} +} + +function mgmtUrl() { + const vX = config.get('APIGEE_MGMT_API_URL') + return [vX, ...arguments].join('/') +} + +function org(obj, ...rest) { + return mgmtUrl('organizations', obj.org, ...rest) +} + +function orgEnv(obj, ...rest) { + return org(obj, 'environments', obj.env, ...rest) +} +*/ + +function auth(options, obj) { + if (obj.user && obj.pass) { + options.auth = { + user: obj.user, + pass: obj.pass + } + } else if (obj.basic) { + options.headers = { + 'Authorization': 'Basic ' + obj.basic + } + } else { + options.auth = { + bearer: obj.bearer + } + } +} + +function mgmtUrl() { + const args = Array.prototype.slice.call(arguments) + const obj = args.shift() + return [obj.configuration.get('APIGEE_MGMT_API_URL')].concat(args).join('/') +} + +function org() { + const args = Array.prototype.slice.call(arguments) + const obj = args.shift() + return mgmtUrl.apply(null, [obj, 'organizations', obj.org].concat(args)) +} + +function orgEnv() { + const args = Array.prototype.slice.call(arguments) + const obj = args.shift() + return org.apply(null, [obj, 'environments', obj.env].concat(args)) +} + + +function getProxyRevision (proxyData, callback) { + var options = { + url: org(proxyData, 'apis', proxyData.proxyname) + } + logger.log.info("Get proxy revision url: " + options.url) + auth(options, proxyData) + request.get(options, function (err, res, body) { + if (err) { + err.url = options.url + var loggerError = logger.ERR_APIGEE_REQ_FAILED(err) + callback(loggerError) + } else if (res.statusCode == 401) { + var loggerError = logger.ERR_APIGEE_AUTH(err, 401) + callback(loggerError) + } else if (res.statusCode == 404) { + var loggerError = logger.ERR_APIGEE_PROXY_NOT_FOUND(err, 404) + callback(loggerError) + } else if (res.statusCode !== 200) { + var loggerError = logger.ERR_APIGEE_GET_PROXY_REV_FAILED(body, res.statusCode) + callback(loggerError) + } else { + body = JSON.parse(body) + var revision = body.revision.pop() + callback(null, revision) + } + }) +} + +function importProxy (proxyData, zipBuffer, callback) { + var formData = { + file: zipBuffer + } + var options = { + url: org(proxyData, 'apis'), + formData: formData, + qs: { + action: 'import', + name: proxyData.proxyname + } + } + logger.log.info("Import proxy url: " + options.url, " proxy name: ", options.qs.name) + auth(options, proxyData) + request.post(options, function (err, httpResponse, body) { + if (err) { + err.url = options.url + err.qs = options.qs + var loggerError = logger.ERR_APIGEE_REQ_FAILED(null, err) + callback(loggerError) + } else if (httpResponse.statusCode !== 201) { + var loggerError = logger.ERR_APIGEE_PROXY_UPLOAD(null, body, httpResponse.statusCode) + callback(loggerError) + } else { + deployProxy(proxyData, callback) + } + }) +} + + +function deployments(obj, revision) { + return orgEnv(obj, 'apis', obj.proxyname, 'revisions', revision, 'deployments') +} + +function deployProxy (proxyData, callback) { + // should get latest version and deploy that + getProxyRevision(proxyData, function (err, revision) { + if (err) { + var loggerError = logger.ERR_UAE(err) + callback(loggerError) + } else { + var options = { + url: deployments(proxyData, revision) + } + logger.log.info("Deploy proxy url: " + options.url) + auth(options, proxyData) + request.post(options, function (err, res, body) { + if (err) { + console.info('ERR', err) + var loggerError = logger.ERR_APIGEE_DEPLOY_PROXY(err) + callback(loggerError) + } else { + try { + body = JSON.parse(body) + } catch (x) { + } + callback(null, { + revision: revision, + statusCode: res.statusCode, + body: body + }) + } + }) + } + }) +} + +function undeployProxy (proxyData, callback) { + // should get latest version and undeploy that + getProxyRevision(proxyData, function (err, revision) { + if (err) { + var loggerError = logger.ERR_UAE(err) + callback(loggerError) + } else { + var options = { + url: deployments(proxyData, revision) + } + logger.log.info("Undeploy proxy url: " + options.url) + auth(options, proxyData) + request.del(options, function (err, res, body) { + if (err) { + var loggerError = logger.ERR_APIGEE_UNDEPLOY_PROXY_FAILED(err) + callback(loggerError) + } else { + callback(null, res) + } + }) + } + }) +} + +function getVirtualHosts (proxyData, callback) { + var options = { + url: orgEnv(proxyData, 'virtualhosts') + } + logger.log.info("Get virtual hosts url: " + options.url) + auth(options, proxyData) + request.get(options, function (err, res, body) { + if (err) { + err.url = options.url + var loggerError = logger.ERR_APIGEE_REQ_FAILED(err) + callback(loggerError) + } else if (res.statusCode !== 200) { + var loggerError = logger.ERR_PROXY_VHOSTS_NON200_RES(body, res.statusCode) + callback(loggerError) + } else { + callback(null, body) + } + }) +} + + +function authenticate (authOptions, callback) { + var options = { + url: org(authOptions) + } + logger.log.info("Authenticate url: " + options.url) + auth(options, authOptions) + request.get(options, function (err, res, body) { + if (err) { + err.url = options.url + var loggerError = logger.ERR_APIGEE_REQ_FAILED(err) + callback(loggerError) + } else if (res.statusCode !== 200) { + var loggerError + if (res.statusCode == 401 && authOptions.bearer) { + loggerError = logger.ERR_APIGEE_AUTH_BEARER_FAILED(body, res.statusCode) + } else { + loggerError = logger.ERR_APIGEE_AUTH(body, res.statusCode) + } + callback(loggerError) + } else { + callback(null, body) + } + }) +} + +module.exports = { + importProxy: importProxy, + getVirtualHosts: getVirtualHosts, + deployProxy: deployProxy, + undeployProxy: undeployProxy, + authenticate: authenticate +} diff --git a/apigee-cf-service-broker/lib/providers/open_api.js b/apigee-cf-service-broker/lib/providers/open_api.js new file mode 100644 index 0000000..93f6240 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/open_api.js @@ -0,0 +1,278 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Generate proxy from OpenAPI interface file + * @module + */ +var swaggerParser = require('swagger-parser') +var async = require('async') +var logger = require('../helpers/logger') +var quota = require('../../policy_templates/quota/quota.js') +var spike = require('../../policy_templates/spikeArrest/spikeArrest.js') +var cache = require('../../policy_templates/cache/responseCache.js') +var verifyApiKey = require('../../policy_templates/security/apikey.js') +var oauth2 = require('../../policy_templates/security/verifyAccessToken.js') +var xmlToJson = require('../../policy_templates/mediation/xmlToJson.js') +var jsonToXml = require('../../policy_templates/mediation/jsonToXml.js') +var DOMParser = require('xmldom').DOMParser +var XMLSerializer = require('xmldom').XMLSerializer +var builder = require('xmlbuilder') + +function getOpenApi (routeUrl, callback) { + const paths = ['/openApi.json', '/openApi.yaml'] + async.map(paths, function (path, cb) { + const url = routeUrl + path + swaggerParser.parse(url, function (err, api, metadata) { + if (err) { + console.info('ERR', err) + if (err.message && err.message.includes('HTTP ERROR 404')) { + logger.log.info("OpenAPI not found at %s", url) + cb(null, null) // plain 404 is to be expected + } else { + var loggerError = logger.ERR_OPENAPI_PARSE_FAIL(err) + cb(loggerError) + } + } else { + logger.log.info("OpenAPI parsed at %s", url) + cb(null, api) + } + }) + }, + function (err, specs) { + if (err) { + callback(err) + } else { + const first = specs.reduce(function (memo, value, index) { + return memo ? memo : value; + }, null) + callback(null, first) + } + }) +} + + +var generatePolicy = function (routeUrl, zip, callback) { + async.waterfall([ + getOpenApi.bind(this, routeUrl), + function (api, callback) { + if (! api) { + callback(true) // Just didn't find spec, nothing "went wrong" + } + // Valid openApi Found -- Look for apigee Policies + else if (api['x-apigee-policies']) { + async.each(Object.keys(api['x-apigee-policies']), function (service, cb) { + // Perform operation on file here. + var policy = api['x-apigee-policies'][service].type + var xmlString = '' + if (policy === 'quota') { + // Add Quota Policy + xmlString = quota.quotaGenTemplate(api['x-apigee-policies'][service].options, service) + } + if (policy === 'spikeArrest') { + // Add spike Policy + xmlString = spike.spikeArrestGenTemplate(api['x-apigee-policies'][service].options, service) + } + if (policy === 'responseCache') { + // Add cache Policies + xmlString = cache.responseCacheGenTemplate(api['x-apigee-policies'][service].options, service) + } + if (policy === 'verifyApiKey') { + // Add cache Policies + xmlString = verifyApiKey.apiKeyGenTemplate(api['x-apigee-policies'][service].options, service) + } + if (policy === 'oAuthV2') { + // Add cache Policies + xmlString = oauth2.verifyAccessTokenGenTemplate(api['x-apigee-policies'][service].options, service) + } + if (policy === 'xmlToJson') { + // Add cache Policies + xmlString = xmlToJson.xmlToJsonGenTemplate(api['x-apigee-policies'][service].options, service) + } + if (policy === 'jsonToXml') { + // Add cache Policies + xmlString = jsonToXml.jsonToXmlGenTemplate(api['x-apigee-policies'][service].options, service) + } + if (xmlString !== '') { + zip.folder('apiproxy/policies').file(service + '.xml', xmlString) + } + cb(null) + }, function (err) { + // if any of the file processing produced an error, err would equal that error + if (err) { + callback(err) + } else { + callback(null, api, zip) + } + }) + } else { + // TODO: Error / Warning + var loggerError = logger.ERR_POLICIES_NOT_FOUND() + callback(loggerError) + } + }, + function (api, zip, callback) { + // Attach policies to preFlow / postFlow + if (api['x-apigee-apply']) { + var proxyText = zip.file('apiproxy/proxies/default.xml').asText() + var targetText = zip.file('apiproxy/targets/default.xml').asText() + var proxyParser = new DOMParser().parseFromString(proxyText, 'text/xml') + var targetParser = new DOMParser().parseFromString(targetText, 'text/xml') + async.each(Object.keys(api['x-apigee-apply']), function (service, cb) { + var flow = api['x-apigee-apply'][service].options.flow.charAt(0).toUpperCase() + api['x-apigee-apply'][service].options.flow.slice(1) + var reqRes = api['x-apigee-apply'][service].options['on'].charAt(0).toUpperCase() + api['x-apigee-apply'][service].options['on'].slice(1) + if (api['x-apigee-apply'][service].options.endPoint === 'proxy') { + try { + var flowParser = proxyParser.documentElement.getElementsByTagName(flow)[0] + var flowReqRes = flowParser.getElementsByTagName(reqRes)[0] + flowReqRes.appendChild(new DOMParser().parseFromString('' + service + '', 'text/xml')) + } catch (ex) { + // do nothing, just print error to log + logger.ERR_INVALID_OPENAPI_SPEC(ex) + } + } + else if (api['x-apigee-apply'][service].options.endPoint === 'target') { + try { + var flowParser = targetParser.documentElement.getElementsByTagName(flow)[0] + var flowReqRes = flowParser.getElementsByTagName(reqRes)[0] + flowReqRes.appendChild(new DOMParser().parseFromString('' + service + '', 'text/xml')) + } catch (ex) { + // do nothing, just print error to log + logger.ERR_INVALID_OPENAPI_SPEC(ex) + } + } + cb(null) + }, function (err) { + // if any of the file processing produced an error, err would equal that error + if (err) { + callback(err) + } + else { + // Add back to zip + zip.file('apiproxy/targets/default.xml', new XMLSerializer().serializeToString(targetParser)) + zip.file('apiproxy/proxies/default.xml', new XMLSerializer().serializeToString(proxyParser)) + callback(null, api, zip) + } + }) + } else { + callback(null, api, zip) + } + }, + function (api, zip, callback) { + // Attach conditional flows + var proxyText = zip.file('apiproxy/proxies/default.xml').asText() + var targetText = zip.file('apiproxy/targets/default.xml').asText() + var proxyParser = new DOMParser().parseFromString(proxyText, 'text/xml') + var targetParser = new DOMParser().parseFromString(targetText, 'text/xml') + var allowedVerbs = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'HEAD', 'TRACE', 'CONNECT', 'PATCH'] + + for (var apiPath in api.paths) { + + for (var resource in api.paths[apiPath]) { + + if (allowedVerbs.indexOf(resource.toUpperCase()) >= 0) { + var resourceItem = api.paths[apiPath][resource] + + resourceItem.operationId = resourceItem.operationId || resource.toUpperCase() + ' ' + apiPath + + var proxyFlowElement = builder.create('Flow', { headless: true }).att('name', resourceItem.operationId) + + var targetFlowElement = builder.create('Flow', { headless: true }).att('name', resourceItem.operationId) + var flowCondition = '(request.uri MatchesPath "' + apiPath + '") and (request.verb = "' + resource.toUpperCase() + '")' + proxyFlowElement.ele('Condition').raw(flowCondition) + proxyFlowElement.ele('Description', {}, resourceItem.summary) + targetFlowElement.ele('Condition').raw(flowCondition) + targetFlowElement.ele('Description', {}, resourceItem.summary) + var requestPipeProxy = proxyFlowElement.ele('Request') + var responsePipeProxy = proxyFlowElement.ele('Response') + var requestPipeTarget = targetFlowElement.ele('Request') + var responsePipeTarget = targetFlowElement.ele('Response') + var proxyFlow = false + var targetFlow = false + if (resourceItem['x-apigee-apply']) { + // Check proxy / target conditonal flows has any policies + for (var service in resourceItem['x-apigee-apply']) { + if (resourceItem['x-apigee-apply'][service].options.endPoint.indexOf('proxy') > -1) { + proxyFlow = true + // Attach policies now + if (resourceItem['x-apigee-apply'][service].options['on'].indexOf('request') > -1) { + var step = requestPipeProxy.ele('Step', {}) + step.ele('Name', {}, service) + } + if (resourceItem['x-apigee-apply'][service].options['on'].indexOf('response') > -1) { + var step = responsePipeProxy.ele('Step', {}) + step.ele('Name', {}, service) + } + } else if (resourceItem['x-apigee-apply'][service].options.endPoint.indexOf('target') > -1) { + targetFlow = true + // Attach policies now + // Attach policies now + if (resourceItem['x-apigee-apply'][service].options['on'].indexOf('request') > -1) { + var step = requestPipeTarget.ele('Step', {}) + step.ele('Name', {}, service) + } + if (resourceItem['x-apigee-apply'][service].options['on'].indexOf('response') > -1) { + var step = responsePipeTarget.ele('Step', {}) + step.ele('Name', {}, service) + } + } + } + } // check for normal policies ends here + // Check for Security Policies + if (resourceItem['security']) { + proxyFlow = true + // Attach policies now + for (var security in resourceItem['security']) { + for (var stepName in resourceItem['security'][security]) { + // Attach verify access token policy.. + var step = requestPipeProxy.ele('Step', {}) + step.ele('Name', {}, stepName) + } + } + } + if (proxyFlow) { + var flowParser = proxyParser.documentElement.getElementsByTagName('Flows')[0] + flowParser.appendChild(new DOMParser().parseFromString(proxyFlowElement.end({ indent: ' ', newline: '\n' }), 'text/xml')) + } + if (targetFlow) { + var flowParser = targetParser.documentElement.getElementsByTagName('Flows')[0] + flowParser.appendChild(new DOMParser().parseFromString(targetFlowElement.end({ indent: ' ', newline: '\n' }), 'text/xml')) + } + } // methods check ends here + } // for loop for resources ends here + } // for loop for paths ends here + zip.file('apiproxy/targets/default.xml', new XMLSerializer().serializeToString(targetParser)) + zip.file('apiproxy/proxies/default.xml', new XMLSerializer().serializeToString(proxyParser)) + callback(null, zip) + } + ], function (err, zip) { + if (err === true) { + logger.log.info("Did not find OpenAPI interface file for %s", routeUrl) + callback(true) // Nothing to wrap or log with stack trace + } else if (err) { + var loggerError = logger.ERR_UAE(err) + callback(loggerError) + } else { + logger.log.info("Applying OpenAPI interface file for %s", routeUrl) + callback(null, zip) + } + }) +} + +module.exports = { + generatePolicy: generatePolicy +} diff --git a/apigee-cf-service-broker/lib/providers/service-binding.js b/apigee-cf-service-broker/lib/providers/service-binding.js new file mode 100644 index 0000000..6cd23c4 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/service-binding.js @@ -0,0 +1,103 @@ +'use strict' +/* + * Copyright 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Creates/deletes service binding + * @module + */ + +var async = require('async') +var logger = require('../helpers/logger') +var mgmt_api = require('./mgmt_api') +var proxy = require('./edge_proxy') + +function createServiceBinding (bindReq, callback) { + async.waterfall([ + function (cb) { + mgmt_api.authenticate(bindReq, function (err, data) { + if (err) { + // Don't return 401, which is reported as failure of basic-auth to the broker + if (err.statusCode == 401 || err.statusCode == 403) { + var loggerError = logger.ERR_APIGEE_AUTH(err, 407) + return cb(loggerError) + } else { + return cb(err, data) + } + } else { + return cb(null) + } + }) + }, + function (cb) { + (async () => { + try { + const result = await bindReq.plan.runBinding(bindReq) + + if (result.error) { + return cb(result.error) + } + return cb(null, result) + } catch (error) { + return cb(error) + } + })() + }, + function (data, cb) { + const { appsInternalFullHostName, appsDomain } = data + + // TODO refactor me to plan instance + if(bindReq.micro_c2c && bindReq.micro_c2c.target_app_route && !bindReq.micro_c2c.off_c2c_binding) { + // can use the parameter on edge_proxy.line-164 to replace public route to internal route for proxy target + bindReq.micro_c2c.target_app_internal_route = appsInternalFullHostName + bindReq.base_apps_domain = appsDomain.entity.name + } + + proxy.create(bindReq, function (err, bindRes) { + if (err) { + var loggerError = logger.ERR_PROXY_CREATION_FAILED(err) + cb(loggerError) + } else { + (async () => { + const bindingResult = await bindReq.plan.runPostBinding(bindRes) + if (bindingResult.error) { + return cb(bindingResult.error) + } + // result needs to have URL details in it + cb(null, bindRes) + })() + } + }) + } + ], + callback) +} + +// wrap createServiceBinding with Promise - for async-await usage +const createAsync = async (bindReq) => { + return new Promise((resolve, reject) => { + return createServiceBinding(bindReq, (err, result) => { + if (err) return reject(err) + + return resolve(result) + }) + }) +} + +module.exports = { + create: createServiceBinding, + createAsync +} diff --git a/apigee-cf-service-broker/lib/providers/service-plans/index.js b/apigee-cf-service-broker/lib/providers/service-plans/index.js new file mode 100644 index 0000000..53aef46 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/service-plans/index.js @@ -0,0 +1,108 @@ +const path = require('path') +const Org = require('./org') +const Micro = require('./micro') +const Microc2c = require('./micro-c2c') +const MicroCoresident = require('./micro-coresident') +const Portal = require('./portal') +const config = require(path.resolve('./config/environment')) +const logger = require(path.resolve('./lib/helpers/logger')) +const { guid } = require(path.resolve('./lib/providers/catalog_data')) +const { SERVICE_PLANS } = require(path.resolve('./lib/helpers/enums')) + +class ServicePlans { + checkNonCoresidentPlan (param) { + let loggerError + if (param.target_app_route) { + loggerError = logger.ERR_NOT_MICRO_CORES_PLAN(null, null, '"target_app_route" parameter is invalid') + } else if (param.target_app_port) { + loggerError = logger.ERR_NOT_MICRO_CORES_PLAN(null, null, '"target_app_port" parameter is invalid') + } else if (param.edgemicro_key) { + loggerError = logger.ERR_NOT_MICRO_CORES_PLAN(null, null, '"edgemicro_key" parameter is invalid') + } else if (param.edgemicro_secret) { + loggerError = logger.ERR_NOT_MICRO_CORES_PLAN(null, null, '"edgemicro_secret" parameter is invalid') + } + + return loggerError + } + + checkCoresidentPlan (param) { + let loggerError + + if (!param.micro_coresident.target_app_route) { + loggerError = logger.ERR_MISSING_MICRO_CORES_PARAMETER(null, null, '"target_app_route" is required') + } else if (!param.micro_coresident.target_app_port) { + loggerError = logger.ERR_MISSING_MICRO_CORES_PARAMETER(null, null, '"target_app_port" is required') + } else if (!param.micro_coresident.edgemicro_key) { + loggerError = logger.ERR_MISSING_MICRO_CORES_PARAMETER(null, null, '"edgemicro_key" is required') + } else if (!param.micro_coresident.edgemicro_secret) { + loggerError = logger.ERR_MISSING_MICRO_CORES_PARAMETER(null, null, '"edgemicro_secret" is required') + } else if (param.micro) { + loggerError = logger.ERR_NOT_MICRO_PLAN() + } else if (param.bind_resource.route) { + loggerError = logger.ERR_BAD_BIND_COMMAND() + } + + return loggerError + } + + getProvider (param) { + let result + + let loggerError + + if (param.plan_id === guid.org) { + result = new Org() + result.name = SERVICE_PLANS.org + } else if (param.plan_id === guid.micro_coresident) { + // micro coresident plan + result = new MicroCoresident() + result.name = SERVICE_PLANS.microCoresident + } else if (param.plan_id === guid.micro) { + // micro plan + result = new Micro() + result.name = SERVICE_PLANS.micro + } else if (param.plan_id === guid.micro_c2c) { + // Micro C2C plan + result = new Microc2c() + result.name = SERVICE_PLANS.microc2c + } else if (param.plan_id === guid.portal) { + // Portal plan + result = new Portal() + result.name = SERVICE_PLANS.portal + } else { + // unknown plan + loggerError = logger.ERR_INVALID_SERVICE_PLAN() + } + + if (loggerError) { + return { error: loggerError } + } + // mixins for plan instances from the provider + // they used in plan.validate + result.checkNonCoresidentPlan = this.checkNonCoresidentPlan.bind(result) + result.checkCoresidentPlan = this.checkCoresidentPlan.bind(result) + + loggerError = result.validate(param) + + if (loggerError) { + return { error: loggerError } + } + return result + } + + validate (body) { + if (!body.parameters.target_app_route) { + return logger.ERR_MISSING_TARGET_APP_ROUTE() + } + return false + } + + getOutputParam (body) { + if (body.bind_resource && body.bind_resource.route) { + return { route_service_url: `${body.parameters.protocol}://${body.bind_resource.route}` } + } + return { route_service_url: `${body.parameters.protocol}://${body.parameters.target_app_route}.${config.cf.appsBaseDomain}` } + } +} + +module.exports = ServicePlans diff --git a/apigee-cf-service-broker/lib/providers/service-plans/micro-c2c.js b/apigee-cf-service-broker/lib/providers/service-plans/micro-c2c.js new file mode 100644 index 0000000..63f27d1 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/service-plans/micro-c2c.js @@ -0,0 +1,79 @@ +const path = require('path') +const logger = require(path.resolve('./lib/helpers/logger')) +const config = require(path.resolve('./config/environment')) +const { CFBinder, APPS_INTERNAL_DOMAIN } = require(path.resolve('./lib/providers/cf-binder')) + +class Microc2c { + // TODO implement me + createProxy () { + console.info('Implement me') + } + deriveParams (params) { + const c2cParams = { + target_app_port: params.target_app_port.toString().trim(), + target_app_route: params.target_app_route.toString().trim(), + target_app_space_name: params.target_app_space_name.toString().trim() + } + if (params.off_c2c_binding) { + c2cParams.off_c2c_binding = true + } + return c2cParams + } + + getUrlFromProxyToApp (param) { + const { appName, baseAppsDomain, targetAppRoute, protocol, port } = param + return `${protocol}://${appName}.${baseAppsDomain}:${port}/${targetAppRoute}` + } + + validate (param) { + let loggerError + if (!param.micro_c2c.target_app_route) { + loggerError = logger.ERR_MISSING_MICRO_C2C_PARAMETER(null, null, '"target_app_route"') + } else if (!param.micro_c2c.target_app_port) { + loggerError = logger.ERR_MISSING_MICRO_C2C_PARAMETER(null, null, '"target_app_port"') + } else if (param.micro) { + loggerError = logger.ERR_NOT_MICRO_PLAN() + } else if (param.micro && param.micro.edgemicro_key) { + loggerError = logger.ERR_NOT_MICRO_CORES_PLAN(null, null, '"edgemicro_key" parameter is invalid') + } else if (param.micro && param.micro.edgemicro_secret) { + loggerError = logger.ERR_NOT_MICRO_CORES_PLAN(null, null, '"edgemicro_secret" parameter is invalid') + } + return loggerError + } + + getOutputParam (param) { + return { + route_service_url: param.proxyURL + } + } + + async runBinding (param) { + const cfbinder = new CFBinder() + try { + const loginResponse = await cfbinder.login() + if (loginResponse.error) { + return loginResponse + } + + const result = await cfbinder.runBinding({ + targetAppRoute: param.micro_c2c.target_app_route, + spaceGuid: param.space_guid, + targetAppPort: param.micro_c2c.target_app_port, + domainForSearch: APPS_INTERNAL_DOMAIN + }) + if (result.error) { + return result + } + return result + } catch (error) { + throw logger.ERR_CF_BRS_FAILED(error) + } + } + + async runPostBinding () { + logger.log.info('Microc2c.runPostBinding.stub') + return Promise.resolve({}) + } +} + +module.exports = Microc2c diff --git a/apigee-cf-service-broker/lib/providers/service-plans/micro-coresident.js b/apigee-cf-service-broker/lib/providers/service-plans/micro-coresident.js new file mode 100644 index 0000000..b5b81b4 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/service-plans/micro-coresident.js @@ -0,0 +1,30 @@ +const path = require('path') +const logger = require(path.resolve('./lib/helpers/logger')) + +class MicroCoresident { + // TODO implement me + createProxy () { + console.info('Implement me') + } + validate (param) { + return this.checkCoresidentPlan(param) + } + + getOutputParam (param) { + const { credentials } = param + + return { credentials, route_service_url: param.proxyURL } + } + + async runBinding (param) { + logger.log.info('MicroCoresident.runBinding.stub') + return Promise.resolve({}) + } + + async runPostBinding() { + logger.log.info('MicroCoresident.runPostBinding.stub') + return Promise.resolve({}) + } +} + +module.exports = MicroCoresident diff --git a/apigee-cf-service-broker/lib/providers/service-plans/micro.js b/apigee-cf-service-broker/lib/providers/service-plans/micro.js new file mode 100644 index 0000000..e74d3a0 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/service-plans/micro.js @@ -0,0 +1,54 @@ +const path = require('path') +const logger = require(path.resolve('./lib/helpers/logger')) + +class Micro { + // TODO implement me + createProxy () { + console.info('Implement me') + } + getUrlFromProxyToApp (param) { + const { appName, baseAppsDomain, targetAppRoute } = param + return `https://${this.name}.${appName}.${baseAppsDomain}/${targetAppRoute}` + } + + deriveParams (params) { + const microParams = { + target_app_port: params.target_app_port.toString().trim(), + target_app_route: params.target_app_route.toString().trim(), + edgemicro_key: params.edgemicro_key.toString().trim(), + edgemicro_secret: params.edgemicro_secret.toString().trim() + } + return microParams + } + + validate (param) { + let result + // micro plan + result = this.checkNonCoresidentPlan(param) + if (result) { + // oops - error + return result + } + + if (!param.micro) { + result = logger.ERR_MICRO_PLAN_REQUIRES_MICRO() + } + return result + } + + getOutputParam (param) { + return { route_service_url: param.proxyURL } + } + + async runBinding () { + logger.log.info('Micro.runBinding.stub') + return Promise.resolve({}) + } + + async runPostBinding() { + logger.log.info('Micro.runPostBinding.stub') + return Promise.resolve({}) + } +} + +module.exports = Micro diff --git a/apigee-cf-service-broker/lib/providers/service-plans/org.js b/apigee-cf-service-broker/lib/providers/service-plans/org.js new file mode 100644 index 0000000..888f030 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/service-plans/org.js @@ -0,0 +1,40 @@ +const path = require('path') +const logger = require(path.resolve('./lib/helpers/logger')) + +class Org { + // TODO implement me + createProxy () { + console.info('Implement me') + } + + validate (param) { + const result = this.checkNonCoresidentPlan(param) + + if (result) { + return result + } + + if (param.micro) { + return logger.ERR_NOT_MICRO_PLAN() + } else if (!param.bind_resource) { + return logger.ERR_BIND_RESOURCE_REQURED() + } + return result + } + + getOutputParam (param) { + return { route_service_url: param.proxyURL } + } + + async runBinding (param) { + logger.log.info('Org.runBinding.stub') + return Promise.resolve({}) + } + + async runPostBinding() { + logger.log.info('Org.runPostBinding.stub') + return Promise.resolve({}) + } +} + +module.exports = Org diff --git a/apigee-cf-service-broker/lib/providers/service-plans/portal.js b/apigee-cf-service-broker/lib/providers/service-plans/portal.js new file mode 100644 index 0000000..ec8e7f0 --- /dev/null +++ b/apigee-cf-service-broker/lib/providers/service-plans/portal.js @@ -0,0 +1,268 @@ +const path = require('path') +const config = require(path.resolve('./config/environment')) +const logger = require(path.resolve('./lib/helpers/logger')) +const ApigeeAuth = require('apigee-auth') +const { API_PRODUCT } = require(path.resolve('./lib/helpers/enums')) +const ApigeePortals = require(path.resolve('./lib/providers/apigee-api/portal')) +const ApigeeSpecs = require(path.resolve('./lib/providers/apigee-api/specs')) +const ApigeeFolders = require(path.resolve('./lib/providers/apigee-api/folders')) +const ApigeeApiProducts = require(path.resolve('./lib/providers/apigee-api/api-product')) +const { CFBinder } = require(path.resolve('./lib/providers/cf-binder')) + +/* + * @description Portal plan class + * + * */ + +class Portal { + // TODO implement me + createProxy () { + console.info('Implement me') + } + /* + * @description Validate input params for binding and proxy creating + * + * @param + * + * @returns + * success: false + * error: error object + * + * */ + validate (param) { + if (param.micro) { + return logger.ERR_NOT_MICRO_PLAN() + } else if (param.micro && param.micro.edgemicro_key) { + return logger.ERR_NOT_MICRO_CORES_PLAN(null, null, '"edgemicro_key" parameter is invalid') + } else if (param.micro && param.micro.edgemicro_secret) { + return logger.ERR_NOT_MICRO_CORES_PLAN(null, null, '"edgemicro_secret" parameter is invalid') + } + if (param.action.proxy) { + if (!param[this.name].target_app_route) { + return logger.ERR_MISSING_MICRO_C2C_PARAMETER( + null, + null, + `Param "target_app_route" is required for plan "${this.name}"` + ) + } else if (!param[this.name].target_app_port) { + return logger.ERR_MISSING_MICRO_C2C_PARAMETER( + null, + null, + `Param "target_app_port" is required for plan "${this.name}"` + ) + } + } else if (param.action.bind) { + if (!param[this.name].target_app_route) { + return logger.ERR_MISSING_MICRO_C2C_PARAMETER( + null, + null, + `Param "target_app_route" is required for plan "${this.name}"` + ) + } + } + + return false + } + + /* + * @description Returns output params for REST caller + * + * @param + * + * @returns + * + * */ + getOutputParam (param) { + return { route_service_url: param.proxyURL } + } + + /* + * @description Runs automation tasks - creates folder, apiProduct, portal, specs for portal for input app + * + * @param + * + * @returns + * + * */ + async runBinding (param) { + const cfbinder = new CFBinder() + try { + const loginResponse = await cfbinder.login() + if (loginResponse.error) { + return loginResponse + } + + const result = await cfbinder.runBinding({ + targetAppRoute: param.portal.target_app_route, + spaceGuid: param.space_guid, + targetAppPort: param.portal.target_app_port, + domainForSearch: config.cf.appsBaseDomain + }) + if (result.error) { + return result + } + return result + } catch (error) { + throw logger.ERR_CF_BRS_FAILED(error) + } + } + + _generateProductName (param) { + return param.portal.target_app_route.replace(/[\.-]+/g, '_') + } + + _generateProductDisplayName (param) { + return `Product for app "${param.portal.target_app_route}"` + } + + _generateProxies (param) { + if (param.action.proxy) { + return [param.proxyname] + } + return [] + } + + _getOpenApiSpecUrl (param) { + let url = `https://${param.portal.target_app_route}.${config.cf.appsBaseDomain}/openapi` + + return url + } + + /* + * @description + * + * @param + * + * @returns + * + * */ + async runPostBinding (param) { + try { + const apiProductParams = { + org: param.org, + name: this._generateProductName(param), + displayName: this._generateProductDisplayName(param), + approvalType: API_PRODUCT.approvalType.auto, + attributes: [ + { + name: 'access', + value: API_PRODUCT.attributes.access.auto + } + ], + description: `Default auto "${this._generateProductName(param)}" description for api`, + environments: ['test', 'prod'], + proxies: this._generateProxies(param), + quota: API_PRODUCT.defaults.quota, + quotaInterval: API_PRODUCT.defaults.quotaInterval, + quotaTimeUnit: API_PRODUCT.defaults.quotaTimeUnit, + } + + let token = {} + if (param.user && param.pass) { + const apigeeAuth = new ApigeeAuth(param.user, param.pass) + + token = await apigeeAuth.getToken() + } else if (param.bearer) { + token = { + token_type: 'Bearer', + access_token: param.bearer + } + } + const apiProductsService = new ApigeeApiProducts() + apiProductsService.setToken(token) + + const portalApiService = new ApigeePortals() + portalApiService.setToken(token) + + const folderService = new ApigeeFolders() + folderService.setToken(token) + + const specsService = new ApigeeSpecs() + specsService.setToken(token) + + const apiProducts = await apiProductsService.getList(param) + let apiProduct = apiProducts.apiProduct.find((a) => { return a.name === apiProductParams.name }) + + if (!apiProduct) { + apiProduct = await apiProductsService.add(apiProductParams) + } + + logger.log.info(`${this.name}.runPostBinding.apiProduct ready`) + + const folderName = folderService.getName(param) + const folders = await folderService.getList(param) + let folder = folders + + if (param.portal.with_docstore) { + // create folder if not exists + const found = folders.content.find((f) => { f.name === folderName }) + + !found + ? folder = await folderService.add({ + org: param.org, + folder: folders.id, + kind: 'Folder', + name: folderName + }) + : null + } + + logger.log.info(`${this.name}.runPostBinding.folder ready`) + + const openApiAppSpecUrl = this._getOpenApiSpecUrl(param) + + logger.log.info(`${this.name}.runPostBinding.openApiUrl ${openApiAppSpecUrl}`) + + const openApiYamlSpec = await specsService.getSpecFromAppAsYaml( + openApiAppSpecUrl, param.proxyURL + ) + + logger.log.info(`${this.name}.runPostBinding.openApiSpec downloaded`) + + const spec = await specsService.add({ + org: param.org, + folderId: folder.id, + name: specsService.generateName(param) + }) + + logger.log.info(`${this.name}.runPostBinding.spec created`) + + await specsService.update({ + org: param.org, + specId: spec.id, + body: openApiYamlSpec + }) + logger.log.info(`${this.name}.runPostBinding.spec filled`) + + const portals = await portalApiService.getList(param) + const portalName = portalApiService.generateName(param) + const portalId = portalApiService.generatePortalId(portalName, param.org) + + let portal = portals.data.find((p) => { return p.id === portalId }) + + if (!portal) { + const name = portalApiService.generateName(param) + + portal = await portalApiService.add({ + orgname: param.org, + name + }) + // add to portal created apiProduct + await portalApiService.addApiProductToPortalWithSpec({ + apiProduct, portal, spec, orgname: param.org + }) + } + logger.log.info(`${this.name}.runPostBinding.portal ready`) + + logger.log.info(`${this.name}.runPostBinding finished`) + + return { apiProduct, portals, portal } + } catch (error) { + // TODO investigate errors and delete all created resources - if some errors occured + return { error: logger.ERR_PORTAL_PLAN_RUN_BINDING(null, error, 500, error.message) } + } + } +} + +module.exports = Portal + diff --git a/apigee-cf-service-broker/manifest.yml b/apigee-cf-service-broker/manifest.yml index a599cfd..6957666 100644 --- a/apigee-cf-service-broker/manifest.yml +++ b/apigee-cf-service-broker/manifest.yml @@ -1,29 +1,23 @@ --- applications: -- name: apigee-cf-service-broker - command: node server.js - buildpacks: - - nodejs_buildpack - env: - APIGEE_CONFIGURATIONS: | - [{"org":"test-org", - "env":"test", - "apigee_dashboard_url":"https://onprem.com/platform/#/", - "apigee_mgmt_api_url":"https://onprem.com/v1", - "apigee_proxy_domain":"onprem.net"}, - {"org":"amer-demo5", - "env":"test", - "apigee_dashboard_url":"https://enterprise.apigee.com/platform/#/", - "apigee_mgmt_api_url":"https://api.enterprise.apigee.com/v1", - "apigee_proxy_domain":"apigee.net"}, - {"org":"cdmo", - "env":"test", - "apigee_dashboard_url":"https://enterprise.apigee.com/platform/#/", - "apigee_mgmt_api_url":"https://api.enterprise.apigee.com/v1", - "apigee_proxy_domain":"apigee.net"}, - {"org":"org-name-here", - "env":"env-name-here", - "apigee_dashboard_url":"https://enterprise.apigee.com/platform/#/", - "apigee_mgmt_api_url":"https://api.enterprise.apigee.com/v1", - "apigee_proxy_domain":"apigee.net"} - ] +- name: apigee-cf-service-broker-test +command: node server.js +buildpack: nodejs_buildpack +env: + APIGEE_CONFIGURATIONS: | + [{"org":"cdmo", + "env":"test", + "apigee_dashboard_url":"https://onprem.com/platform/#/", + "apigee_mgmt_api_url":"https://api.enterprise.apigee.com/v1", + "apigee_proxy_domain":"onprem.net"}, + {"org":"somebody-eval", + "env":"test", + "apigee_dashboard_url":"https://enterprise.apigee.com/platform/#/", + "apigee_mgmt_api_url":"https://api.enterprise.apigee.com/v1", + "apigee_proxy_domain":"apigee.net"} + ] + SECURITY_USER_NAME: admin + SECURITY_USER_PASSWORD: jijkjijijijijjiji== + MICROGATEWAY_APP_NAME: edgemicro-app + BROKER_APP_NAME: apigee-cf-service-broker-test + APPS_BASE_DOMAIN: apps.pcf24.apigee.xyz diff --git a/apigee-cf-service-broker/npm-shrinkwrap.json b/apigee-cf-service-broker/npm-shrinkwrap.json index ea95549..e491856 100644 --- a/apigee-cf-service-broker/npm-shrinkwrap.json +++ b/apigee-cf-service-broker/npm-shrinkwrap.json @@ -1,193 +1,453 @@ { "name": "apigee-cf-service-broker", - "version": "1.1.0", + "version": "3.0.0", + "lockfileVersion": 1, + "requires": true, "dependencies": { + "@types/chai": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", + "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", + "dev": true + }, + "@types/cookiejar": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.1.tgz", + "integrity": "sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw==", + "dev": true + }, + "@types/node": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.4.tgz", + "integrity": "sha512-j8YL2C0fXq7IONwl/Ud5Kt0PeXw22zGERt+HSSnwbKOJVsAGkEz3sFCYwaF9IOuoG1HOtE0vKCj6sXF7Q0+Vaw==", + "dev": true + }, + "@types/superagent": { + "version": "3.8.7", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-3.8.7.tgz", + "integrity": "sha512-9KhCkyXv268A2nZ1Wvu7rQWM+BmdYUVkycFeNnYrUL5Zwu7o8wPQ3wBfW59dDP+wuoxw0ww8YKgTNv8j/cgscA==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "apigee-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/apigee-auth/-/apigee-auth-2.0.1.tgz", + "integrity": "sha512-znytSjEiKfZ89mmT3viHurRG6H2zf4IuvRgZgvr6Y9oDDZ2FBrM9/OaM9sMGVqZc7fICTBRN2v740B8fl/e00w==", + "requires": { + "axios": "^0.18.0", + "otpauth": "^3.2.1" + } + }, + "append-transform": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true, + "requires": { + "default-require-extensions": "^1.0.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "async": { "version": "1.5.2", - "from": "async@>=1.5.0 <2.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz" + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "axios": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz", + "integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "basic-auth": { "version": "1.0.4", - "from": "basic-auth@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz" + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz", + "integrity": "sha1-Awk1sB3nyblKgksp8/zLdQ06UpA=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bluebird": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.0.6.tgz", + "integrity": "sha1-8kiPMleC9m0XSEL0gZkuL6ulbzg=" }, "body-parser": { - "version": "1.12.4", - "from": "body-parser@1.12.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.12.4.tgz", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, "dependencies": { - "bytes": { - "version": "1.0.0", - "from": "bytes@1.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz" - }, - "content-type": { - "version": "1.0.2", - "from": "content-type@>=1.0.2 <1.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz" - }, - "debug": { - "version": "2.2.0", - "from": "debug@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "dependencies": { - "ms": { - "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - } - } - }, - "depd": { - "version": "1.0.1", - "from": "depd@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz" - }, "iconv-lite": { - "version": "0.4.8", - "from": "iconv-lite@0.4.8", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.8.tgz" - }, - "on-finished": { - "version": "2.2.1", - "from": "on-finished@>=2.2.1 <2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.2.1.tgz", - "dependencies": { - "ee-first": { - "version": "1.1.0", - "from": "ee-first@1.1.0", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.0.tgz" - } + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" } }, "qs": { - "version": "2.4.2", - "from": "qs@2.4.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-2.4.2.tgz" - }, - "raw-body": { - "version": "2.0.2", - "from": "raw-body@>=2.0.1 <2.1.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.0.2.tgz", - "dependencies": { - "bytes": { - "version": "2.1.0", - "from": "bytes@2.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz" - } - } - }, - "type-is": { - "version": "1.6.13", - "from": "type-is@>=1.6.13 <1.7.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz", - "dependencies": { - "media-typer": { - "version": "0.3.0", - "from": "media-typer@0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" - }, - "mime-types": { - "version": "2.1.11", - "from": "mime-types@>=2.1.11 <2.2.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz", - "dependencies": { - "mime-db": { - "version": "1.23.0", - "from": "mime-db@>=1.23.0 <1.24.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz" - } - } - } - } + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" } } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "bunyan": { "version": "1.8.1", - "from": "bunyan@>=1.5.1 <2.0.0", "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.1.tgz", + "integrity": "sha1-aMakpQLVYgvJ9y1nNoEMGxiYCX8=", + "requires": { + "dtrace-provider": "~0.6", + "moment": "^2.10.6", + "mv": "~2", + "safe-json-stringify": "~1" + }, "dependencies": { "dtrace-provider": { "version": "0.6.0", - "from": "dtrace-provider@>=0.6.0 <0.7.0", "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz", + "integrity": "sha1-CweNVReTfYcxAUUtkUZzdVe3XlE=", + "optional": true, + "requires": { + "nan": "^2.0.8" + }, "dependencies": { "nan": { "version": "2.4.0", - "from": "nan@>=2.0.8 <3.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz" + "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz", + "integrity": "sha1-+zxZ1F/k7/4hXwuJD4rfbrMtIjI=", + "optional": true } } }, + "moment": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz", + "integrity": "sha1-s1snxH5X7S3ccAU9awe+zbKRdBw=", + "optional": true + }, "mv": { "version": "2.1.1", - "from": "mv@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + }, "dependencies": { "mkdirp": { "version": "0.5.1", - "from": "mkdirp@>=0.5.1 <0.6.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "optional": true, + "requires": { + "minimist": "0.0.8" + }, "dependencies": { "minimist": { "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "optional": true } } }, "ncp": { "version": "2.0.0", - "from": "ncp@>=2.0.0 <2.1.0", - "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true }, "rimraf": { "version": "2.4.5", - "from": "rimraf@>=2.4.0 <2.5.0", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, + "requires": { + "glob": "^6.0.1" + }, "dependencies": { "glob": { "version": "6.0.4", - "from": "glob@>=6.0.1 <7.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "dependencies": { "inflight": { "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "optional": true } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "optional": true }, "minimatch": { "version": "3.0.2", - "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "integrity": "sha1-DzmKcwDqRB6cNIyD2Yq4ydv5xAo=", + "optional": true, + "requires": { + "brace-expansion": "^1.0.0" + }, "dependencies": { "brace-expansion": { "version": "1.1.5", - "from": "brace-expansion@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "integrity": "sha1-9bStV04st8zB64Pm/nm47K33pSY=", + "optional": true, + "requires": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + }, "dependencies": { "balanced-match": { "version": "0.4.1", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", + "integrity": "sha1-GQU+LgdI6ts3nabAnUVc9eEDkzU=", + "optional": true }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "optional": true } } } @@ -195,20 +455,26 @@ }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "optional": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "optional": true } } }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=", + "optional": true } } } @@ -218,125 +484,403 @@ }, "safe-json-stringify": { "version": "1.0.3", - "from": "safe-json-stringify@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.3.tgz" - }, - "moment": { - "version": "2.14.1", - "from": "moment@>=2.10.6 <3.0.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz" + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.3.tgz", + "integrity": "sha1-PLZxdmCghtB8tb2bemh1vPZ70F4=", + "optional": true } } }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, "cfenv": { - "version": "1.0.3", - "from": "cfenv@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/cfenv/-/cfenv-1.0.3.tgz", - "dependencies": { - "js-yaml": { - "version": "3.4.6", - "from": "js-yaml@>=3.4.0 <3.5.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz", - "dependencies": { - "argparse": { - "version": "1.0.7", - "from": "argparse@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.7.tgz", - "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "from": "sprintf-js@>=1.0.2 <1.1.0", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - } - } - }, - "esprima": { - "version": "2.7.2", - "from": "esprima@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" - }, - "inherit": { - "version": "2.2.4", - "from": "inherit@>=2.2.2 <3.0.0", - "resolved": "https://registry.npmjs.org/inherit/-/inherit-2.2.4.tgz" - } - } - }, - "ports": { - "version": "1.1.0", - "from": "ports@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/ports/-/ports-1.1.0.tgz" - }, - "underscore": { - "version": "1.8.3", - "from": "underscore@>=1.8.0 <1.9.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz" - } + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfenv/-/cfenv-1.2.2.tgz", + "integrity": "sha512-fl8xrG9ezqfO7L664lL+/vkqXun0D/xS/0IJ9++IMHLR6SI0If56C/KIHy9oIGb8jq9swHZFdct1MfN/80yYUw==", + "requires": { + "js-yaml": "3.13.x", + "ports": "1.1.x", + "underscore": "1.9.x" } }, "chai": { "version": "3.5.0", - "from": "chai@>=3.4.1 <4.0.0", "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true, + "requires": { + "assertion-error": "^1.0.1", + "deep-eql": "^0.1.3", + "type-detect": "^1.0.0" + }, "dependencies": { "assertion-error": { "version": "1.0.2", - "from": "assertion-error@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true }, "deep-eql": { "version": "0.1.3", - "from": "deep-eql@>=0.1.3 <0.2.0", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "requires": { + "type-detect": "0.1.1" + }, "dependencies": { "type-detect": { "version": "0.1.1", - "from": "type-detect@0.1.1", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz" + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "dev": true } } }, "type-detect": { "version": "1.0.0", - "from": "type-detect@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + } + } + }, + "chai-http": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/chai-http/-/chai-http-4.3.0.tgz", + "integrity": "sha512-zFTxlN7HLMv+7+SPXZdkd5wUlK+KxH6Q7bIEMiEx0FK3zuuMqL7cwICAQ0V1+yYRozBburYuxN1qZstgHpFZQg==", + "dev": true, + "requires": { + "@types/chai": "4", + "@types/superagent": "^3.8.3", + "cookiejar": "^2.1.1", + "is-ip": "^2.0.0", + "methods": "^1.1.2", + "qs": "^6.5.1", + "superagent": "^3.7.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + } } } }, "chai-things": { "version": "0.2.0", - "from": "chai-things@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/chai-things/-/chai-things-0.2.0.tgz" + "resolved": "https://registry.npmjs.org/chai-things/-/chai-things-0.2.0.tgz", + "integrity": "sha1-xVEoN4+bs5nplPAAUhUZhO1uvnA=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "command-line-args": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz", + "integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==", + "requires": { + "array-back": "^3.0.1", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + } + }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true, + "optional": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "core-js": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", + "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "dev": true, + "requires": { + "strip-bom": "^2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "dotenv": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.0.0.tgz", + "integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg==" + }, + "dtrace-provider": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.7.tgz", + "integrity": "sha1-3JObTT4GIM/gwc2APQ0tftBP/QQ=", + "requires": { + "nan": "^2.10.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, "es6-template-strings": { "version": "2.0.0", - "from": "es6-template-strings@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/es6-template-strings/-/es6-template-strings-2.0.0.tgz", + "integrity": "sha1-NcgDZe+7wVEP58qfR1ln1UbBafw=", + "requires": { + "es5-ext": "^0.10.7", + "esniff": "1" + }, "dependencies": { "es5-ext": { "version": "0.10.12", - "from": "es5-ext@>=0.10.7 <0.11.0", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz", + "integrity": "sha1-qoRkHU23a2Krul5F/YBey6sUAEc=", + "requires": { + "es6-iterator": "2", + "es6-symbol": "~3.1" + }, "dependencies": { "es6-iterator": { "version": "2.0.0", - "from": "es6-iterator@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz", + "integrity": "sha1-vZaFZ9YWNeM8C4BydhPJy0sJa6w=", + "requires": { + "d": "^0.1.1", + "es5-ext": "^0.10.7", + "es6-symbol": "3" + }, "dependencies": { "d": { "version": "0.1.1", - "from": "d@>=0.1.1 <0.2.0" + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", + "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=", + "requires": { + "es5-ext": "~0.10.2" + } } } }, "es6-symbol": { "version": "3.1.0", - "from": "es6-symbol@>=3.1.0 <3.2.0", "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz", + "integrity": "sha1-lEgcZV56fK2C66gy2X1UM0ltf/o=", + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.11" + }, "dependencies": { "d": { "version": "0.1.1", - "from": "d@>=0.1.1 <0.2.0" + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", + "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=", + "requires": { + "es5-ext": "~0.10.2" + } } } } @@ -344,776 +888,861 @@ }, "esniff": { "version": "1.0.0", - "from": "esniff@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/esniff/-/esniff-1.0.0.tgz", + "integrity": "sha1-qNW32PvoNrQbBk5DWwnBmYjbFC4=", + "requires": { + "d": "^0.1.1", + "es5-ext": "^0.10.7" + }, "dependencies": { "d": { "version": "0.1.1", - "from": "d@>=0.1.1 <0.2.0" + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", + "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=", + "requires": { + "es5-ext": "~0.10.2" + } } } } } }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, "express": { - "version": "4.14.0", - "from": "express@>=4.13.3 <5.0.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.14.0.tgz", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, "dependencies": { - "accepts": { - "version": "1.3.3", - "from": "accepts@>=1.3.3 <1.4.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", - "dependencies": { - "mime-types": { - "version": "2.1.11", - "from": "mime-types@>=2.1.11 <2.2.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz", - "dependencies": { - "mime-db": { - "version": "1.23.0", - "from": "mime-db@>=1.23.0 <1.24.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz" - } - } - }, - "negotiator": { - "version": "0.6.1", - "from": "negotiator@0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz" - } - } - }, - "array-flatten": { - "version": "1.1.1", - "from": "array-flatten@1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" - }, - "content-disposition": { - "version": "0.5.1", - "from": "content-disposition@0.5.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.1.tgz" - }, - "content-type": { - "version": "1.0.2", - "from": "content-type@>=1.0.2 <1.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz" - }, - "cookie": { - "version": "0.3.1", - "from": "cookie@0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz" - }, - "cookie-signature": { - "version": "1.0.6", - "from": "cookie-signature@1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" - }, - "debug": { - "version": "2.2.0", - "from": "debug@>=2.2.0 <2.3.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "dependencies": { - "ms": { - "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - } - } - }, - "depd": { - "version": "1.1.0", - "from": "depd@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz" - }, - "encodeurl": { - "version": "1.0.1", - "from": "encodeurl@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz" - }, - "escape-html": { - "version": "1.0.3", - "from": "escape-html@>=1.0.3 <1.1.0", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" - }, - "etag": { - "version": "1.7.0", - "from": "etag@>=1.7.0 <1.8.0", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz" - }, - "finalhandler": { - "version": "0.5.0", - "from": "finalhandler@0.5.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz", - "dependencies": { - "statuses": { - "version": "1.3.0", - "from": "statuses@>=1.3.0 <1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.0.tgz" - }, - "unpipe": { - "version": "1.0.0", - "from": "unpipe@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" - } - } - }, - "fresh": { - "version": "0.3.0", - "from": "fresh@0.3.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz" - }, - "merge-descriptors": { - "version": "1.0.1", - "from": "merge-descriptors@1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" - }, - "methods": { - "version": "1.1.2", - "from": "methods@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" - }, - "on-finished": { - "version": "2.3.0", - "from": "on-finished@>=2.3.0 <2.4.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "dependencies": { - "ee-first": { - "version": "1.1.1", - "from": "ee-first@1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" - } - } - }, - "parseurl": { - "version": "1.3.1", - "from": "parseurl@>=1.3.1 <1.4.0", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz" - }, - "path-to-regexp": { - "version": "0.1.7", - "from": "path-to-regexp@0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" - }, - "proxy-addr": { - "version": "1.1.2", - "from": "proxy-addr@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.2.tgz", - "dependencies": { - "forwarded": { - "version": "0.1.0", - "from": "forwarded@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz" - }, - "ipaddr.js": { - "version": "1.1.1", - "from": "ipaddr.js@1.1.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.1.1.tgz" - } - } - }, "qs": { - "version": "6.2.0", - "from": "qs@>=6.2.0 <6.3.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz" - }, - "range-parser": { - "version": "1.2.0", - "from": "range-parser@>=1.2.0 <1.3.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz" - }, - "send": { - "version": "0.14.1", - "from": "send@0.14.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.14.1.tgz", - "dependencies": { - "destroy": { - "version": "1.0.4", - "from": "destroy@>=1.0.4 <1.1.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz" - }, - "http-errors": { - "version": "1.5.0", - "from": "http-errors@>=1.5.0 <1.6.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.0.tgz", - "dependencies": { - "inherits": { - "version": "2.0.1", - "from": "inherits@2.0.1" - }, - "setprototypeof": { - "version": "1.0.1", - "from": "setprototypeof@1.0.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.1.tgz" - } - } - }, - "mime": { - "version": "1.3.4", - "from": "mime@1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" - }, - "ms": { - "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - }, - "statuses": { - "version": "1.3.0", - "from": "statuses@>=1.3.0 <1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.0.tgz" - } - } - }, - "serve-static": { - "version": "1.11.1", - "from": "serve-static@>=1.11.1 <1.12.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.1.tgz" - }, - "type-is": { - "version": "1.6.13", - "from": "type-is@>=1.6.13 <1.7.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.13.tgz", - "dependencies": { - "media-typer": { - "version": "0.3.0", - "from": "media-typer@0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" - }, - "mime-types": { - "version": "2.1.11", - "from": "mime-types@>=2.1.11 <2.2.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz", - "dependencies": { - "mime-db": { - "version": "1.23.0", - "from": "mime-db@>=1.23.0 <1.24.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz" - } - } - } - } - }, - "utils-merge": { - "version": "1.0.0", - "from": "utils-merge@1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz" - }, - "vary": { - "version": "1.1.0", - "from": "vary@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.0.tgz" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" } } }, "express-jsonschema": { "version": "1.1.0", - "from": "express-jsonschema@>=1.1.0 <2.0.0", "resolved": "https://registry.npmjs.org/express-jsonschema/-/express-jsonschema-1.1.0.tgz", + "integrity": "sha1-LTbqHhUSdxnh5qlaFut9Xmj30P0=", + "requires": { + "jsonschema": "^1.0.0" + }, "dependencies": { "jsonschema": { "version": "1.1.0", - "from": "jsonschema@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.1.0.tgz" + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.1.0.tgz", + "integrity": "sha1-A5zCGe1SSwbnHa8SymDQJjn68po=" } } }, - "istanbul": { - "version": "0.4.4", - "from": "istanbul@0.4.4", - "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.4.tgz", + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fileset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz", + "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=", + "dev": true, + "requires": { + "glob": "^7.0.3", + "minimatch": "^3.0.3" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "requires": { + "array-back": "^3.0.1" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + }, "dependencies": { - "abbrev": { - "version": "1.0.9", - "from": "abbrev@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" - }, - "escodegen": { - "version": "1.8.1", - "from": "escodegen@>=1.8.0 <1.9.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", - "dependencies": { - "estraverse": { - "version": "1.9.3", - "from": "estraverse@>=1.9.1 <2.0.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz" - }, - "esutils": { - "version": "2.0.2", - "from": "esutils@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz" - }, - "optionator": { - "version": "0.8.1", - "from": "optionator@>=0.8.1 <0.9.0", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.1.tgz", - "dependencies": { - "prelude-ls": { - "version": "1.1.2", - "from": "prelude-ls@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" - }, - "deep-is": { - "version": "0.1.3", - "from": "deep-is@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" - }, - "type-check": { - "version": "0.3.2", - "from": "type-check@>=0.3.2 <0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" - }, - "levn": { - "version": "0.3.0", - "from": "levn@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" - }, - "fast-levenshtein": { - "version": "1.1.4", - "from": "fast-levenshtein@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz" - } - } - }, - "source-map": { - "version": "0.2.0", - "from": "source-map@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", - "dependencies": { - "amdefine": { - "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" - } - } - } - } - }, - "esprima": { - "version": "2.7.2", - "from": "esprima@>=2.7.0 <2.8.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" - }, - "fileset": { - "version": "0.2.1", - "from": "fileset@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz", - "dependencies": { - "minimatch": { - "version": "2.0.10", - "from": "minimatch@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "dependencies": { - "brace-expansion": { - "version": "1.1.6", - "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz", - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz" - }, - "concat-map": { - "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - } - } - } - } - }, - "glob": { - "version": "5.0.15", - "from": "glob@>=5.0.0 <6.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "dependencies": { - "inflight": { - "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", - "dependencies": { - "wrappy": { - "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - } - } - }, - "inherits": { - "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" - }, - "path-is-absolute": { - "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" - } - } - } - } - }, - "handlebars": { - "version": "4.0.5", - "from": "handlebars@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz", - "dependencies": { - "optimist": { - "version": "0.6.1", - "from": "optimist@>=0.6.1 <0.7.0", - "dependencies": { - "wordwrap": { - "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" - }, - "minimist": { - "version": "0.0.10", - "from": "minimist@>=0.0.1 <0.1.0" - } - } - }, - "source-map": { - "version": "0.4.4", - "from": "source-map@>=0.4.4 <0.5.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "dependencies": { - "amdefine": { - "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" - } - } - }, - "uglify-js": { - "version": "2.7.0", - "from": "uglify-js@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.0.tgz", - "dependencies": { - "async": { - "version": "0.2.10", - "from": "async@>=0.2.6 <0.3.0", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" - }, - "source-map": { - "version": "0.5.6", - "from": "source-map@>=0.5.1 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" - }, - "uglify-to-browserify": { - "version": "1.0.2", - "from": "uglify-to-browserify@>=1.0.0 <1.1.0" - }, - "yargs": { - "version": "3.10.0", - "from": "yargs@>=3.10.0 <3.11.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "dependencies": { - "camelcase": { - "version": "1.2.1", - "from": "camelcase@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" - }, - "cliui": { - "version": "2.1.0", - "from": "cliui@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "dependencies": { - "center-align": { - "version": "0.1.3", - "from": "center-align@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "dependencies": { - "align-text": { - "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "dependencies": { - "kind-of": { - "version": "3.0.4", - "from": "kind-of@>=3.0.2 <4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz", - "dependencies": { - "is-buffer": { - "version": "1.1.4", - "from": "is-buffer@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz" - } - } - }, - "longest": { - "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" - }, - "repeat-string": { - "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" - } - } - }, - "lazy-cache": { - "version": "1.0.4", - "from": "lazy-cache@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" - } - } - }, - "right-align": { - "version": "0.1.3", - "from": "right-align@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "dependencies": { - "align-text": { - "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "dependencies": { - "kind-of": { - "version": "3.0.4", - "from": "kind-of@>=3.0.2 <4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.4.tgz", - "dependencies": { - "is-buffer": { - "version": "1.1.4", - "from": "is-buffer@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz" - } - } - }, - "longest": { - "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" - }, - "repeat-string": { - "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" - } - } - } - } - }, - "wordwrap": { - "version": "0.0.2", - "from": "wordwrap@0.0.2" - } - } - }, - "decamelize": { - "version": "1.2.0", - "from": "decamelize@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" - }, - "window-size": { - "version": "0.1.0", - "from": "window-size@0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" - } - } - } - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "dependencies": { - "minimist": { - "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - } - } - }, - "nopt": { - "version": "3.0.6", - "from": "nopt@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz" - }, - "once": { - "version": "1.3.3", - "from": "once@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "dependencies": { - "wrappy": { - "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - } + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" } - }, - "resolve": { - "version": "1.1.7", - "from": "resolve@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" - }, - "supports-color": { - "version": "3.1.2", - "from": "supports-color@>=3.1.0 <4.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", - "dependencies": { - "has-flag": { - "version": "1.0.0", - "from": "has-flag@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz" - } + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", + "dev": true + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "handlebars": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", + "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", + "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" + }, + "is-buffer": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", + "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", + "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "dev": true, + "requires": { + "ip-regex": "^2.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "istanbul": { + "version": "1.1.0-alpha.1", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-1.1.0-alpha.1.tgz", + "integrity": "sha1-eBeVZWAYohdMX2DzZ+5dNhy1e3c=", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "istanbul-api": "^1.1.0-alpha", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + } + }, + "istanbul-api": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", + "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", + "dev": true, + "requires": { + "async": "^2.1.4", + "fileset": "^2.0.2", + "istanbul-lib-coverage": "^1.2.1", + "istanbul-lib-hook": "^1.2.2", + "istanbul-lib-instrument": "^1.10.2", + "istanbul-lib-report": "^1.1.5", + "istanbul-lib-source-maps": "^1.2.6", + "istanbul-reports": "^1.5.1", + "js-yaml": "^3.7.0", + "mkdirp": "^0.5.1", + "once": "^1.4.0" + }, + "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" } }, - "which": { - "version": "1.2.10", - "from": "which@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.10.tgz", - "dependencies": { - "isexe": { - "version": "1.1.2", - "from": "isexe@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz" - } + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" } - }, - "wordwrap": { - "version": "1.0.0", - "from": "wordwrap@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" } } }, "istanbul-cobertura-badger": { "version": "1.2.1", - "from": "istanbul-cobertura-badger@>=1.2.1 <2.0.0", "resolved": "https://registry.npmjs.org/istanbul-cobertura-badger/-/istanbul-cobertura-badger-1.2.1.tgz", + "integrity": "sha1-aZzAcCuxQeDCQhaG31z8NAc+1JY=", + "dev": true, + "requires": { + "commander": "^2.8.1", + "xml-splitter": "~1.2.1", + "xtend": "~4.0.1" + }, "dependencies": { "commander": { "version": "2.9.0", - "from": "commander@>=2.8.1 <3.0.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + }, "dependencies": { "graceful-readlink": { "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true } } }, "xml-splitter": { "version": "1.2.1", - "from": "xml-splitter@>=1.2.1 <1.3.0", "resolved": "https://registry.npmjs.org/xml-splitter/-/xml-splitter-1.2.1.tgz", + "integrity": "sha1-s/0oyIBj5RCrajXtCUMpJAnEyBI=", + "dev": true, + "requires": { + "clone": "~0.1.11", + "sax": "~0.5.5" + }, "dependencies": { - "sax": { - "version": "0.5.8", - "from": "sax@>=0.5.5 <0.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz" - }, "clone": { "version": "0.1.19", - "from": "clone@>=0.1.11 <0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.1.19.tgz" + "resolved": "https://registry.npmjs.org/clone/-/clone-0.1.19.tgz", + "integrity": "sha1-YT+2hjmyaklKxTJT4Vsaa9iK2oU=", + "dev": true + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", + "dev": true } } }, "xtend": { "version": "4.0.1", - "from": "xtend@>=4.0.1 <4.1.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true } } }, - "js-yaml": { - "version": "3.6.1", - "from": "js-yaml@>=3.5.3 <4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", + "istanbul-lib-coverage": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", + "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", + "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", + "dev": true, + "requires": { + "append-transform": "^0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", + "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", + "dev": true, + "requires": { + "babel-generator": "^6.18.0", + "babel-template": "^6.16.0", + "babel-traverse": "^6.18.0", + "babel-types": "^6.18.0", + "babylon": "^6.18.0", + "istanbul-lib-coverage": "^1.2.1", + "semver": "^5.3.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", + "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "path-parse": "^1.0.5", + "supports-color": "^3.1.2" + }, "dependencies": { - "argparse": { - "version": "1.0.7", - "from": "argparse@>=1.0.7 <2.0.0", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.7.tgz", - "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "from": "sprintf-js@>=1.0.2 <1.1.0", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - } + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", + "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "istanbul-lib-coverage": "^1.2.1", + "mkdirp": "^0.5.1", + "rimraf": "^2.6.1", + "source-map": "^0.5.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" } }, - "esprima": { - "version": "2.7.2", - "from": "esprima@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", + "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", + "dev": true, + "requires": { + "handlebars": "^4.0.3" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json-to-pretty-yaml": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz", + "integrity": "sha1-9M0L0KXo/h3yWq9boRiwmf2ZLVs=", + "requires": { + "remedial": "^1.0.7", + "remove-trailing-spaces": "^1.0.6" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" } } }, "jszip": { "version": "2.6.1", - "from": "jszip@2.6.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-2.6.1.tgz", + "integrity": "sha1-uI86ey5noqBIFSmCx6N1bZxIKPA=", + "requires": { + "pako": "~1.0.2" + }, "dependencies": { "pako": { "version": "1.0.3", - "from": "pako@>=1.0.2 <1.1.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.3.tgz" + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.3.tgz", + "integrity": "sha1-X1FbDGci4ZgpIK6ABerLC3ynPM8=" } } }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "requires": { + "mime-db": "1.40.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, "mocha": { "version": "2.5.3", - "from": "mocha@>=2.4.5 <3.0.0", "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", + "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", + "dev": true, + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.11", + "growl": "1.9.2", + "jade": "0.26.3", + "mkdirp": "0.5.1", + "supports-color": "1.2.0", + "to-iso-string": "0.0.2" + }, "dependencies": { "commander": { "version": "2.3.0", - "from": "commander@2.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz" + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", + "dev": true }, "debug": { "version": "2.2.0", - "from": "debug@2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + }, "dependencies": { "ms": { "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true } } }, "diff": { "version": "1.4.0", - "from": "diff@1.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz" + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true }, "escape-string-regexp": { "version": "1.0.2", - "from": "escape-string-regexp@1.0.2", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "dev": true }, "glob": { "version": "3.2.11", - "from": "glob@3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "dev": true, + "requires": { + "inherits": "2", + "minimatch": "0.3" + }, "dependencies": { "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "minimatch": { "version": "0.3.0", - "from": "minimatch@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, "dependencies": { "lru-cache": { "version": "2.7.3", - "from": "lru-cache@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz" + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true }, "sigmund": { "version": "1.0.1", - "from": "sigmund@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true } } } @@ -1121,117 +1750,175 @@ }, "growl": { "version": "1.9.2", - "from": "growl@1.9.2", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz" + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true }, "jade": { "version": "0.26.3", - "from": "jade@0.26.3", "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", + "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", + "dev": true, + "requires": { + "commander": "0.6.1", + "mkdirp": "0.3.0" + }, "dependencies": { "commander": { "version": "0.6.1", - "from": "commander@0.6.1" + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true }, "mkdirp": { "version": "0.3.0", - "from": "mkdirp@0.3.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz" + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "dev": true } } }, "mkdirp": { "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, "dependencies": { "minimist": { "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true } } }, "supports-color": { "version": "1.2.0", - "from": "supports-color@1.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz" + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", + "dev": true }, "to-iso-string": { "version": "0.0.2", - "from": "to-iso-string@0.0.2", - "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz" + "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", + "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", + "dev": true } } }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, "nconf": { "version": "0.8.4", - "from": "nconf@>=0.8.2 <0.9.0", "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.8.4.tgz", + "integrity": "sha1-lQIjT3rWI4yrf5LXwGjCBDTT/5M=", + "requires": { + "async": "^1.4.0", + "ini": "^1.3.0", + "secure-keys": "^1.0.0", + "yargs": "^3.19.0" + }, "dependencies": { "ini": { "version": "1.3.4", - "from": "ini@>=1.3.0 <2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz" + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=" }, "secure-keys": { "version": "1.0.0", - "from": "secure-keys@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz", + "integrity": "sha1-8MgtmKOxOah3aogIBQuCRDEIf8o=" }, "yargs": { "version": "3.32.0", - "from": "yargs@>=3.19.0 <4.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "requires": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + }, "dependencies": { "camelcase": { "version": "2.1.1", - "from": "camelcase@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz" + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" }, "cliui": { "version": "3.2.0", - "from": "cliui@>=3.0.3 <4.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, "dependencies": { "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + }, "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=" } } }, "wrap-ansi": { "version": "2.0.0", - "from": "wrap-ansi@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.0.0.tgz", + "integrity": "sha1-fTD4+HP5pbvDpk2ryNF34HGuQm8=", + "requires": { + "string-width": "^1.0.1" + } } } }, "decamelize": { "version": "1.2.0", - "from": "decamelize@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "os-locale": { "version": "1.4.0", - "from": "os-locale@>=1.4.0 <2.0.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + }, "dependencies": { "lcid": { "version": "1.0.0", - "from": "lcid@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + }, "dependencies": { "invert-kv": { "version": "1.0.0", - "from": "invert-kv@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" } } } @@ -1239,42 +1926,56 @@ }, "string-width": { "version": "1.0.1", - "from": "string-width@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz", + "integrity": "sha1-ySEptvHX9SrPmvQkom44ZKBc6wo=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, "dependencies": { "code-point-at": { "version": "1.0.0", - "from": "code-point-at@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz", + "integrity": "sha1-9psZLT99keOC5Lcb3bd4eGGasMY=", + "requires": { + "number-is-nan": "^1.0.0" + }, "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=" } } }, "is-fullwidth-code-point": { "version": "1.0.0", - "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + }, "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=" } } }, "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + }, "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=" } } } @@ -1282,552 +1983,691 @@ }, "window-size": { "version": "0.1.4", - "from": "window-size@>=0.1.4 <0.2.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz" + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=" }, "y18n": { "version": "3.2.1", - "from": "y18n@>=3.2.0 <4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz" + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" } } } } }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, "nock": { - "version": "7.7.3", - "from": "nock@>=7.0.2 <8.0.0", - "resolved": "https://registry.npmjs.org/nock/-/nock-7.7.3.tgz", + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/nock/-/nock-10.0.6.tgz", + "integrity": "sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w==", + "dev": true, + "requires": { + "chai": "^4.1.2", + "debug": "^4.1.0", + "deep-equal": "^1.0.0", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.5", + "mkdirp": "^0.5.0", + "propagate": "^1.0.0", + "qs": "^6.5.1", + "semver": "^5.5.0" + }, "dependencies": { - "debug": { - "version": "2.2.0", - "from": "debug@>=2.2.0 <3.0.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "dependencies": { - "ms": { - "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - } + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" } }, - "deep-equal": { - "version": "1.0.1", - "from": "deep-equal@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz" - }, - "json-stringify-safe": { - "version": "5.0.1", - "from": "json-stringify-safe@>=5.0.1 <6.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - }, - "lodash": { - "version": "3.10.1", - "from": "lodash@>=3.10.1 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" - }, - "mkdirp": { - "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "dependencies": { - "minimist": { - "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - } + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" } }, - "propagate": { - "version": "0.3.1", - "from": "propagate@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-0.3.1.tgz" - }, - "qs": { - "version": "6.2.0", - "from": "qs@>=6.0.2 <7.0.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz" + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, - "request": { - "version": "2.74.0", - "from": "request@2.74.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.74.0.tgz", + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, "dependencies": { - "aws-sign2": { - "version": "0.6.0", - "from": "aws-sign2@>=0.6.0 <0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz" - }, - "aws4": { - "version": "1.4.1", - "from": "aws4@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.4.1.tgz" - }, - "bl": { - "version": "1.1.2", - "from": "bl@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "from": "readable-stream@>=2.0.5 <2.1.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - }, - "inherits": { - "version": "2.0.1", - "from": "inherits@>=2.0.1 <2.1.0", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" - }, - "isarray": { - "version": "1.0.0", - "from": "isarray@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - }, - "process-nextick-args": { - "version": "1.0.7", - "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" - }, - "string_decoder": { - "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - }, - "util-deprecate": { - "version": "1.0.2", - "from": "util-deprecate@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - } - } - } - } - }, - "caseless": { - "version": "0.11.0", - "from": "caseless@>=0.11.0 <0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" - }, - "combined-stream": { - "version": "1.0.5", - "from": "combined-stream@>=1.0.5 <1.1.0", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "dependencies": { - "delayed-stream": { - "version": "1.0.0", - "from": "delayed-stream@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - } - } - }, - "extend": { - "version": "3.0.0", - "from": "extend@>=3.0.0 <3.1.0", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" - }, - "forever-agent": { - "version": "0.6.1", - "from": "forever-agent@>=0.6.1 <0.7.0", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" - }, - "form-data": { - "version": "1.0.0-rc4", - "from": "form-data@>=1.0.0-rc4 <1.1.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz" - }, - "har-validator": { - "version": "2.0.6", - "from": "har-validator@>=2.0.6 <2.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "dependencies": { - "chalk": { - "version": "1.1.3", - "from": "chalk@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "from": "ansi-styles@>=2.2.1 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" - }, - "escape-string-regexp": { - "version": "1.0.5", - "from": "escape-string-regexp@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - }, - "has-ansi": { - "version": "2.0.0", - "from": "has-ansi@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "dependencies": { - "ansi-regex": { - "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "dependencies": { - "ansi-regex": { - "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" - } - } - }, - "supports-color": { - "version": "2.0.0", - "from": "supports-color@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" - } - } - }, - "commander": { - "version": "2.9.0", - "from": "commander@>=2.9.0 <3.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "dependencies": { - "graceful-readlink": { - "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" - } - } - }, - "is-my-json-valid": { - "version": "2.13.1", - "from": "is-my-json-valid@>=2.12.4 <3.0.0", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz", - "dependencies": { - "generate-function": { - "version": "2.0.0", - "from": "generate-function@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" - }, - "generate-object-property": { - "version": "1.2.0", - "from": "generate-object-property@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "dependencies": { - "is-property": { - "version": "1.0.2", - "from": "is-property@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" - } - } - }, - "jsonpointer": { - "version": "2.0.0", - "from": "jsonpointer@2.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" - }, - "xtend": { - "version": "4.0.1", - "from": "xtend@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" - } - } - }, - "pinkie-promise": { - "version": "2.0.1", - "from": "pinkie-promise@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "dependencies": { - "pinkie": { - "version": "2.0.4", - "from": "pinkie@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" - } - } - } - } - }, - "hawk": { - "version": "3.1.3", - "from": "hawk@>=3.1.3 <3.2.0", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "dependencies": { - "hoek": { - "version": "2.16.3", - "from": "hoek@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" - }, - "boom": { - "version": "2.10.1", - "from": "boom@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" - }, - "cryptiles": { - "version": "2.0.5", - "from": "cryptiles@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz" - }, - "sntp": { - "version": "1.0.9", - "from": "sntp@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" - } - } - }, - "http-signature": { - "version": "1.1.1", - "from": "http-signature@>=1.1.0 <1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "dependencies": { - "assert-plus": { - "version": "0.2.0", - "from": "assert-plus@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz" - }, - "jsprim": { - "version": "1.3.0", - "from": "jsprim@>=1.2.2 <2.0.0", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.0.tgz", - "dependencies": { - "extsprintf": { - "version": "1.0.2", - "from": "extsprintf@1.0.2", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" - }, - "json-schema": { - "version": "0.2.2", - "from": "json-schema@0.2.2", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz" - }, - "verror": { - "version": "1.3.6", - "from": "verror@1.3.6", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz" - } - } - }, - "sshpk": { - "version": "1.9.2", - "from": "sshpk@>=1.7.0 <2.0.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.9.2.tgz", - "dependencies": { - "asn1": { - "version": "0.2.3", - "from": "asn1@>=0.2.3 <0.3.0", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz" - }, - "assert-plus": { - "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" - }, - "dashdash": { - "version": "1.14.0", - "from": "dashdash@>=1.12.0 <2.0.0", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz" - }, - "getpass": { - "version": "0.1.6", - "from": "getpass@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz" - }, - "jsbn": { - "version": "0.1.0", - "from": "jsbn@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" - }, - "tweetnacl": { - "version": "0.13.3", - "from": "tweetnacl@>=0.13.0 <0.14.0", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz" - }, - "jodid25519": { - "version": "1.0.2", - "from": "jodid25519@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz" - }, - "ecc-jsbn": { - "version": "0.1.1", - "from": "ecc-jsbn@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz" - } - } - } + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "otpauth": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/otpauth/-/otpauth-3.2.7.tgz", + "integrity": "sha512-Eard+0ljOWx0mo6F0PeDLk3Ek3hYF1ahnix79ll4X+x0jiBRdh/gfN0xhcFl5IdqZZmpq94w13lbBXXAOZiIvQ==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "ports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ports/-/ports-1.1.0.tgz", + "integrity": "sha1-twGqKF6V2ujJbNonUhdySh9/bGA=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "propagate": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz", + "integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=", + "dev": true + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "psl": { + "version": "1.1.32", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.32.tgz", + "integrity": "sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" } - }, - "is-typedarray": { + } + } + }, + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "remedial": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/remedial/-/remedial-1.0.8.tgz", + "integrity": "sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==" + }, + "remove-trailing-spaces": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/remove-trailing-spaces/-/remove-trailing-spaces-1.0.7.tgz", + "integrity": "sha512-wjM17CJ2kk0SgoGyJ7ZMzRRCuTq+V8YhMwpZ5XEWX0uaked2OUq6utvHXGNBQrfkUzUUABFMyxlKn+85hMv4dg==" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "assert-plus": { "version": "1.0.0", - "from": "is-typedarray@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, - "isstream": { - "version": "0.1.2", - "from": "isstream@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, - "json-stringify-safe": { - "version": "5.0.1", - "from": "json-stringify-safe@>=5.0.1 <5.1.0", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } }, - "mime-types": { - "version": "2.1.11", - "from": "mime-types@>=2.1.7 <2.2.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz", - "dependencies": { - "mime-db": { - "version": "1.23.0", - "from": "mime-db@>=1.23.0 <1.24.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz" - } + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" } }, - "node-uuid": { - "version": "1.4.7", - "from": "node-uuid@>=1.4.7 <1.5.0", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } }, "oauth-sign": { - "version": "0.8.2", - "from": "oauth-sign@>=0.8.1 <0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, - "qs": { - "version": "6.2.1", - "from": "qs@>=6.2.0 <6.3.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz" + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, - "stringstream": { - "version": "0.0.5", - "from": "stringstream@>=0.0.4 <0.1.0", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "tough-cookie": { - "version": "2.3.1", - "from": "tough-cookie@>=2.3.0 <2.4.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.1.tgz" + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } }, "tunnel-agent": { - "version": "0.4.3", - "from": "tunnel-agent@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } } } }, + "restler": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/restler/-/restler-3.4.0.tgz", + "integrity": "sha1-dB7As9FrlJ/uooE9DDxoUp6IjZs=", + "requires": { + "iconv-lite": "0.2.11", + "qs": "1.2.0", + "xml2js": "0.4.0", + "yaml": "0.2.3" + }, + "dependencies": { + "qs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-1.2.0.tgz", + "integrity": "sha1-7Qeb4oaCFH5v2aNMwrDB4OxkU+4=" + } + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=" + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, "should": { "version": "8.4.0", - "from": "should@>=8.2.1 <9.0.0", "resolved": "https://registry.npmjs.org/should/-/should-8.4.0.tgz", + "integrity": "sha1-XmCInT5kS73Tl6MM00+tKPz5C8A=", + "dev": true, + "requires": { + "should-equal": "0.8.0", + "should-format": "0.3.2", + "should-type": "0.2.0" + }, "dependencies": { "should-equal": { "version": "0.8.0", - "from": "should-equal@0.8.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-0.8.0.tgz" + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-0.8.0.tgz", + "integrity": "sha1-o/BXMv9FusG3ukEvhAiFaBlkEpk=", + "dev": true, + "requires": { + "should-type": "0.2.0" + } }, "should-format": { "version": "0.3.2", - "from": "should-format@0.3.2", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-0.3.2.tgz" + "resolved": "https://registry.npmjs.org/should-format/-/should-format-0.3.2.tgz", + "integrity": "sha1-pZgx4Bot3uFJkRvHFIvlyAMZ4f8=", + "dev": true, + "requires": { + "should-type": "0.2.0" + } }, "should-type": { "version": "0.2.0", - "from": "should-type@0.2.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-0.2.0.tgz" + "resolved": "https://registry.npmjs.org/should-type/-/should-type-0.2.0.tgz", + "integrity": "sha1-ZwfvlVKdmJ3MCY/gdTqx+RNrt/Y=", + "dev": true + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" } } }, "standard": { "version": "5.4.1", - "from": "standard@>=5.4.1 <6.0.0", "resolved": "https://registry.npmjs.org/standard/-/standard-5.4.1.tgz", + "integrity": "sha1-LwE5ErJ5Tdswu6qJ3BP7OpkMxys=", + "dev": true, + "requires": { + "eslint-config-standard": "4.4.0", + "eslint-config-standard-react": "1.2.1", + "eslint-plugin-react": "^3.9.0", + "eslint-plugin-standard": "^1.3.1", + "standard-engine": "^2.0.4", + "standard-format": "^1.3.3" + }, "dependencies": { "eslint-config-standard": { "version": "4.4.0", - "from": "eslint-config-standard@4.4.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-4.4.0.tgz" + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-4.4.0.tgz", + "integrity": "sha1-wSl0nhmZ4M+GEHeyddnFHc2XzXU=", + "dev": true }, "eslint-config-standard-react": { "version": "1.2.1", - "from": "eslint-config-standard-react@1.2.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard-react/-/eslint-config-standard-react-1.2.1.tgz" + "resolved": "https://registry.npmjs.org/eslint-config-standard-react/-/eslint-config-standard-react-1.2.1.tgz", + "integrity": "sha1-7QRf2yKzoP4LsL1EnPO/vq7etbM=", + "dev": true }, "eslint-plugin-react": { "version": "3.16.1", - "from": "eslint-plugin-react@>=3.9.0 <4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-3.16.1.tgz" + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-3.16.1.tgz", + "integrity": "sha1-Ji2Wt318SkKvgJpzwOUnpYYSKTw=", + "dev": true }, "eslint-plugin-standard": { "version": "1.3.3", - "from": "eslint-plugin-standard@>=1.3.1 <2.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-1.3.3.tgz" + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-1.3.3.tgz", + "integrity": "sha1-owhUUVI0MedvQJxwy4+U4yvw7H8=", + "dev": true }, "standard-engine": { "version": "2.2.5", - "from": "standard-engine@>=2.0.4 <3.0.0", "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-2.2.5.tgz", + "integrity": "sha1-ornUQZ9kiiIbjReCP7dFQG83w04=", + "dev": true, + "requires": { + "defaults": "^1.0.2", + "deglob": "^1.0.0", + "dezalgo": "^1.0.2", + "eslint": "1.9.0", + "find-root": "^0.1.1", + "get-stdin": "^4.0.1", + "minimist": "^1.1.0", + "multiline": "^1.0.2", + "pkg-config": "^1.0.1", + "xtend": "^4.0.0" + }, "dependencies": { "defaults": { "version": "1.0.3", - "from": "defaults@>=1.0.2 <2.0.0", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + }, "dependencies": { "clone": { "version": "1.0.2", - "from": "clone@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", + "dev": true } } }, "deglob": { "version": "1.1.1", - "from": "deglob@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/deglob/-/deglob-1.1.1.tgz", + "integrity": "sha1-0nDNWtcBv4tLhZR+RtAT/9e9Qio=", + "dev": true, + "requires": { + "find-root": "^0.1.1", + "glob": "^6.0.4", + "ignore": "^3.0.9", + "pkg-config": "^1.1.0", + "run-parallel": "^1.1.2", + "uniq": "^1.0.1", + "xtend": "^4.0.0" + }, "dependencies": { "glob": { "version": "6.0.4", - "from": "glob@>=6.0.4 <7.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "dependencies": { "inflight": { "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "minimatch": { "version": "3.0.2", - "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "integrity": "sha1-DzmKcwDqRB6cNIyD2Yq4ydv5xAo=", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + }, "dependencies": { "brace-expansion": { "version": "1.1.5", - "from": "brace-expansion@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "integrity": "sha1-9bStV04st8zB64Pm/nm47K33pSY=", + "dev": true, + "requires": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + }, "dependencies": { "balanced-match": { "version": "0.4.1", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", + "integrity": "sha1-GQU+LgdI6ts3nabAnUVc9eEDkzU=", + "dev": true }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true } } } @@ -1835,259 +2675,455 @@ }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=", + "dev": true } } }, "ignore": { "version": "3.1.3", - "from": "ignore@>=3.0.9 <4.0.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.1.3.tgz" + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.1.3.tgz", + "integrity": "sha1-nokMBlJRkRWulCfaR1Fr1U0daZk=", + "dev": true }, "run-parallel": { "version": "1.1.6", - "from": "run-parallel@>=1.1.2 <2.0.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.6.tgz" + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.6.tgz", + "integrity": "sha1-KQA8miFj4B4tLfyQV18sbB1hoDk=", + "dev": true }, "uniq": { "version": "1.0.1", - "from": "uniq@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true } } }, "dezalgo": { "version": "1.0.3", - "from": "dezalgo@>=1.0.2 <2.0.0", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + }, "dependencies": { "asap": { "version": "2.0.4", - "from": "asap@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.4.tgz" + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.4.tgz", + "integrity": "sha1-s5G/f2v7xlcGAi/sj0nEsH/s9Yk=", + "dev": true }, "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "eslint": { "version": "1.9.0", - "from": "eslint@1.9.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-1.9.0.tgz", + "integrity": "sha1-p1qvB+KGUHcu0OcNqizggwebZRQ=", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "concat-stream": "^1.4.6", + "debug": "^2.1.1", + "doctrine": "^0.7.0", + "escape-string-regexp": "^1.0.2", + "escope": "^3.2.0", + "espree": "^2.2.4", + "estraverse": "^4.1.1", + "estraverse-fb": "^1.3.1", + "esutils": "^2.0.2", + "file-entry-cache": "^1.1.1", + "glob": "^5.0.14", + "globals": "^8.11.0", + "handlebars": "^4.0.0", + "inquirer": "^0.11.0", + "is-my-json-valid": "^2.10.0", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.2.5", + "json-stable-stringify": "^1.0.0", + "lodash.clonedeep": "^3.0.1", + "lodash.merge": "^3.3.2", + "lodash.omit": "^3.1.0", + "minimatch": "^3.0.0", + "mkdirp": "^0.5.0", + "object-assign": "^4.0.1", + "optionator": "^0.6.0", + "path-is-absolute": "^1.0.0", + "path-is-inside": "^1.0.1", + "shelljs": "^0.5.3", + "strip-json-comments": "~1.0.1", + "text-table": "~0.2.0", + "to-double-quotes": "^2.0.0", + "to-single-quotes": "^2.0.0", + "user-home": "^2.0.0", + "xml-escape": "~1.0.0" + }, "dependencies": { "chalk": { "version": "1.1.3", - "from": "chalk@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, "dependencies": { "ansi-styles": { "version": "2.2.1", - "from": "ansi-styles@>=2.2.1 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true }, "has-ansi": { "version": "2.0.0", - "from": "has-ansi@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=", + "dev": true } } }, "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=", + "dev": true } } }, "supports-color": { "version": "2.0.0", - "from": "supports-color@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true } } }, "concat-stream": { "version": "1.5.1", - "from": "concat-stream@>=1.4.6 <2.0.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.1.tgz", + "integrity": "sha1-87gKz54fSOOHXAaItBtsMWAu6hw=", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~2.0.0", + "typedarray": "~0.0.5" + }, "dependencies": { "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.1 <2.1.0" - }, - "typedarray": { - "version": "0.0.6", - "from": "typedarray@>=0.0.5 <0.1.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "readable-stream": { "version": "2.0.6", - "from": "readable-stream@>=2.0.0 <2.1.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + }, "dependencies": { "core-util-is": { "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "isarray": { "version": "1.0.0", - "from": "isarray@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "process-nextick-args": { "version": "1.0.7", - "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true }, "string_decoder": { "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0" + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true }, "util-deprecate": { "version": "1.0.2", - "from": "util-deprecate@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true } } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true } } }, "debug": { "version": "2.2.0", - "from": "debug@>=2.1.1 <3.0.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + }, "dependencies": { "ms": { "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true } } }, "doctrine": { "version": "0.7.2", - "from": "doctrine@>=0.7.0 <0.8.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz", + "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=", + "dev": true, + "requires": { + "esutils": "^1.1.6", + "isarray": "0.0.1" + }, "dependencies": { "esutils": { "version": "1.1.6", - "from": "esutils@>=1.1.6 <2.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz" + "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", + "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=", + "dev": true }, "isarray": { "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true } } }, "escape-string-regexp": { "version": "1.0.5", - "from": "escape-string-regexp@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "escope": { "version": "3.6.0", - "from": "escope@>=3.2.0 <4.0.0", "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, "dependencies": { "es6-map": { "version": "0.1.4", - "from": "es6-map@>=0.1.3 <0.2.0", "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.4.tgz", + "integrity": "sha1-o0sUe+IkdzpNfagHJ5TO+jYyuJc=", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.11", + "es6-iterator": "2", + "es6-set": "~0.1.3", + "es6-symbol": "~3.1.0", + "event-emitter": "~0.3.4" + }, "dependencies": { "d": { "version": "0.1.1", - "from": "d@>=0.1.1 <0.2.0" + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", + "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=", + "dev": true, + "requires": { + "es5-ext": "~0.10.2" + } }, "es5-ext": { "version": "0.10.12", - "from": "es5-ext@>=0.10.11 <0.11.0", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz" + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz", + "integrity": "sha1-qoRkHU23a2Krul5F/YBey6sUAEc=", + "dev": true, + "requires": { + "es6-iterator": "2", + "es6-symbol": "~3.1" + } }, "es6-iterator": { "version": "2.0.0", - "from": "es6-iterator@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz", + "integrity": "sha1-vZaFZ9YWNeM8C4BydhPJy0sJa6w=", + "dev": true, + "requires": { + "d": "^0.1.1", + "es5-ext": "^0.10.7", + "es6-symbol": "3" + } }, "es6-set": { "version": "0.1.4", - "from": "es6-set@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.4.tgz" + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.4.tgz", + "integrity": "sha1-lRa2dhwpZLkv9HlFYjOiR9xwfOg=", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.11", + "es6-iterator": "2", + "es6-symbol": "3", + "event-emitter": "~0.3.4" + } }, "es6-symbol": { "version": "3.1.0", - "from": "es6-symbol@>=3.1.0 <3.2.0", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz" + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz", + "integrity": "sha1-lEgcZV56fK2C66gy2X1UM0ltf/o=", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.11" + } }, "event-emitter": { "version": "0.3.4", - "from": "event-emitter@>=0.3.4 <0.4.0", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz" + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.4.tgz", + "integrity": "sha1-jWPd+0z+H647MsomXExyAiIIC7U=", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.7" + } } } }, "es6-weak-map": { "version": "2.0.1", - "from": "es6-weak-map@>=2.0.1 <3.0.0", "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.1.tgz", + "integrity": "sha1-DSu9iCfrX7S6j5f7/qUNQ9sh6oE=", + "dev": true, + "requires": { + "d": "^0.1.1", + "es5-ext": "^0.10.8", + "es6-iterator": "2", + "es6-symbol": "3" + }, "dependencies": { "d": { "version": "0.1.1", - "from": "d@>=0.1.1 <0.2.0" + "resolved": "https://registry.npmjs.org/d/-/d-0.1.1.tgz", + "integrity": "sha1-2hhMU10Y2O57oqoim5FACfrhEwk=", + "dev": true, + "requires": { + "es5-ext": "~0.10.2" + } }, "es5-ext": { "version": "0.10.12", - "from": "es5-ext@>=0.10.8 <0.11.0", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz" + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.12.tgz", + "integrity": "sha1-qoRkHU23a2Krul5F/YBey6sUAEc=", + "dev": true, + "requires": { + "es6-iterator": "2", + "es6-symbol": "~3.1" + } }, "es6-iterator": { "version": "2.0.0", - "from": "es6-iterator@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz", + "integrity": "sha1-vZaFZ9YWNeM8C4BydhPJy0sJa6w=", + "dev": true, + "requires": { + "d": "^0.1.1", + "es5-ext": "^0.10.7", + "es6-symbol": "3" + } }, "es6-symbol": { "version": "3.1.0", - "from": "es6-symbol@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz" + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz", + "integrity": "sha1-lEgcZV56fK2C66gy2X1UM0ltf/o=", + "dev": true, + "requires": { + "d": "~0.1.1", + "es5-ext": "~0.10.11" + } } } }, "esrecurse": { "version": "4.1.0", - "from": "esrecurse@>=4.1.0 <5.0.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz", + "integrity": "sha1-RxO2U2rffyrE8yfVWed1a/9kgiA=", + "dev": true, + "requires": { + "estraverse": "~4.1.0", + "object-assign": "^4.0.1" + }, "dependencies": { "estraverse": { "version": "4.1.1", - "from": "estraverse@>=4.1.0 <4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz" + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.1.1.tgz", + "integrity": "sha1-9srKcokzqFDvkGYdDheYK6RxEaI=", + "dev": true } } } @@ -2095,96 +3131,160 @@ }, "espree": { "version": "2.2.5", - "from": "espree@>=2.2.4 <3.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz" + "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", + "integrity": "sha1-32kbkxCIlAKuspzAZnCMVmkLhUs=", + "dev": true }, "estraverse": { "version": "4.2.0", - "from": "estraverse@>=4.1.1 <5.0.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz" + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true }, "estraverse-fb": { "version": "1.3.1", - "from": "estraverse-fb@>=1.3.1 <2.0.0", - "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.1.tgz" + "resolved": "https://registry.npmjs.org/estraverse-fb/-/estraverse-fb-1.3.1.tgz", + "integrity": "sha1-Fg51qA5gWwjOiUvM4v4+Qpq/kr8=", + "dev": true }, "esutils": { "version": "2.0.2", - "from": "esutils@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz" + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true }, "file-entry-cache": { "version": "1.2.4", - "from": "file-entry-cache@>=1.1.1 <2.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.2.4.tgz", + "integrity": "sha1-mlhgcsaTZafvfscqfCuQRt4JHpw=", + "dev": true, + "requires": { + "flat-cache": "^1.0.9", + "object-assign": "^4.0.1" + }, "dependencies": { "flat-cache": { "version": "1.0.10", - "from": "flat-cache@>=1.0.9 <2.0.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.0.10.tgz", + "integrity": "sha1-c9bfSihQIWCgXgWVRKau6uiwBHo=", + "dev": true, + "requires": { + "del": "^2.0.2", + "graceful-fs": "^4.1.2", + "read-json-sync": "^1.1.0", + "write": "^0.2.1" + }, "dependencies": { "del": { "version": "2.2.1", - "from": "del@>=2.0.2 <3.0.0", "resolved": "https://registry.npmjs.org/del/-/del-2.2.1.tgz", + "integrity": "sha1-9nYwJkciCcTwNJERxawoCGi+xP4=", + "dev": true, + "requires": { + "globby": "^5.0.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "rimraf": "^2.2.8" + }, "dependencies": { "globby": { "version": "5.0.0", - "from": "globby@>=5.0.0 <6.0.0", "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, "dependencies": { "array-union": { "version": "1.0.2", - "from": "array-union@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + }, "dependencies": { "array-uniq": { "version": "1.0.3", - "from": "array-uniq@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true } } }, "arrify": { "version": "1.0.1", - "from": "arrify@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true }, "glob": { "version": "7.0.5", - "from": "glob@>=7.0.3 <8.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz", + "integrity": "sha1-tCAqaQmbu00pKnwblbZoK2fr3JU=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "dependencies": { "fs.realpath": { "version": "1.0.0", - "from": "fs.realpath@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "inflight": { "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } } @@ -2194,78 +3294,120 @@ }, "is-path-cwd": { "version": "1.0.0", - "from": "is-path-cwd@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true }, "is-path-in-cwd": { "version": "1.0.0", - "from": "is-path-in-cwd@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + }, "dependencies": { "is-path-inside": { "version": "1.0.0", - "from": "is-path-inside@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } } } }, "pify": { "version": "2.3.0", - "from": "pify@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true }, "pinkie-promise": { "version": "2.0.1", - "from": "pinkie-promise@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + }, "dependencies": { "pinkie": { "version": "2.0.4", - "from": "pinkie@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true } } }, "rimraf": { "version": "2.5.3", - "from": "rimraf@>=2.2.8 <3.0.0", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.3.tgz", + "integrity": "sha1-bl792kqi8DQX9rKldK7Cn0tlJwU=", + "dev": true, + "requires": { + "glob": "^7.0.5" + }, "dependencies": { "glob": { "version": "7.0.5", - "from": "glob@>=7.0.5 <8.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz", + "integrity": "sha1-tCAqaQmbu00pKnwblbZoK2fr3JU=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "dependencies": { "fs.realpath": { "version": "1.0.0", - "from": "fs.realpath@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "inflight": { "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } } @@ -2277,18 +3419,27 @@ }, "graceful-fs": { "version": "4.1.4", - "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz", + "integrity": "sha1-7widKIDwM7ARgjzlyPrnmNp3Xb0=", + "dev": true }, "read-json-sync": { "version": "1.1.1", - "from": "read-json-sync@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/read-json-sync/-/read-json-sync-1.1.1.tgz" + "resolved": "https://registry.npmjs.org/read-json-sync/-/read-json-sync-1.1.1.tgz", + "integrity": "sha1-Q8ZproZKrjCN+7snIaZ+KV7I//Y=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2" + } }, "write": { "version": "0.2.1", - "from": "write@>=0.2.1 <0.3.0", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz" + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } } } } @@ -2296,34 +3447,55 @@ }, "glob": { "version": "5.0.15", - "from": "glob@>=5.0.14 <6.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "dependencies": { "inflight": { "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } } @@ -2331,147 +3503,250 @@ }, "globals": { "version": "8.18.0", - "from": "globals@>=8.11.0 <9.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz" + "resolved": "https://registry.npmjs.org/globals/-/globals-8.18.0.tgz", + "integrity": "sha1-k9SmK9ysOM+vr8R9awNHaMsP/LQ=", + "dev": true }, "handlebars": { "version": "4.0.5", - "from": "handlebars@>=4.0.0 <5.0.0", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz", + "integrity": "sha1-ksbta7FkEQxQ1NjQ+93HCAbG+Oc=", + "dev": true, + "requires": { + "async": "^1.4.0", + "optimist": "^0.6.1", + "source-map": "^0.4.4", + "uglify-js": "^2.6" + }, "dependencies": { "optimist": { "version": "0.6.1", - "from": "optimist@>=0.6.1 <0.7.0", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + }, "dependencies": { - "wordwrap": { - "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" - }, "minimist": { "version": "0.0.10", - "from": "minimist@>=0.0.1 <0.1.0" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true } } }, "source-map": { "version": "0.4.4", - "from": "source-map@>=0.4.4 <0.5.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + }, "dependencies": { "amdefine": { "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz", + "integrity": "sha1-/RdHRwDLXMnCtwnwvp0jzjwZjDM=", + "dev": true } } }, "uglify-js": { "version": "2.7.0", - "from": "uglify-js@>=2.6.0 <3.0.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.0.tgz", + "integrity": "sha1-8CHji6LKdAhg9b1caVwqgXNF8Ow=", + "dev": true, + "optional": true, + "requires": { + "async": "~0.2.6", + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, "dependencies": { "async": { "version": "0.2.10", - "from": "async@>=0.2.6 <0.3.0", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true, + "optional": true }, "source-map": { "version": "0.5.6", - "from": "source-map@>=0.5.1 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true, + "optional": true }, "uglify-to-browserify": { "version": "1.0.2", - "from": "uglify-to-browserify@>=1.0.0 <1.1.0" + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true }, "yargs": { "version": "3.10.0", - "from": "yargs@>=3.10.0 <3.11.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + }, "dependencies": { "camelcase": { "version": "1.2.1", - "from": "camelcase@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true }, "cliui": { "version": "2.1.0", - "from": "cliui@>=2.1.0 <3.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, "dependencies": { "center-align": { "version": "0.1.3", - "from": "center-align@>=0.1.1 <0.2.0", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + }, "dependencies": { "align-text": { "version": "0.1.4", - "from": "align-text@>=0.1.3 <0.2.0", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + }, "dependencies": { "kind-of": { "version": "3.0.3", - "from": "kind-of@>=3.0.2 <4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", + "integrity": "sha1-xhYIdH2BWwNiVW2zJ2Nip6OK3tM=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.0.2" + }, "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", + "integrity": "sha1-24l/w/esotUN6UtsjCiWpHcWJ68=", + "dev": true, + "optional": true } } }, "longest": { "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true, + "optional": true }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", + "integrity": "sha1-ZOwMkeD0tHX5DVtkNlHj5uW2wtU=", + "dev": true, + "optional": true } } }, "lazy-cache": { "version": "1.0.4", - "from": "lazy-cache@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true } } }, "right-align": { "version": "0.1.3", - "from": "right-align@>=0.1.1 <0.2.0", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "optional": true, + "requires": { + "align-text": "^0.1.1" + }, "dependencies": { "align-text": { "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "optional": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + }, "dependencies": { "kind-of": { "version": "3.0.3", - "from": "kind-of@>=3.0.2 <4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", + "integrity": "sha1-xhYIdH2BWwNiVW2zJ2Nip6OK3tM=", + "dev": true, + "optional": true, + "requires": { + "is-buffer": "^1.0.2" + }, "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", + "integrity": "sha1-24l/w/esotUN6UtsjCiWpHcWJ68=", + "dev": true, + "optional": true } } }, "longest": { "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true, + "optional": true }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", + "integrity": "sha1-ZOwMkeD0tHX5DVtkNlHj5uW2wtU=", + "dev": true, + "optional": true } } } @@ -2479,19 +3754,26 @@ }, "wordwrap": { "version": "0.0.2", - "from": "wordwrap@0.0.2" + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true } } }, "decamelize": { "version": "1.2.0", - "from": "decamelize@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "optional": true }, "window-size": { "version": "0.1.0", - "from": "window-size@0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true } } } @@ -2501,38 +3783,67 @@ }, "inquirer": { "version": "0.11.4", - "from": "inquirer@>=0.11.0 <0.12.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.11.4.tgz", + "integrity": "sha1-geM3ToNhvq/y2XAWIG01nQsy+k0=", + "dev": true, + "requires": { + "ansi-escapes": "^1.1.0", + "ansi-regex": "^2.0.0", + "chalk": "^1.0.0", + "cli-cursor": "^1.0.1", + "cli-width": "^1.0.1", + "figures": "^1.3.5", + "lodash": "^3.3.1", + "readline2": "^1.0.1", + "run-async": "^0.1.0", + "rx-lite": "^3.1.2", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + }, "dependencies": { "ansi-escapes": { "version": "1.4.0", - "from": "ansi-escapes@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz" + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true }, "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=", + "dev": true }, "cli-cursor": { "version": "1.0.2", - "from": "cli-cursor@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "^1.0.1" + }, "dependencies": { "restore-cursor": { "version": "1.0.1", - "from": "restore-cursor@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "^1.0.0", + "onetime": "^1.0.0" + }, "dependencies": { "exit-hook": { "version": "1.1.1", - "from": "exit-hook@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz" + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true }, "onetime": { "version": "1.1.0", - "from": "onetime@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz" + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true } } } @@ -2540,69 +3851,102 @@ }, "cli-width": { "version": "1.1.1", - "from": "cli-width@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz" + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz", + "integrity": "sha1-pNKT72frt7iNSk1CwMzwDE0eNm0=", + "dev": true }, "figures": { "version": "1.7.0", - "from": "figures@>=1.3.5 <2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz" + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } }, "lodash": { "version": "3.10.1", - "from": "lodash@>=3.3.1 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true }, "readline2": { "version": "1.0.1", - "from": "readline2@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "mute-stream": "0.0.5" + }, "dependencies": { "code-point-at": { "version": "1.0.0", - "from": "code-point-at@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz", + "integrity": "sha1-9psZLT99keOC5Lcb3bd4eGGasMY=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + }, "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=", + "dev": true } } }, "is-fullwidth-code-point": { "version": "1.0.0", - "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + }, "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=", + "dev": true } } }, "mute-stream": { "version": "0.0.5", - "from": "mute-stream@0.0.5", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz" + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true } } }, "run-async": { "version": "0.1.0", - "from": "run-async@>=0.1.0 <0.2.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true, + "requires": { + "once": "^1.3.0" + }, "dependencies": { "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } } @@ -2610,35 +3954,52 @@ }, "rx-lite": { "version": "3.1.2", - "from": "rx-lite@>=3.1.2 <4.0.0", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz" + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true }, "string-width": { "version": "1.0.1", - "from": "string-width@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz", + "integrity": "sha1-ySEptvHX9SrPmvQkom44ZKBc6wo=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, "dependencies": { "code-point-at": { "version": "1.0.0", - "from": "code-point-at@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz", + "integrity": "sha1-9psZLT99keOC5Lcb3bd4eGGasMY=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + }, "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=", + "dev": true } } }, "is-fullwidth-code-point": { "version": "1.0.0", - "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + }, "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=", + "dev": true } } } @@ -2646,124 +4007,186 @@ }, "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } }, "through": { "version": "2.3.8", - "from": "through@>=2.3.6 <3.0.0", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true } } }, "is-my-json-valid": { "version": "2.13.1", - "from": "is-my-json-valid@>=2.10.0 <3.0.0", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz", + "integrity": "sha1-1Vd4qC/rawlj/0vhEdXRaE6JBwc=", + "dev": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "jsonpointer": "2.0.0", + "xtend": "^4.0.0" + }, "dependencies": { "generate-function": { "version": "2.0.0", - "from": "generate-function@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true }, "generate-object-property": { "version": "1.2.0", - "from": "generate-object-property@>=1.1.0 <2.0.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "^1.0.0" + }, "dependencies": { "is-property": { "version": "1.0.2", - "from": "is-property@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true } } }, "jsonpointer": { "version": "2.0.0", - "from": "jsonpointer@2.0.0", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz", + "integrity": "sha1-OvHdIP6FRjkQ1GmjheMwF9KgMNk=", + "dev": true } } }, "is-resolvable": { "version": "1.0.0", - "from": "is-resolvable@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", + "dev": true, + "requires": { + "tryit": "^1.0.1" + }, "dependencies": { "tryit": { "version": "1.0.2", - "from": "tryit@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.2.tgz", + "integrity": "sha1-wZawBz5rHFldk8nIMIVbeswypFM=", + "dev": true } } }, "json-stable-stringify": { "version": "1.0.1", - "from": "json-stable-stringify@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + }, "dependencies": { "jsonify": { "version": "0.0.0", - "from": "jsonify@>=0.0.0 <0.1.0" + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true } } }, "lodash.clonedeep": { "version": "3.0.2", - "from": "lodash.clonedeep@>=3.0.1 <4.0.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-3.0.2.tgz", + "integrity": "sha1-oKHkDYKl6on/WxR7hETtY9koJ9s=", + "dev": true, + "requires": { + "lodash._baseclone": "^3.0.0", + "lodash._bindcallback": "^3.0.0" + }, "dependencies": { "lodash._baseclone": { "version": "3.3.0", - "from": "lodash._baseclone@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash._baseclone/-/lodash._baseclone-3.3.0.tgz", + "integrity": "sha1-MDUZv2OT/n5C802LYw73eU41Qrc=", + "dev": true, + "requires": { + "lodash._arraycopy": "^3.0.0", + "lodash._arrayeach": "^3.0.0", + "lodash._baseassign": "^3.0.0", + "lodash._basefor": "^3.0.0", + "lodash.isarray": "^3.0.0", + "lodash.keys": "^3.0.0" + }, "dependencies": { "lodash._arraycopy": { "version": "3.0.0", - "from": "lodash._arraycopy@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz" + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", + "integrity": "sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=", + "dev": true }, "lodash._arrayeach": { "version": "3.0.0", - "from": "lodash._arrayeach@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz" + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", + "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=", + "dev": true }, "lodash._baseassign": { "version": "3.2.0", - "from": "lodash._baseassign@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash.keys": "^3.0.0" + }, "dependencies": { "lodash._basecopy": { "version": "3.0.1", - "from": "lodash._basecopy@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true } } }, "lodash._basefor": { "version": "3.0.3", - "from": "lodash._basefor@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz" + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", + "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=", + "dev": true }, "lodash.isarray": { "version": "3.0.4", - "from": "lodash.isarray@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true }, "lodash.keys": { "version": "3.1.2", - "from": "lodash.keys@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + }, "dependencies": { "lodash._getnative": { "version": "3.9.1", - "from": "lodash._getnative@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true }, "lodash.isarguments": { "version": "3.0.8", - "from": "lodash.isarguments@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz", + "integrity": "sha1-W/jaiH8B8qnknAoXXNrrMYoOQ9w=", + "dev": true } } } @@ -2771,99 +4194,153 @@ }, "lodash._bindcallback": { "version": "3.0.1", - "from": "lodash._bindcallback@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", + "dev": true } } }, "lodash.merge": { "version": "3.3.2", - "from": "lodash.merge@>=3.3.2 <4.0.0", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-3.3.2.tgz", + "integrity": "sha1-DZDZPtY3sYeEN7s+IWASYNev6ZQ=", + "dev": true, + "requires": { + "lodash._arraycopy": "^3.0.0", + "lodash._arrayeach": "^3.0.0", + "lodash._createassigner": "^3.0.0", + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0", + "lodash.isplainobject": "^3.0.0", + "lodash.istypedarray": "^3.0.0", + "lodash.keys": "^3.0.0", + "lodash.keysin": "^3.0.0", + "lodash.toplainobject": "^3.0.0" + }, "dependencies": { "lodash._arraycopy": { "version": "3.0.0", - "from": "lodash._arraycopy@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz" + "resolved": "https://registry.npmjs.org/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz", + "integrity": "sha1-due3wfH7klRzdIeKVi7Qaj5Q9uE=", + "dev": true }, "lodash._arrayeach": { "version": "3.0.0", - "from": "lodash._arrayeach@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz" + "resolved": "https://registry.npmjs.org/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz", + "integrity": "sha1-urFWsqkNPxu9XGU0AzSeXlkz754=", + "dev": true }, "lodash._createassigner": { "version": "3.1.1", - "from": "lodash._createassigner@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz", + "integrity": "sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=", + "dev": true, + "requires": { + "lodash._bindcallback": "^3.0.0", + "lodash._isiterateecall": "^3.0.0", + "lodash.restparam": "^3.0.0" + }, "dependencies": { "lodash._bindcallback": { "version": "3.0.1", - "from": "lodash._bindcallback@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", + "dev": true }, "lodash._isiterateecall": { "version": "3.0.9", - "from": "lodash._isiterateecall@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz" + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true }, "lodash.restparam": { "version": "3.6.1", - "from": "lodash.restparam@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "dev": true } } }, "lodash._getnative": { "version": "3.9.1", - "from": "lodash._getnative@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true }, "lodash.isarguments": { "version": "3.0.8", - "from": "lodash.isarguments@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz", + "integrity": "sha1-W/jaiH8B8qnknAoXXNrrMYoOQ9w=", + "dev": true }, "lodash.isarray": { "version": "3.0.4", - "from": "lodash.isarray@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true }, "lodash.isplainobject": { "version": "3.2.0", - "from": "lodash.isplainobject@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz", + "integrity": "sha1-moI4rhayAEMpYM1zRlEtASP79MU=", + "dev": true, + "requires": { + "lodash._basefor": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.keysin": "^3.0.0" + }, "dependencies": { "lodash._basefor": { "version": "3.0.3", - "from": "lodash._basefor@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz" + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", + "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=", + "dev": true } } }, "lodash.istypedarray": { "version": "3.0.6", - "from": "lodash.istypedarray@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz" + "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", + "integrity": "sha1-yaR3SYYHUB2OhJTSg7h8OSgc72I=", + "dev": true }, "lodash.keys": { "version": "3.1.2", - "from": "lodash.keys@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz" + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } }, "lodash.keysin": { "version": "3.0.8", - "from": "lodash.keysin@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz" + "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", + "integrity": "sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8=", + "dev": true, + "requires": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } }, "lodash.toplainobject": { "version": "3.0.0", - "from": "lodash.toplainobject@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz", + "integrity": "sha1-KHkK2ULSk9eKpmOgfs9/UsoEGY0=", + "dev": true, + "requires": { + "lodash._basecopy": "^3.0.0", + "lodash.keysin": "^3.0.0" + }, "dependencies": { "lodash._basecopy": { "version": "3.0.1", - "from": "lodash._basecopy@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz" + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true } } } @@ -2871,38 +4348,63 @@ }, "lodash.omit": { "version": "3.1.0", - "from": "lodash.omit@>=3.1.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash.omit/-/lodash.omit-3.1.0.tgz", + "integrity": "sha1-iX/jguZBPZrJfGH3jtHgV6AK+fM=", + "dev": true, + "requires": { + "lodash._arraymap": "^3.0.0", + "lodash._basedifference": "^3.0.0", + "lodash._baseflatten": "^3.0.0", + "lodash._bindcallback": "^3.0.0", + "lodash._pickbyarray": "^3.0.0", + "lodash._pickbycallback": "^3.0.0", + "lodash.keysin": "^3.0.0", + "lodash.restparam": "^3.0.0" + }, "dependencies": { "lodash._arraymap": { "version": "3.0.0", - "from": "lodash._arraymap@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz" + "resolved": "https://registry.npmjs.org/lodash._arraymap/-/lodash._arraymap-3.0.0.tgz", + "integrity": "sha1-Go/Q9MDfS2HeoHbXF83Jfwo8PmY=", + "dev": true }, "lodash._basedifference": { "version": "3.0.3", - "from": "lodash._basedifference@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash._basedifference/-/lodash._basedifference-3.0.3.tgz", + "integrity": "sha1-8sIEKWwqeOArOJCBtu3KyTPPYpw=", + "dev": true, + "requires": { + "lodash._baseindexof": "^3.0.0", + "lodash._cacheindexof": "^3.0.0", + "lodash._createcache": "^3.0.0" + }, "dependencies": { "lodash._baseindexof": { "version": "3.1.0", - "from": "lodash._baseindexof@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz" + "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", + "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=", + "dev": true }, "lodash._cacheindexof": { "version": "3.0.2", - "from": "lodash._cacheindexof@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz" + "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", + "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=", + "dev": true }, "lodash._createcache": { "version": "3.1.2", - "from": "lodash._createcache@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", + "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0" + }, "dependencies": { "lodash._getnative": { "version": "3.9.1", - "from": "lodash._getnative@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true } } } @@ -2910,86 +4412,120 @@ }, "lodash._baseflatten": { "version": "3.1.4", - "from": "lodash._baseflatten@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz", + "integrity": "sha1-B3D/gBMa9uNPO1EXlqe6UhTmX/c=", + "dev": true, + "requires": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + }, "dependencies": { "lodash.isarguments": { "version": "3.0.8", - "from": "lodash.isarguments@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz", + "integrity": "sha1-W/jaiH8B8qnknAoXXNrrMYoOQ9w=", + "dev": true }, "lodash.isarray": { "version": "3.0.4", - "from": "lodash.isarray@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true } } }, "lodash._bindcallback": { "version": "3.0.1", - "from": "lodash._bindcallback@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz" + "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=", + "dev": true }, "lodash._pickbyarray": { "version": "3.0.2", - "from": "lodash._pickbyarray@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz" + "resolved": "https://registry.npmjs.org/lodash._pickbyarray/-/lodash._pickbyarray-3.0.2.tgz", + "integrity": "sha1-H4mNlgfrVgsOFnOEt3x8bRCKpMU=", + "dev": true }, "lodash._pickbycallback": { "version": "3.0.0", - "from": "lodash._pickbycallback@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash._pickbycallback/-/lodash._pickbycallback-3.0.0.tgz", + "integrity": "sha1-/2G5oBens699MObFPeKK+hm4dQo=", + "dev": true, + "requires": { + "lodash._basefor": "^3.0.0", + "lodash.keysin": "^3.0.0" + }, "dependencies": { "lodash._basefor": { "version": "3.0.3", - "from": "lodash._basefor@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz" + "resolved": "https://registry.npmjs.org/lodash._basefor/-/lodash._basefor-3.0.3.tgz", + "integrity": "sha1-dVC06SGO8J+tJDQ7YSAhx5tMIMI=", + "dev": true } } }, "lodash.keysin": { "version": "3.0.8", - "from": "lodash.keysin@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/lodash.keysin/-/lodash.keysin-3.0.8.tgz", + "integrity": "sha1-IsRJPrvtsUJ5YqVLRFssinZ/tH8=", + "dev": true, + "requires": { + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + }, "dependencies": { "lodash.isarguments": { "version": "3.0.8", - "from": "lodash.isarguments@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.0.8.tgz", + "integrity": "sha1-W/jaiH8B8qnknAoXXNrrMYoOQ9w=", + "dev": true }, "lodash.isarray": { "version": "3.0.4", - "from": "lodash.isarray@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true } } }, "lodash.restparam": { "version": "3.6.1", - "from": "lodash.restparam@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz" + "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", + "dev": true } } }, "minimatch": { "version": "3.0.2", - "from": "minimatch@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "integrity": "sha1-DzmKcwDqRB6cNIyD2Yq4ydv5xAo=", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + }, "dependencies": { "brace-expansion": { "version": "1.1.5", - "from": "brace-expansion@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "integrity": "sha1-9bStV04st8zB64Pm/nm47K33pSY=", + "dev": true, + "requires": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + }, "dependencies": { "balanced-match": { "version": "0.4.1", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", + "integrity": "sha1-GQU+LgdI6ts3nabAnUVc9eEDkzU=", + "dev": true }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true } } } @@ -2997,218 +4533,330 @@ }, "mkdirp": { "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, "dependencies": { "minimist": { "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true } } }, "object-assign": { "version": "4.1.0", - "from": "object-assign@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", + "dev": true }, "optionator": { "version": "0.6.0", - "from": "optionator@>=0.6.0 <0.7.0", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.6.0.tgz", + "integrity": "sha1-tj7Lvw4xX61LyYJ7Rdx7pFKE/LY=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~1.0.6", + "levn": "~0.2.5", + "prelude-ls": "~1.1.1", + "type-check": "~0.3.1", + "wordwrap": "~0.0.2" + }, "dependencies": { - "prelude-ls": { - "version": "1.1.2", - "from": "prelude-ls@>=1.1.1 <1.2.0", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" - }, "deep-is": { "version": "0.1.3", - "from": "deep-is@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true }, - "wordwrap": { - "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" - }, - "type-check": { - "version": "0.3.2", - "from": "type-check@>=0.3.1 <0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + "fast-levenshtein": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz", + "integrity": "sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk=", + "dev": true }, "levn": { "version": "0.2.5", - "from": "levn@>=0.2.5 <0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz" + "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz", + "integrity": "sha1-uo0znQykphDjo/FFucr0iAcVUFQ=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.0", + "type-check": "~0.3.1" + } }, - "fast-levenshtein": { - "version": "1.0.7", - "from": "fast-levenshtein@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz" + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true } } }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=", + "dev": true }, "path-is-inside": { "version": "1.0.1", - "from": "path-is-inside@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.1.tgz", + "integrity": "sha1-mNjx0DC/BL167uShulSF1AMY/Yk=", + "dev": true }, "shelljs": { "version": "0.5.3", - "from": "shelljs@>=0.5.3 <0.6.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz" + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.5.3.tgz", + "integrity": "sha1-xUmCuZbHbvDB5rWfvcWCX1txMRM=", + "dev": true }, "strip-json-comments": { "version": "1.0.4", - "from": "strip-json-comments@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz" + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true }, "text-table": { "version": "0.2.0", - "from": "text-table@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, "to-double-quotes": { "version": "2.0.0", - "from": "to-double-quotes@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/to-double-quotes/-/to-double-quotes-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/to-double-quotes/-/to-double-quotes-2.0.0.tgz", + "integrity": "sha1-qvIx1vqUiUn4GTAburRITYWI5Kc=", + "dev": true }, "to-single-quotes": { "version": "2.0.1", - "from": "to-single-quotes@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/to-single-quotes/-/to-single-quotes-2.0.1.tgz" + "resolved": "https://registry.npmjs.org/to-single-quotes/-/to-single-quotes-2.0.1.tgz", + "integrity": "sha1-fMKRUfD18sQZRvEZ9ZMv5VQXASU=", + "dev": true }, "user-home": { "version": "2.0.0", - "from": "user-home@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0" + }, "dependencies": { "os-homedir": { "version": "1.0.1", - "from": "os-homedir@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz", + "integrity": "sha1-DWK99EuRb9O73PLKsZGUj7CU8Ac=", + "dev": true } } }, "xml-escape": { "version": "1.0.0", - "from": "xml-escape@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.0.0.tgz", + "integrity": "sha1-AJY9aXsq3wwYXE4E5zF0upsojrI=", + "dev": true } } }, "find-root": { "version": "0.1.2", - "from": "find-root@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-0.1.2.tgz" + "resolved": "https://registry.npmjs.org/find-root/-/find-root-0.1.2.tgz", + "integrity": "sha1-mNImfP8ZFsyvJ0OzoO6oHXnX3NE=", + "dev": true }, "get-stdin": { "version": "4.0.1", - "from": "get-stdin@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true }, "minimist": { "version": "1.2.0", - "from": "minimist@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true }, "multiline": { "version": "1.0.2", - "from": "multiline@>=1.0.2 <2.0.0", "resolved": "https://registry.npmjs.org/multiline/-/multiline-1.0.2.tgz", + "integrity": "sha1-abHyX/B00oKJBPJE3dBrfZbvbJM=", + "dev": true, + "requires": { + "strip-indent": "^1.0.0" + }, "dependencies": { "strip-indent": { "version": "1.0.1", - "from": "strip-indent@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } } } }, "pkg-config": { "version": "1.1.1", - "from": "pkg-config@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", + "dev": true, + "requires": { + "debug-log": "^1.0.0", + "find-root": "^1.0.0", + "xtend": "^4.0.1" + }, "dependencies": { "debug-log": { "version": "1.0.0", - "from": "debug-log@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.0.tgz", + "integrity": "sha1-6lIIAbS3gYG5jJSZRSWAw0xPC/4=", + "dev": true }, "find-root": { "version": "1.0.0", - "from": "find-root@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.0.0.tgz", + "integrity": "sha1-li/yEaqyXGUg/u641ih/j26VgHo=", + "dev": true } } }, "xtend": { "version": "4.0.1", - "from": "xtend@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true } } }, "standard-format": { "version": "1.6.10", - "from": "standard-format@>=1.3.3 <2.0.0", "resolved": "https://registry.npmjs.org/standard-format/-/standard-format-1.6.10.tgz", + "integrity": "sha1-sYPI+DfI05OHmPPQlD5dgHoboD8=", + "dev": true, + "requires": { + "deglob": "^1.0.0", + "esformatter": "^0.8.1", + "esformatter-eol-last": "^1.0.0", + "esformatter-jsx": "^2.0.11", + "esformatter-literal-notation": "^1.0.0", + "esformatter-quotes": "^1.0.0", + "esformatter-semicolon-first": "^1.1.0", + "esformatter-spaced-lined-comment": "^2.0.0", + "minimist": "^1.1.0", + "stdin": "0.0.1" + }, "dependencies": { "deglob": { "version": "1.1.1", - "from": "deglob@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/deglob/-/deglob-1.1.1.tgz", + "integrity": "sha1-0nDNWtcBv4tLhZR+RtAT/9e9Qio=", + "dev": true, + "requires": { + "find-root": "^0.1.1", + "glob": "^6.0.4", + "ignore": "^3.0.9", + "pkg-config": "^1.1.0", + "run-parallel": "^1.1.2", + "uniq": "^1.0.1", + "xtend": "^4.0.0" + }, "dependencies": { "find-root": { "version": "0.1.2", - "from": "find-root@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-0.1.2.tgz" + "resolved": "https://registry.npmjs.org/find-root/-/find-root-0.1.2.tgz", + "integrity": "sha1-mNImfP8ZFsyvJ0OzoO6oHXnX3NE=", + "dev": true }, "glob": { "version": "6.0.4", - "from": "glob@>=6.0.4 <7.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "dependencies": { "inflight": { "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "minimatch": { "version": "3.0.2", - "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "integrity": "sha1-DzmKcwDqRB6cNIyD2Yq4ydv5xAo=", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + }, "dependencies": { "brace-expansion": { "version": "1.1.5", - "from": "brace-expansion@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "integrity": "sha1-9bStV04st8zB64Pm/nm47K33pSY=", + "dev": true, + "requires": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + }, "dependencies": { "balanced-match": { "version": "0.4.1", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", + "integrity": "sha1-GQU+LgdI6ts3nabAnUVc9eEDkzU=", + "dev": true }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true } } } @@ -3216,133 +4864,209 @@ }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=", + "dev": true } } }, "ignore": { "version": "3.1.3", - "from": "ignore@>=3.0.9 <4.0.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.1.3.tgz" + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.1.3.tgz", + "integrity": "sha1-nokMBlJRkRWulCfaR1Fr1U0daZk=", + "dev": true }, "pkg-config": { "version": "1.1.1", - "from": "pkg-config@>=1.1.0 <2.0.0", "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", + "dev": true, + "requires": { + "debug-log": "^1.0.0", + "find-root": "^1.0.0", + "xtend": "^4.0.1" + }, "dependencies": { "debug-log": { "version": "1.0.0", - "from": "debug-log@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.0.tgz", + "integrity": "sha1-6lIIAbS3gYG5jJSZRSWAw0xPC/4=", + "dev": true }, "find-root": { "version": "1.0.0", - "from": "find-root@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.0.0.tgz", + "integrity": "sha1-li/yEaqyXGUg/u641ih/j26VgHo=", + "dev": true } } }, "run-parallel": { "version": "1.1.6", - "from": "run-parallel@>=1.1.2 <2.0.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.6.tgz" + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.6.tgz", + "integrity": "sha1-KQA8miFj4B4tLfyQV18sbB1hoDk=", + "dev": true }, "uniq": { "version": "1.0.1", - "from": "uniq@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true }, "xtend": { "version": "4.0.1", - "from": "xtend@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true } } }, "esformatter": { "version": "0.8.2", - "from": "esformatter@>=0.8.1 <0.9.0", "resolved": "https://registry.npmjs.org/esformatter/-/esformatter-0.8.2.tgz", + "integrity": "sha1-e6mIKqPtMIOfivds3fTxLaM3084=", + "dev": true, + "requires": { + "debug": "^0.7.4", + "disparity": "^2.0.0", + "espree": "^2.2.4", + "glob": "^5.0.3", + "minimist": "^1.1.1", + "mout": ">=0.9 <2.0", + "npm-run": "^2.0.0", + "resolve": "^1.1.5", + "rocambole": ">=0.7 <2.0", + "rocambole-indent": "^2.0.4", + "rocambole-linebreak": "^1.0.0", + "rocambole-node": "~1.0", + "rocambole-token": "^1.1.2", + "rocambole-whitespace": "^1.0.0", + "stdin": "*", + "strip-json-comments": "~0.1.1", + "supports-color": "^1.3.1", + "user-home": "^2.0.0" + }, "dependencies": { "debug": { "version": "0.7.4", - "from": "debug@>=0.7.4 <0.8.0" + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", + "dev": true }, "disparity": { "version": "2.0.0", - "from": "disparity@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/disparity/-/disparity-2.0.0.tgz", + "integrity": "sha1-V92stHMkrl9Y0swNqIbbTOnutxg=", + "dev": true, + "requires": { + "ansi-styles": "^2.0.1", + "diff": "^1.3.2" + }, "dependencies": { "ansi-styles": { "version": "2.2.1", - "from": "ansi-styles@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true }, "diff": { "version": "1.4.0", - "from": "diff@>=1.3.2 <2.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz" + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true } } }, "espree": { "version": "2.2.5", - "from": "espree@>=2.2.4 <3.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz" + "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", + "integrity": "sha1-32kbkxCIlAKuspzAZnCMVmkLhUs=", + "dev": true }, "glob": { "version": "5.0.15", - "from": "glob@>=5.0.3 <6.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "dependencies": { "inflight": { "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "minimatch": { "version": "3.0.2", - "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "integrity": "sha1-DzmKcwDqRB6cNIyD2Yq4ydv5xAo=", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + }, "dependencies": { "brace-expansion": { "version": "1.1.5", - "from": "brace-expansion@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "integrity": "sha1-9bStV04st8zB64Pm/nm47K33pSY=", + "dev": true, + "requires": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + }, "dependencies": { "balanced-match": { "version": "0.4.1", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", + "integrity": "sha1-GQU+LgdI6ts3nabAnUVc9eEDkzU=", + "dev": true }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true } } } @@ -3350,47 +5074,72 @@ }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=", + "dev": true } } }, "mout": { "version": "1.0.0", - "from": "mout@>=0.9.0 <2.0.0", - "resolved": "https://registry.npmjs.org/mout/-/mout-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/mout/-/mout-1.0.0.tgz", + "integrity": "sha1-m98dSvV9ZtR8s1OmM1oygQmOFQE=", + "dev": true }, "npm-run": { "version": "2.0.0", - "from": "npm-run@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/npm-run/-/npm-run-2.0.0.tgz", + "integrity": "sha1-KN/ArV4uRv4ISOK9WN3wAue3PBU=", + "dev": true, + "requires": { + "minimist": "^1.1.1", + "npm-path": "^1.0.1", + "npm-which": "^2.0.0", + "serializerr": "^1.0.1", + "spawn-sync": "^1.0.5", + "sync-exec": "^0.5.0" + }, "dependencies": { "npm-path": { "version": "1.1.0", - "from": "npm-path@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-1.1.0.tgz", + "integrity": "sha1-BHSuAEGcMn1UcBt88s0F3Ii+EUA=", + "dev": true, + "requires": { + "which": "^1.2.4" + }, "dependencies": { "which": { "version": "1.2.10", - "from": "which@>=1.2.4 <2.0.0", "resolved": "https://registry.npmjs.org/which/-/which-1.2.10.tgz", + "integrity": "sha1-kc2b0HUTIkEbZZtA8FSyHelXqy0=", + "dev": true, + "requires": { + "isexe": "^1.1.1" + }, "dependencies": { "isexe": { "version": "1.1.2", - "from": "isexe@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz" + "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz", + "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=", + "dev": true } } } @@ -3398,30 +5147,46 @@ }, "npm-which": { "version": "2.0.0", - "from": "npm-which@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-2.0.0.tgz", + "integrity": "sha1-DEaYIWC3gwk2YdHQG9RJbS/qu6w=", + "dev": true, + "requires": { + "commander": "^2.2.0", + "npm-path": "^1.0.0", + "which": "^1.0.5" + }, "dependencies": { "commander": { "version": "2.9.0", - "from": "commander@>=2.2.0 <3.0.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + }, "dependencies": { "graceful-readlink": { "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true } } }, "which": { "version": "1.2.10", - "from": "which@>=1.0.5 <2.0.0", "resolved": "https://registry.npmjs.org/which/-/which-1.2.10.tgz", + "integrity": "sha1-kc2b0HUTIkEbZZtA8FSyHelXqy0=", + "dev": true, + "requires": { + "isexe": "^1.1.1" + }, "dependencies": { "isexe": { "version": "1.1.2", - "from": "isexe@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz" + "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz", + "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=", + "dev": true } } } @@ -3429,199 +5194,287 @@ }, "serializerr": { "version": "1.0.2", - "from": "serializerr@>=1.0.1 <2.0.0", "resolved": "https://registry.npmjs.org/serializerr/-/serializerr-1.0.2.tgz", + "integrity": "sha1-rIs9jK2o/GFk3yBWj8YYKVJzG5o=", + "dev": true, + "requires": { + "protochain": "^1.0.3" + }, "dependencies": { "protochain": { "version": "1.0.5", - "from": "protochain@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/protochain/-/protochain-1.0.5.tgz" + "resolved": "https://registry.npmjs.org/protochain/-/protochain-1.0.5.tgz", + "integrity": "sha1-mRxAfpneJkqt+PgVBLXn+ve/omA=", + "dev": true } } }, "spawn-sync": { "version": "1.0.15", - "from": "spawn-sync@>=1.0.5 <2.0.0", "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "requires": { + "concat-stream": "^1.4.7", + "os-shim": "^0.1.2" + }, "dependencies": { "concat-stream": { "version": "1.5.1", - "from": "concat-stream@>=1.4.7 <2.0.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.1.tgz", + "integrity": "sha1-87gKz54fSOOHXAaItBtsMWAu6hw=", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "~2.0.0", + "typedarray": "~0.0.5" + }, "dependencies": { "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.1 <2.1.0" - }, - "typedarray": { - "version": "0.0.6", - "from": "typedarray@>=0.0.5 <0.1.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "readable-stream": { "version": "2.0.6", - "from": "readable-stream@>=2.0.0 <2.1.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + }, "dependencies": { "core-util-is": { "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "isarray": { "version": "1.0.0", - "from": "isarray@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "process-nextick-args": { "version": "1.0.7", - "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true }, "string_decoder": { "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0" + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true }, "util-deprecate": { "version": "1.0.2", - "from": "util-deprecate@>=1.0.1 <1.1.0", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true } } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true } } }, "os-shim": { "version": "0.1.3", - "from": "os-shim@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz" + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true } } }, "sync-exec": { "version": "0.5.0", - "from": "sync-exec@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.5.0.tgz" + "resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.5.0.tgz", + "integrity": "sha1-P3JY5KW6FyRTgZCfpqb2z1BuFmE=", + "dev": true } } }, "resolve": { "version": "1.1.7", - "from": "resolve@>=1.1.5 <2.0.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true }, "rocambole": { "version": "0.7.0", - "from": "rocambole@>=0.7.0 <2.0.0", "resolved": "https://registry.npmjs.org/rocambole/-/rocambole-0.7.0.tgz", + "integrity": "sha1-9seVBVF9xCtvuECEK4uVOw+WhYU=", + "dev": true, + "requires": { + "esprima": "^2.1" + }, "dependencies": { "esprima": { "version": "2.7.2", - "from": "esprima@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz", + "integrity": "sha1-9DvlQ2CZhOrkTJM6xjNSpq818zk=", + "dev": true } } }, "rocambole-indent": { "version": "2.0.4", - "from": "rocambole-indent@>=2.0.4 <3.0.0", "resolved": "https://registry.npmjs.org/rocambole-indent/-/rocambole-indent-2.0.4.tgz", + "integrity": "sha1-oYokl3ygQAuGHapGMehh3LUtCFw=", + "dev": true, + "requires": { + "debug": "^2.1.3", + "mout": "^0.11.0", + "rocambole-token": "^1.2.1" + }, "dependencies": { "debug": { "version": "2.2.0", - "from": "debug@>=2.1.3 <3.0.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + }, "dependencies": { "ms": { "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true } } }, "mout": { "version": "0.11.1", - "from": "mout@>=0.11.0 <0.12.0", - "resolved": "https://registry.npmjs.org/mout/-/mout-0.11.1.tgz" + "resolved": "https://registry.npmjs.org/mout/-/mout-0.11.1.tgz", + "integrity": "sha1-ujYR318OWx/7/QEWa48C0fX6K5k=", + "dev": true } } }, "rocambole-linebreak": { "version": "1.0.2", - "from": "rocambole-linebreak@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/rocambole-linebreak/-/rocambole-linebreak-1.0.2.tgz", + "integrity": "sha1-A2IVFbQ7RyHJflocG8paA2Y2jy8=", + "dev": true, + "requires": { + "debug": "^2.1.3", + "rocambole-token": "^1.2.1", + "semver": "^4.3.1" + }, "dependencies": { "debug": { "version": "2.2.0", - "from": "debug@>=2.1.3 <3.0.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + }, "dependencies": { "ms": { "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true } } }, "semver": { "version": "4.3.6", - "from": "semver@>=4.3.1 <5.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz" + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", + "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "dev": true } } }, "rocambole-node": { "version": "1.0.0", - "from": "rocambole-node@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/rocambole-node/-/rocambole-node-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/rocambole-node/-/rocambole-node-1.0.0.tgz", + "integrity": "sha1-21tJ3nQHsAgN1RSHLyjjk9D3/z8=", + "dev": true }, "rocambole-token": { "version": "1.2.1", - "from": "rocambole-token@>=1.1.2 <2.0.0", - "resolved": "https://registry.npmjs.org/rocambole-token/-/rocambole-token-1.2.1.tgz" + "resolved": "https://registry.npmjs.org/rocambole-token/-/rocambole-token-1.2.1.tgz", + "integrity": "sha1-x4XfdCjcPLJ614lwR71SOMwHDTU=", + "dev": true }, "rocambole-whitespace": { "version": "1.0.0", - "from": "rocambole-whitespace@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/rocambole-whitespace/-/rocambole-whitespace-1.0.0.tgz", + "integrity": "sha1-YzMJSSVrKZQfWbGQRZ+ZnGsdO/k=", + "dev": true, + "requires": { + "debug": "^2.1.3", + "repeat-string": "^1.5.0", + "rocambole-token": "^1.2.1" + }, "dependencies": { "debug": { "version": "2.2.0", - "from": "debug@>=2.1.3 <3.0.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + }, "dependencies": { "ms": { "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true } } }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.0 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", + "integrity": "sha1-ZOwMkeD0tHX5DVtkNlHj5uW2wtU=", + "dev": true } } }, "strip-json-comments": { "version": "0.1.3", - "from": "strip-json-comments@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz" + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz", + "integrity": "sha1-Fkxk43Coo8wAyeAbU55WmCPw7lQ=", + "dev": true }, "supports-color": { "version": "1.3.1", - "from": "supports-color@>=1.3.1 <2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz" + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz", + "integrity": "sha1-FXWN8J2P87SswwdTn6vicJXhBC0=", + "dev": true }, "user-home": { "version": "2.0.0", - "from": "user-home@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, + "requires": { + "os-homedir": "^1.0.0" + }, "dependencies": { "os-homedir": { "version": "1.0.1", - "from": "os-homedir@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz", + "integrity": "sha1-DWK99EuRb9O73PLKsZGUj7CU8Ac=", + "dev": true } } } @@ -3629,244 +5482,384 @@ }, "esformatter-eol-last": { "version": "1.0.0", - "from": "esformatter-eol-last@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/esformatter-eol-last/-/esformatter-eol-last-1.0.0.tgz", + "integrity": "sha1-RaeP9GIrHUnkT1a0mQV2amMpDAc=", + "dev": true, + "requires": { + "string.prototype.endswith": "^0.2.0" + }, "dependencies": { "string.prototype.endswith": { "version": "0.2.0", - "from": "string.prototype.endswith@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/string.prototype.endswith/-/string.prototype.endswith-0.2.0.tgz" + "resolved": "https://registry.npmjs.org/string.prototype.endswith/-/string.prototype.endswith-0.2.0.tgz", + "integrity": "sha1-oZwg3uUamHd+mkfhDwm+OTubunU=", + "dev": true } } }, "esformatter-jsx": { "version": "2.3.11", - "from": "esformatter-jsx@>=2.0.11 <3.0.0", "resolved": "https://registry.npmjs.org/esformatter-jsx/-/esformatter-jsx-2.3.11.tgz", + "integrity": "sha1-QRxE7TJHVK+VquXe2FbVp+78td8=", + "dev": true, + "requires": { + "babel-core": "^5.8.34", + "esformatter-ignore": "^0.1.3", + "extend": "^2.0.1", + "fresh-falafel": "^1.2.0", + "js-beautify": "^1.5.10" + }, "dependencies": { "babel-core": { "version": "5.8.38", - "from": "babel-core@>=5.8.34 <6.0.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-5.8.38.tgz", + "integrity": "sha1-H8ruedfmG3ULALjlT238nQr4ZVg=", + "dev": true, + "requires": { + "babel-plugin-constant-folding": "^1.0.1", + "babel-plugin-dead-code-elimination": "^1.0.2", + "babel-plugin-eval": "^1.0.1", + "babel-plugin-inline-environment-variables": "^1.0.1", + "babel-plugin-jscript": "^1.0.4", + "babel-plugin-member-expression-literals": "^1.0.1", + "babel-plugin-property-literals": "^1.0.1", + "babel-plugin-proto-to-assign": "^1.0.3", + "babel-plugin-react-constant-elements": "^1.0.3", + "babel-plugin-react-display-name": "^1.0.3", + "babel-plugin-remove-console": "^1.0.1", + "babel-plugin-remove-debugger": "^1.0.1", + "babel-plugin-runtime": "^1.0.7", + "babel-plugin-undeclared-variables-check": "^1.0.2", + "babel-plugin-undefined-to-void": "^1.1.6", + "babylon": "^5.8.38", + "bluebird": "^2.9.33", + "chalk": "^1.0.0", + "convert-source-map": "^1.1.0", + "core-js": "^1.0.0", + "debug": "^2.1.1", + "detect-indent": "^3.0.0", + "esutils": "^2.0.0", + "fs-readdir-recursive": "^0.1.0", + "globals": "^6.4.0", + "home-or-tmp": "^1.0.0", + "is-integer": "^1.0.4", + "js-tokens": "1.0.1", + "json5": "^0.4.0", + "lodash": "^3.10.0", + "minimatch": "^2.0.3", + "output-file-sync": "^1.1.0", + "path-exists": "^1.0.0", + "path-is-absolute": "^1.0.0", + "private": "^0.1.6", + "regenerator": "0.8.40", + "regexpu": "^1.3.0", + "repeating": "^1.1.2", + "resolve": "^1.1.6", + "shebang-regex": "^1.0.0", + "slash": "^1.0.0", + "source-map": "^0.5.0", + "source-map-support": "^0.2.10", + "to-fast-properties": "^1.0.0", + "trim-right": "^1.0.0", + "try-resolve": "^1.0.0" + }, "dependencies": { "babel-plugin-constant-folding": { "version": "1.0.1", - "from": "babel-plugin-constant-folding@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz", + "integrity": "sha1-g2HTZMmORJw2kr26Ue/whEKQqo4=", + "dev": true }, "babel-plugin-dead-code-elimination": { "version": "1.0.2", - "from": "babel-plugin-dead-code-elimination@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz", + "integrity": "sha1-X3xFEnTc18zNv7s+C4XdKBIfD2U=", + "dev": true }, "babel-plugin-eval": { "version": "1.0.1", - "from": "babel-plugin-eval@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz", + "integrity": "sha1-ovrtJc5r5preS/7CY/cBaRlZUNo=", + "dev": true }, "babel-plugin-inline-environment-variables": { "version": "1.0.1", - "from": "babel-plugin-inline-environment-variables@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz", + "integrity": "sha1-H1jOkSB61qgmqL9kX6/mj/X+P/4=", + "dev": true }, "babel-plugin-jscript": { "version": "1.0.4", - "from": "babel-plugin-jscript@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz", + "integrity": "sha1-jzQsOCduh6R9X6CovT1etsytj8w=", + "dev": true }, "babel-plugin-member-expression-literals": { "version": "1.0.1", - "from": "babel-plugin-member-expression-literals@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz", + "integrity": "sha1-zF7bD6qNyScXDnTW0cAkQAIWJNM=", + "dev": true }, "babel-plugin-property-literals": { "version": "1.0.1", - "from": "babel-plugin-property-literals@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz", + "integrity": "sha1-AlIwGQAZKYCxwRjv6kjOk6q4MzY=", + "dev": true }, "babel-plugin-proto-to-assign": { "version": "1.0.4", - "from": "babel-plugin-proto-to-assign@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz", + "integrity": "sha1-xJ56/QL1d7xNoF6i3wAiUM980SM=", + "dev": true, + "requires": { + "lodash": "^3.9.3" + } }, "babel-plugin-react-constant-elements": { "version": "1.0.3", - "from": "babel-plugin-react-constant-elements@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz", + "integrity": "sha1-lGc26DeEKcvDSdz/YvUcFDs041o=", + "dev": true }, "babel-plugin-react-display-name": { "version": "1.0.3", - "from": "babel-plugin-react-display-name@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz", + "integrity": "sha1-dU/jiSboQkpOexWrbqYTne4FFPw=", + "dev": true }, "babel-plugin-remove-console": { "version": "1.0.1", - "from": "babel-plugin-remove-console@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz", + "integrity": "sha1-2PJFVsOgUAXUKqqv0neH9T/wE6c=", + "dev": true }, "babel-plugin-remove-debugger": { "version": "1.0.1", - "from": "babel-plugin-remove-debugger@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz", + "integrity": "sha1-/S6jzWGkKK0fO5yJiC/0KT6MFMc=", + "dev": true }, "babel-plugin-runtime": { "version": "1.0.7", - "from": "babel-plugin-runtime@>=1.0.7 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz", + "integrity": "sha1-v3x9lm3Vbs1cF/ocslPJrLflSq8=", + "dev": true }, "babel-plugin-undeclared-variables-check": { "version": "1.0.2", - "from": "babel-plugin-undeclared-variables-check@>=1.0.2 <2.0.0", "resolved": "https://registry.npmjs.org/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz", + "integrity": "sha1-XPGqU52BP/ZOmWQSkK9iCWX2Xe4=", + "dev": true, + "requires": { + "leven": "^1.0.2" + }, "dependencies": { "leven": { "version": "1.0.2", - "from": "leven@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/leven/-/leven-1.0.2.tgz", + "integrity": "sha1-kUS27ryl8dBoAWnxpncNzqYLdcM=", + "dev": true } } }, "babel-plugin-undefined-to-void": { "version": "1.1.6", - "from": "babel-plugin-undefined-to-void@>=1.1.6 <2.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz" + "resolved": "https://registry.npmjs.org/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz", + "integrity": "sha1-f1eO+LeN+uYAM4XYQXph7aBuL4E=", + "dev": true }, "babylon": { "version": "5.8.38", - "from": "babylon@>=5.8.38 <6.0.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz" + "resolved": "https://registry.npmjs.org/babylon/-/babylon-5.8.38.tgz", + "integrity": "sha1-7JsSCxG/bM1Bc6GL8hfmC3mFn/0=", + "dev": true }, "bluebird": { "version": "2.10.2", - "from": "bluebird@>=2.9.33 <3.0.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz" + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz", + "integrity": "sha1-AkpVFylTCIV/FPkfEQb8O1VfRGs=", + "dev": true }, "chalk": { "version": "1.1.3", - "from": "chalk@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, "dependencies": { "ansi-styles": { "version": "2.2.1", - "from": "ansi-styles@>=2.2.1 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", - "from": "escape-string-regexp@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "has-ansi": { "version": "2.0.0", - "from": "has-ansi@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=", + "dev": true } } }, "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", + "integrity": "sha1-xQYbbg74qBd15Q9dZhUb9r83EQc=", + "dev": true } } }, "supports-color": { "version": "2.0.0", - "from": "supports-color@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true } } }, "convert-source-map": { "version": "1.2.0", - "from": "convert-source-map@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.2.0.tgz" + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.2.0.tgz", + "integrity": "sha1-RMCMJQbxD7PKb9iI1aNETPjWpmk=", + "dev": true }, "core-js": { "version": "1.2.6", - "from": "core-js@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz" + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.6.tgz", + "integrity": "sha1-4jUfbK52T4w05dg5rLamDO+LSkU=", + "dev": true }, "debug": { "version": "2.2.0", - "from": "debug@>=2.1.1 <3.0.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + }, "dependencies": { "ms": { "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true } } }, "detect-indent": { "version": "3.0.1", - "from": "detect-indent@>=3.0.0 <4.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", + "integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "minimist": "^1.1.0", + "repeating": "^1.1.0" + }, "dependencies": { "get-stdin": { "version": "4.0.1", - "from": "get-stdin@>=4.0.1 <5.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true } } }, "esutils": { "version": "2.0.2", - "from": "esutils@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz" + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true }, "fs-readdir-recursive": { "version": "0.1.2", - "from": "fs-readdir-recursive@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz" + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz", + "integrity": "sha1-MVtPuMHKW4xH3v7zGdBz2tNWgFk=", + "dev": true }, "globals": { "version": "6.4.1", - "from": "globals@>=6.4.0 <7.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz" + "resolved": "https://registry.npmjs.org/globals/-/globals-6.4.1.tgz", + "integrity": "sha1-hJgDKzttHMge68X3lpDY/in6v08=", + "dev": true }, "home-or-tmp": { "version": "1.0.0", - "from": "home-or-tmp@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-1.0.0.tgz", + "integrity": "sha1-S58eQIAMPlDGwn94FnavzOcfOYU=", + "dev": true, + "requires": { + "os-tmpdir": "^1.0.1", + "user-home": "^1.1.1" + }, "dependencies": { "os-tmpdir": { "version": "1.0.1", - "from": "os-tmpdir@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz", + "integrity": "sha1-6bQjoe2vR5iCVi6S7XHXdDoHG24=", + "dev": true }, "user-home": { "version": "1.1.1", - "from": "user-home@>=1.1.1 <2.0.0", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz" + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "dev": true } } }, "is-integer": { "version": "1.0.6", - "from": "is-integer@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/is-integer/-/is-integer-1.0.6.tgz", + "integrity": "sha1-UnOBn62ogNEj4awAqTjnFy3Y2V4=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + }, "dependencies": { "is-finite": { "version": "1.0.1", - "from": "is-finite@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz", + "integrity": "sha1-ZDhgPq6+J5OUj/SkJi7I2z1iWXs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + }, "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=", + "dev": true } } } @@ -3874,38 +5867,52 @@ }, "js-tokens": { "version": "1.0.1", - "from": "js-tokens@1.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-1.0.1.tgz", + "integrity": "sha1-zENaXIuUrRWst5gxQPyAGCyJrq4=", + "dev": true }, "json5": { "version": "0.4.0", - "from": "json5@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz" + "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz", + "integrity": "sha1-BUNS5MTIDIbAkjh31EneF2pzLI0=", + "dev": true }, "lodash": { "version": "3.10.1", - "from": "lodash@>=3.10.0 <4.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true }, "minimatch": { "version": "2.0.10", - "from": "minimatch@>=2.0.3 <3.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true, + "requires": { + "brace-expansion": "^1.0.0" + }, "dependencies": { "brace-expansion": { "version": "1.1.5", - "from": "brace-expansion@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "integrity": "sha1-9bStV04st8zB64Pm/nm47K33pSY=", + "dev": true, + "requires": { + "balanced-match": "^0.4.1", + "concat-map": "0.0.1" + }, "dependencies": { "balanced-match": { "version": "0.4.1", - "from": "balanced-match@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", + "integrity": "sha1-GQU+LgdI6ts3nabAnUVc9eEDkzU=", + "dev": true }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true } } } @@ -3913,117 +5920,187 @@ }, "output-file-sync": { "version": "1.1.2", - "from": "output-file-sync@>=1.1.0 <2.0.0", "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", + "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.4", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.0" + }, "dependencies": { "graceful-fs": { "version": "4.1.4", - "from": "graceful-fs@>=4.1.4 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz", + "integrity": "sha1-7widKIDwM7ARgjzlyPrnmNp3Xb0=", + "dev": true }, "mkdirp": { "version": "0.5.1", - "from": "mkdirp@>=0.5.1 <0.6.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, "dependencies": { "minimist": { "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true } } }, "object-assign": { "version": "4.1.0", - "from": "object-assign@>=4.1.0 <5.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", + "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=", + "dev": true } } }, "path-exists": { "version": "1.0.0", - "from": "path-exists@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz", + "integrity": "sha1-1aiZjrce83p0w06w2eum6HjuoIE=", + "dev": true }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", + "integrity": "sha1-Jj2tpmqz8vsQv3+dJN2PPlcO+RI=", + "dev": true }, "private": { "version": "0.1.6", - "from": "private@>=0.1.6 <0.2.0", - "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz" + "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz", + "integrity": "sha1-VcapdtD5uvuZJIUTUP5HubX7t8E=", + "dev": true }, "regenerator": { "version": "0.8.40", - "from": "regenerator@0.8.40", "resolved": "https://registry.npmjs.org/regenerator/-/regenerator-0.8.40.tgz", + "integrity": "sha1-oORXxY69uuV1yfjNdRJ+k3VkNdg=", + "dev": true, + "requires": { + "commoner": "~0.10.3", + "defs": "~1.1.0", + "esprima-fb": "~15001.1001.0-dev-harmony-fb", + "private": "~0.1.5", + "recast": "0.10.33", + "through": "~2.3.8" + }, "dependencies": { "commoner": { "version": "0.10.4", - "from": "commoner@>=0.10.3 <0.11.0", "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.4.tgz", + "integrity": "sha1-mPMzPdOtOZWWuy04Sng7tyE9aPg=", + "dev": true, + "requires": { + "commander": "^2.5.0", + "detective": "^4.3.1", + "glob": "^5.0.15", + "graceful-fs": "^4.1.2", + "iconv-lite": "^0.4.5", + "mkdirp": "^0.5.0", + "private": "^0.1.6", + "q": "^1.1.2", + "recast": "^0.10.0" + }, "dependencies": { "commander": { "version": "2.9.0", - "from": "commander@>=2.5.0 <3.0.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + }, "dependencies": { "graceful-readlink": { "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true } } }, "detective": { "version": "4.3.1", - "from": "detective@>=4.3.1 <5.0.0", "resolved": "https://registry.npmjs.org/detective/-/detective-4.3.1.tgz", + "integrity": "sha1-n7Bt0e6PDqTbzGB82jnZzh1Pcm8=", + "dev": true, + "requires": { + "acorn": "^1.0.3", + "defined": "^1.0.0" + }, "dependencies": { "acorn": { "version": "1.2.2", - "from": "acorn@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz" + "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", + "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=", + "dev": true }, "defined": { "version": "1.0.0", - "from": "defined@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true } } }, "glob": { "version": "5.0.15", - "from": "glob@>=5.0.15 <6.0.0", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "dependencies": { "inflight": { "version": "1.0.5", - "from": "inflight@>=1.0.4 <2.0.0", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "integrity": "sha1-2zIEzVqd4ubNiQuFxuL2a89PYgo=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0" + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1" + }, "dependencies": { "wrappy": { "version": "1.0.2", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } } @@ -4031,171 +6108,257 @@ }, "graceful-fs": { "version": "4.1.4", - "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz", + "integrity": "sha1-7widKIDwM7ARgjzlyPrnmNp3Xb0=", + "dev": true }, "iconv-lite": { "version": "0.4.13", - "from": "iconv-lite@>=0.4.5 <0.5.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz" + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", + "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", + "dev": true }, "mkdirp": { "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, "dependencies": { "minimist": { "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true } } }, "q": { "version": "1.4.1", - "from": "q@>=1.1.2 <2.0.0", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz" + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true } } }, "defs": { "version": "1.1.1", - "from": "defs@>=1.1.0 <1.2.0", "resolved": "https://registry.npmjs.org/defs/-/defs-1.1.1.tgz", + "integrity": "sha1-siYJ8sehG6ej2xFoBcE5scr/qdI=", + "dev": true, + "requires": { + "alter": "~0.2.0", + "ast-traverse": "~0.1.1", + "breakable": "~1.0.0", + "esprima-fb": "~15001.1001.0-dev-harmony-fb", + "simple-fmt": "~0.1.0", + "simple-is": "~0.2.0", + "stringmap": "~0.2.2", + "stringset": "~0.2.1", + "tryor": "~0.1.2", + "yargs": "~3.27.0" + }, "dependencies": { "alter": { "version": "0.2.0", - "from": "alter@>=0.2.0 <0.3.0", "resolved": "https://registry.npmjs.org/alter/-/alter-0.2.0.tgz", + "integrity": "sha1-x1iICGF1cgNKrmJICvJrHU0cs80=", + "dev": true, + "requires": { + "stable": "~0.1.3" + }, "dependencies": { "stable": { "version": "0.1.5", - "from": "stable@>=0.1.3 <0.2.0" + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.5.tgz", + "integrity": "sha1-CCMvYMcy6YkHhLW+0HNPizKoh7k=", + "dev": true } } }, "ast-traverse": { "version": "0.1.1", - "from": "ast-traverse@>=0.1.1 <0.2.0", - "resolved": "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz" + "resolved": "https://registry.npmjs.org/ast-traverse/-/ast-traverse-0.1.1.tgz", + "integrity": "sha1-ac8rg4bxnc2hux4F1o/jWdiJfeY=", + "dev": true }, "breakable": { "version": "1.0.0", - "from": "breakable@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/breakable/-/breakable-1.0.0.tgz", + "integrity": "sha1-eEp5eRWjjq0nutRWtVcstLuqeME=", + "dev": true }, "simple-fmt": { "version": "0.1.0", - "from": "simple-fmt@>=0.1.0 <0.2.0", - "resolved": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz" + "resolved": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz", + "integrity": "sha1-GRv1ZqWeZTBILLJatTtKjchcOms=", + "dev": true }, "simple-is": { "version": "0.2.0", - "from": "simple-is@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz" + "resolved": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz", + "integrity": "sha1-Krt1qt453rXMgVzhDmGRFkhQuvA=", + "dev": true }, "stringmap": { "version": "0.2.2", - "from": "stringmap@>=0.2.2 <0.3.0", - "resolved": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz" + "resolved": "https://registry.npmjs.org/stringmap/-/stringmap-0.2.2.tgz", + "integrity": "sha1-VWwTeyWPlCuHdvWy71gqoGnX0bE=", + "dev": true }, "stringset": { "version": "0.2.1", - "from": "stringset@>=0.2.1 <0.3.0", - "resolved": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz" + "resolved": "https://registry.npmjs.org/stringset/-/stringset-0.2.1.tgz", + "integrity": "sha1-7yWcTjSTRDd/zRyRPdLoSMnAQrU=", + "dev": true }, "tryor": { "version": "0.1.2", - "from": "tryor@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz" + "resolved": "https://registry.npmjs.org/tryor/-/tryor-0.1.2.tgz", + "integrity": "sha1-gUXkynyv9ArN48z5Rui4u3W0Fys=", + "dev": true }, "yargs": { "version": "3.27.0", - "from": "yargs@>=3.27.0 <3.28.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.27.0.tgz", + "integrity": "sha1-ISBUaTFuk5Ex1Z8toMbX+YIh6kA=", + "dev": true, + "requires": { + "camelcase": "^1.2.1", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "os-locale": "^1.4.0", + "window-size": "^0.1.2", + "y18n": "^3.2.0" + }, "dependencies": { "camelcase": { "version": "1.2.1", - "from": "camelcase@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true }, "cliui": { "version": "2.1.0", - "from": "cliui@>=2.1.0 <3.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + }, "dependencies": { "center-align": { "version": "0.1.3", - "from": "center-align@>=0.1.1 <0.2.0", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" + }, "dependencies": { "align-text": { "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + }, "dependencies": { "kind-of": { "version": "3.0.3", - "from": "kind-of@>=3.0.2 <4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", + "integrity": "sha1-xhYIdH2BWwNiVW2zJ2Nip6OK3tM=", + "dev": true, + "requires": { + "is-buffer": "^1.0.2" + }, "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", + "integrity": "sha1-24l/w/esotUN6UtsjCiWpHcWJ68=", + "dev": true } } }, "longest": { "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", + "integrity": "sha1-ZOwMkeD0tHX5DVtkNlHj5uW2wtU=", + "dev": true } } }, "lazy-cache": { "version": "1.0.4", - "from": "lazy-cache@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true } } }, "right-align": { "version": "0.1.3", - "from": "right-align@>=0.1.1 <0.2.0", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "^0.1.1" + }, "dependencies": { "align-text": { "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" + }, "dependencies": { "kind-of": { "version": "3.0.3", - "from": "kind-of@>=3.0.2 <4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", + "integrity": "sha1-xhYIdH2BWwNiVW2zJ2Nip6OK3tM=", + "dev": true, + "requires": { + "is-buffer": "^1.0.2" + }, "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", + "integrity": "sha1-24l/w/esotUN6UtsjCiWpHcWJ68=", + "dev": true } } }, "longest": { "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", + "integrity": "sha1-ZOwMkeD0tHX5DVtkNlHj5uW2wtU=", + "dev": true } } } @@ -4203,29 +6366,41 @@ }, "wordwrap": { "version": "0.0.2", - "from": "wordwrap@0.0.2" + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true } } }, "decamelize": { "version": "1.2.0", - "from": "decamelize@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true }, "os-locale": { "version": "1.4.0", - "from": "os-locale@>=1.4.0 <2.0.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + }, "dependencies": { "lcid": { "version": "1.0.0", - "from": "lcid@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + }, "dependencies": { "invert-kv": { "version": "1.0.0", - "from": "invert-kv@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true } } } @@ -4233,13 +6408,15 @@ }, "window-size": { "version": "0.1.4", - "from": "window-size@>=0.1.2 <0.2.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz" + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "dev": true }, "y18n": { "version": "3.2.1", - "from": "y18n@>=3.2.0 <4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz" + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true } } } @@ -4247,74 +6424,109 @@ }, "esprima-fb": { "version": "15001.1001.0-dev-harmony-fb", - "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0", - "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz" + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz", + "integrity": "sha1-Q761fsJujPI3092LM+QlM1d/Jlk=", + "dev": true }, "recast": { "version": "0.10.33", - "from": "recast@0.10.33", "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.33.tgz", + "integrity": "sha1-lCgI96oBbx+nFCxGHX5XBKqo1pc=", + "dev": true, + "requires": { + "ast-types": "0.8.12", + "esprima-fb": "~15001.1001.0-dev-harmony-fb", + "private": "~0.1.5", + "source-map": "~0.5.0" + }, "dependencies": { "ast-types": { "version": "0.8.12", - "from": "ast-types@0.8.12", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz" + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.12.tgz", + "integrity": "sha1-oNkOQ1G7iHcWyD/WN+v4GK9K38w=", + "dev": true } } }, "through": { "version": "2.3.8", - "from": "through@>=2.3.8 <2.4.0", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true } } }, "regexpu": { "version": "1.3.0", - "from": "regexpu@>=1.3.0 <2.0.0", "resolved": "https://registry.npmjs.org/regexpu/-/regexpu-1.3.0.tgz", + "integrity": "sha1-5TTcmRqeWEYFDJjebX3UpVyeoW0=", + "dev": true, + "requires": { + "esprima": "^2.6.0", + "recast": "^0.10.10", + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + }, "dependencies": { "esprima": { "version": "2.7.2", - "from": "esprima@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz", + "integrity": "sha1-9DvlQ2CZhOrkTJM6xjNSpq818zk=", + "dev": true }, "recast": { "version": "0.10.43", - "from": "recast@>=0.10.10 <0.11.0", "resolved": "https://registry.npmjs.org/recast/-/recast-0.10.43.tgz", + "integrity": "sha1-uV1Q9tYHYaX2JS4V2AZ4FoSRzn8=", + "dev": true, + "requires": { + "ast-types": "0.8.15", + "esprima-fb": "~15001.1001.0-dev-harmony-fb", + "private": "~0.1.5", + "source-map": "~0.5.0" + }, "dependencies": { - "esprima-fb": { - "version": "15001.1001.0-dev-harmony-fb", - "from": "esprima-fb@>=15001.1001.0-dev-harmony-fb <15001.1002.0", - "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz" - }, "ast-types": { "version": "0.8.15", - "from": "ast-types@0.8.15", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz" + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz", + "integrity": "sha1-ju8IJ/BN/w7IhXupJavj/qYZTlI=", + "dev": true + }, + "esprima-fb": { + "version": "15001.1001.0-dev-harmony-fb", + "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz", + "integrity": "sha1-Q761fsJujPI3092LM+QlM1d/Jlk=", + "dev": true } } }, "regenerate": { "version": "1.3.1", - "from": "regenerate@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.1.tgz" + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.1.tgz", + "integrity": "sha1-AwAgOl0v3PiRFtzoQnXQEfWQPzM=", + "dev": true }, "regjsgen": { "version": "0.2.0", - "from": "regjsgen@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz" + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true }, "regjsparser": { "version": "0.1.5", - "from": "regjsparser@>=0.1.4 <0.2.0", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, "dependencies": { "jsesc": { "version": "0.5.0", - "from": "jsesc@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true } } } @@ -4322,18 +6534,27 @@ }, "repeating": { "version": "1.1.3", - "from": "repeating@>=1.1.2 <2.0.0", "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", + "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + }, "dependencies": { "is-finite": { "version": "1.0.1", - "from": "is-finite@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.1.tgz", + "integrity": "sha1-ZDhgPq6+J5OUj/SkJi7I2z1iWXs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + }, "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", + "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=", + "dev": true } } } @@ -4341,38 +6562,51 @@ }, "resolve": { "version": "1.1.7", - "from": "resolve@>=1.1.6 <2.0.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true }, "shebang-regex": { "version": "1.0.0", - "from": "shebang-regex@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true }, "slash": { "version": "1.0.0", - "from": "slash@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true }, "source-map": { "version": "0.5.6", - "from": "source-map@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true }, "source-map-support": { "version": "0.2.10", - "from": "source-map-support@>=0.2.10 <0.3.0", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.2.10.tgz", + "integrity": "sha1-6lo5AKHByyUJagrozFwrSxDe09w=", + "dev": true, + "requires": { + "source-map": "0.1.32" + }, "dependencies": { "source-map": { "version": "0.1.32", - "from": "source-map@0.1.32", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.32.tgz", + "integrity": "sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + }, "dependencies": { "amdefine": { "version": "1.0.0", - "from": "amdefine@>=0.0.4", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz", + "integrity": "sha1-/RdHRwDLXMnCtwnwvp0jzjwZjDM=", + "dev": true } } } @@ -4380,101 +6614,140 @@ }, "to-fast-properties": { "version": "1.0.2", - "from": "to-fast-properties@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz", + "integrity": "sha1-8/XAw7pymafvmUJ+RGMyV63kMyA=", + "dev": true }, "trim-right": { "version": "1.0.1", - "from": "trim-right@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true }, "try-resolve": { "version": "1.0.1", - "from": "try-resolve@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/try-resolve/-/try-resolve-1.0.1.tgz", + "integrity": "sha1-z95vq9ctY+V5fPqrhzq76OcA6RI=", + "dev": true } } }, "esformatter-ignore": { "version": "0.1.3", - "from": "esformatter-ignore@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/esformatter-ignore/-/esformatter-ignore-0.1.3.tgz" + "resolved": "https://registry.npmjs.org/esformatter-ignore/-/esformatter-ignore-0.1.3.tgz", + "integrity": "sha1-BNO4db+knd4ATMWN9va7w8BWfx4=", + "dev": true }, "extend": { "version": "2.0.1", - "from": "extend@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/extend/-/extend-2.0.1.tgz" + "resolved": "https://registry.npmjs.org/extend/-/extend-2.0.1.tgz", + "integrity": "sha1-HugBBonnOV/5RIJByYZSvHWagmA=", + "dev": true }, "fresh-falafel": { "version": "1.2.0", - "from": "fresh-falafel@>=1.2.0 <2.0.0", "resolved": "https://registry.npmjs.org/fresh-falafel/-/fresh-falafel-1.2.0.tgz", + "integrity": "sha1-WWbe6V+zXSopsS0vJRaLFyJeS2w=", + "dev": true, + "requires": { + "acorn": "^1.0.3", + "foreach": "^2.0.5", + "isarray": "0.0.1", + "object-keys": "^1.0.6" + }, "dependencies": { "acorn": { "version": "1.2.2", - "from": "acorn@>=1.0.3 <2.0.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz" + "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", + "integrity": "sha1-yM4n3grMdtiW0rH6099YjZ6C8BQ=", + "dev": true }, "foreach": { "version": "2.0.5", - "from": "foreach@>=2.0.5 <3.0.0", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz" + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true }, "isarray": { "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true }, "object-keys": { "version": "1.0.11", - "from": "object-keys@>=1.0.6 <2.0.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz" + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true } } }, "js-beautify": { "version": "1.6.3", - "from": "js-beautify@>=1.5.10 <2.0.0", "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.6.3.tgz", + "integrity": "sha1-1/HrUVzsFsmfDXS/9f1vl2fySjc=", + "dev": true, + "requires": { + "config-chain": "~1.1.5", + "mkdirp": "~0.5.0", + "nopt": "~3.0.1" + }, "dependencies": { "config-chain": { "version": "1.1.10", - "from": "config-chain@>=1.1.5 <1.2.0", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.10.tgz", + "integrity": "sha1-f8OD3g/MhNcRy0Zb0XZXnK1hI0Y=", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, "dependencies": { - "proto-list": { - "version": "1.2.4", - "from": "proto-list@>=1.2.1 <1.3.0", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz" - }, "ini": { "version": "1.3.4", - "from": "ini@>=1.3.4 <2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz" + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "dev": true + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true } } }, "mkdirp": { "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, "dependencies": { "minimist": { "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true } } }, "nopt": { "version": "3.0.6", - "from": "nopt@>=3.0.1 <3.1.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + }, "dependencies": { "abbrev": { "version": "1.0.9", - "from": "abbrev@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true } } } @@ -4484,267 +6757,378 @@ }, "esformatter-literal-notation": { "version": "1.0.1", - "from": "esformatter-literal-notation@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/esformatter-literal-notation/-/esformatter-literal-notation-1.0.1.tgz", + "integrity": "sha1-cQ57QgF1/j9+WvrVu60ykQOELi8=", + "dev": true, + "requires": { + "rocambole": "^0.3.6", + "rocambole-token": "^1.2.1" + }, "dependencies": { "rocambole": { "version": "0.3.6", - "from": "rocambole@>=0.3.6 <0.4.0", "resolved": "https://registry.npmjs.org/rocambole/-/rocambole-0.3.6.tgz", + "integrity": "sha1-Teu/WUMUS8e2AG2Vvo+swLdDUqc=", + "dev": true, + "requires": { + "esprima": "~1.0" + }, "dependencies": { "esprima": { "version": "1.0.4", - "from": "esprima@>=1.0.0 <1.1.0" + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", + "dev": true } } }, "rocambole-token": { "version": "1.2.1", - "from": "rocambole-token@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/rocambole-token/-/rocambole-token-1.2.1.tgz" + "resolved": "https://registry.npmjs.org/rocambole-token/-/rocambole-token-1.2.1.tgz", + "integrity": "sha1-x4XfdCjcPLJ614lwR71SOMwHDTU=", + "dev": true } } }, "esformatter-quotes": { "version": "1.1.0", - "from": "esformatter-quotes@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/esformatter-quotes/-/esformatter-quotes-1.1.0.tgz" + "resolved": "https://registry.npmjs.org/esformatter-quotes/-/esformatter-quotes-1.1.0.tgz", + "integrity": "sha1-4ixsRFx/MGBB2BybnlH8psv6yoI=", + "dev": true }, "esformatter-semicolon-first": { "version": "1.1.0", - "from": "esformatter-semicolon-first@>=1.1.0 <2.0.0", "resolved": "https://registry.npmjs.org/esformatter-semicolon-first/-/esformatter-semicolon-first-1.1.0.tgz", + "integrity": "sha1-63UwrHX20ANxEFZeVfGzAycuDpM=", + "dev": true, + "requires": { + "espree": "^2.0.3", + "rocambole": ">=0.6.0 <2.0", + "rocambole-token": "^1.2.1" + }, "dependencies": { "espree": { "version": "2.2.5", - "from": "espree@>=2.0.3 <3.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz" + "resolved": "https://registry.npmjs.org/espree/-/espree-2.2.5.tgz", + "integrity": "sha1-32kbkxCIlAKuspzAZnCMVmkLhUs=", + "dev": true }, "rocambole": { "version": "0.7.0", - "from": "rocambole@>=0.6.0 <2.0.0", "resolved": "https://registry.npmjs.org/rocambole/-/rocambole-0.7.0.tgz", + "integrity": "sha1-9seVBVF9xCtvuECEK4uVOw+WhYU=", + "dev": true, + "requires": { + "esprima": "^2.1" + }, "dependencies": { "esprima": { "version": "2.7.2", - "from": "esprima@>=2.1.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz" + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.2.tgz", + "integrity": "sha1-9DvlQ2CZhOrkTJM6xjNSpq818zk=", + "dev": true } } }, "rocambole-token": { "version": "1.2.1", - "from": "rocambole-token@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/rocambole-token/-/rocambole-token-1.2.1.tgz" + "resolved": "https://registry.npmjs.org/rocambole-token/-/rocambole-token-1.2.1.tgz", + "integrity": "sha1-x4XfdCjcPLJ614lwR71SOMwHDTU=", + "dev": true } } }, "esformatter-spaced-lined-comment": { "version": "2.0.1", - "from": "esformatter-spaced-lined-comment@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/esformatter-spaced-lined-comment/-/esformatter-spaced-lined-comment-2.0.1.tgz" + "resolved": "https://registry.npmjs.org/esformatter-spaced-lined-comment/-/esformatter-spaced-lined-comment-2.0.1.tgz", + "integrity": "sha1-3F80B/k8KV4eVkRr00RWDaXm3Kw=", + "dev": true }, "minimist": { "version": "1.2.0", - "from": "minimist@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true }, "stdin": { "version": "0.0.1", - "from": "stdin@0.0.1", - "resolved": "https://registry.npmjs.org/stdin/-/stdin-0.0.1.tgz" + "resolved": "https://registry.npmjs.org/stdin/-/stdin-0.0.1.tgz", + "integrity": "sha1-0wQZgarsPf28d6GzjWNy449ftx4=", + "dev": true } } } } }, - "supertest": { + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string_decoder": { "version": "1.2.0", - "from": "supertest@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "superagent": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.0.5.tgz", + "integrity": "sha512-5fnihpNqJfDJHxeIkqlXKFDOW5t4WUFV8Ba1erxdWT0RySqjgAW6Hska0xNYEpAfaoMzubn77GROm/XlkssOoQ==", + "dev": true, + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "form-data": "^2.3.3", + "formidable": "^1.2.1", + "methods": "^1.1.2", + "mime": "^2.4.2", + "qs": "^6.7.0", + "readable-stream": "^3.3.0", + "semver": "^6.0.0" + }, "dependencies": { - "superagent": { - "version": "1.8.3", - "from": "superagent@>=1.7.2 <2.0.0", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-1.8.3.tgz", - "dependencies": { - "qs": { - "version": "2.3.3", - "from": "qs@2.3.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz" - }, - "formidable": { - "version": "1.0.17", - "from": "formidable@>=1.0.14 <1.1.0", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.17.tgz" - }, - "mime": { - "version": "1.3.4", - "from": "mime@1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" - }, - "component-emitter": { - "version": "1.2.1", - "from": "component-emitter@>=1.2.0 <1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz" - }, - "cookiejar": { - "version": "2.0.6", - "from": "cookiejar@2.0.6", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.0.6.tgz" - }, - "debug": { - "version": "2.2.0", - "from": "debug@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "dependencies": { - "ms": { - "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" - } - } - }, - "reduce-component": { - "version": "1.0.1", - "from": "reduce-component@1.0.1", - "resolved": "https://registry.npmjs.org/reduce-component/-/reduce-component-1.0.1.tgz" - }, - "extend": { - "version": "3.0.0", - "from": "extend@3.0.0", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" - }, - "form-data": { - "version": "1.0.0-rc3", - "from": "form-data@1.0.0-rc3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc3.tgz", - "dependencies": { - "combined-stream": { - "version": "1.0.5", - "from": "combined-stream@>=1.0.5 <2.0.0", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "dependencies": { - "delayed-stream": { - "version": "1.0.0", - "from": "delayed-stream@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - } - } - }, - "mime-types": { - "version": "2.1.11", - "from": "mime-types@>=2.1.3 <3.0.0", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz", - "dependencies": { - "mime-db": { - "version": "1.23.0", - "from": "mime-db@>=1.23.0 <1.24.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz" - } - } - } - } - }, - "readable-stream": { - "version": "1.0.27-1", - "from": "readable-stream@1.0.27-1", - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - }, - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, - "string_decoder": { - "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0" - }, - "inherits": { - "version": "2.0.1", - "from": "inherits@>=2.0.1 <2.1.0" - } - } - } + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "mime": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.3.tgz", + "integrity": "sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "semver": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz", + "integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==", + "dev": true + } + } + }, + "supertest": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-4.0.2.tgz", + "integrity": "sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^3.8.3" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" } }, - "methods": { - "version": "1.1.2", - "from": "methods@>=1.1.2 <1.2.0", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + } } } }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, "swagger-parser": { "version": "3.4.1", - "from": "swagger-parser@>=3.4.0 <4.0.0", "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-3.4.1.tgz", + "integrity": "sha1-ApBSnbriVNF4tEKpXfYNI9FCMB0=", + "requires": { + "call-me-maybe": "^1.0.1", + "debug": "^2.2.0", + "es6-promise": "^3.0.2", + "json-schema-ref-parser": "^1.4.1", + "ono": "^2.0.1", + "swagger-methods": "^1.0.0", + "swagger-schema-official": "2.0.0-bab6bed", + "z-schema": "^3.16.1" + }, "dependencies": { "call-me-maybe": { "version": "1.0.1", - "from": "call-me-maybe@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" }, "debug": { "version": "2.2.0", - "from": "debug@2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "requires": { + "ms": "0.7.1" + }, "dependencies": { "ms": { "version": "0.7.1", - "from": "ms@0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz" + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" } } }, "es6-promise": { "version": "3.2.1", - "from": "es6-promise@>=3.0.2 <4.0.0", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz" + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", + "integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q=" }, "json-schema-ref-parser": { "version": "1.4.1", - "from": "json-schema-ref-parser@>=1.4.1 <2.0.0", - "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-1.4.1.tgz" + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-1.4.1.tgz", + "integrity": "sha1-wMLkOL8HlnI7AkUbrovH3Qs3/tA=", + "requires": { + "call-me-maybe": "^1.0.1", + "debug": "^2.2.0", + "es6-promise": "^3.0.2", + "js-yaml": "^3.4.6", + "ono": "^2.0.1" + } }, "ono": { "version": "2.2.1", - "from": "ono@>=2.0.1 <3.0.0", - "resolved": "https://registry.npmjs.org/ono/-/ono-2.2.1.tgz" + "resolved": "https://registry.npmjs.org/ono/-/ono-2.2.1.tgz", + "integrity": "sha1-ci/H6EKf9zOIeoDnQ/s4u9mFsAM=" }, "swagger-methods": { "version": "1.0.0", - "from": "swagger-methods@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-1.0.0.tgz" + "resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-1.0.0.tgz", + "integrity": "sha1-s5x3lX0wWmU1wKHgFQgRhbmdYfw=" }, "swagger-schema-official": { "version": "2.0.0-bab6bed", - "from": "swagger-schema-official@2.0.0-bab6bed", - "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz" + "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", + "integrity": "sha1-cAcEaNbSl3ylI3suUZyn0Gouo/0=" }, "z-schema": { "version": "3.17.0", - "from": "z-schema@>=3.16.1 <4.0.0", "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-3.17.0.tgz", + "integrity": "sha1-RCs4+denr3rke/z8NWhz6GFq0bc=", + "requires": { + "commander": "^2.7.1", + "lodash.get": "^4.1.2", + "request": "^2.54.0", + "validator": "^5.0.0" + }, "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "optional": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + }, + "dependencies": { + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "optional": true + } + } + }, "lodash.get": { "version": "4.3.0", - "from": "lodash.get@>=4.1.2 <5.0.0", "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.3.0.tgz", + "integrity": "sha1-03Zf+/dw1OPSu09vQJlc6qIj428=", + "requires": { + "lodash._stringtopath": "~4.8.0" + }, "dependencies": { "lodash._stringtopath": { "version": "4.8.0", - "from": "lodash._stringtopath@>=4.8.0 <4.9.0", "resolved": "https://registry.npmjs.org/lodash._stringtopath/-/lodash._stringtopath-4.8.0.tgz", + "integrity": "sha1-lBvPDmQmbl/B1m/tCmlZVExXaCQ=", + "requires": { + "lodash._basetostring": "~4.12.0" + }, "dependencies": { "lodash._basetostring": { "version": "4.12.0", - "from": "lodash._basetostring@>=4.12.0 <4.13.0", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz" + "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-4.12.0.tgz", + "integrity": "sha1-kyfJ3FFYhmt/pLnUL0Y45XZt2d8=" } } } @@ -4752,41 +7136,185 @@ }, "validator": { "version": "5.4.0", - "from": "validator@>=5.0.0 <6.0.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-5.4.0.tgz" - }, - "commander": { - "version": "2.9.0", - "from": "commander@>=2.7.1 <3.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "dependencies": { - "graceful-readlink": { - "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" - } - } + "resolved": "https://registry.npmjs.org/validator/-/validator-5.4.0.tgz", + "integrity": "sha1-RCDdyf3CCU2QS4UwPhtKE4+E5x4=" } } } } }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==" + }, + "uglify-js": { + "version": "3.5.15", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.15.tgz", + "integrity": "sha512-fe7aYFotptIddkwcm6YuA0HmknBZ52ZzOsUxZEdhhkSsz7RfjHDX2QDxwKTiv4JQ5t5NhfmpgAK+J7LiDhKSqg==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml2js": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.0.tgz", + "integrity": "sha1-Ek/EEUtBKcgQgA7LKshs8lRiy5o=", + "requires": { + "sax": "0.5.x", + "xmlbuilder": ">=0.4.2" + } + }, "xmlbuilder": { "version": "4.2.1", - "from": "xmlbuilder@>=4.2.1 <5.0.0", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", + "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", + "requires": { + "lodash": "^4.0.0" + }, "dependencies": { "lodash": { - "version": "4.13.1", - "from": "lodash@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz" + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" } } }, "xmldom": { "version": "0.1.22", - "from": "xmldom@>=0.1.22 <0.2.0", - "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.22.tgz" + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.22.tgz", + "integrity": "sha1-EN5OXpZJgfA8jMcvrcCNFLbDqiY=" + }, + "yaml": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-0.2.3.tgz", + "integrity": "sha1-tUUOkudu82td0k42YAkeuu7z5cc=" } } } diff --git a/apigee-cf-service-broker/package.json b/apigee-cf-service-broker/package.json index 438c4fa..5cf07b1 100644 --- a/apigee-cf-service-broker/package.json +++ b/apigee-cf-service-broker/package.json @@ -4,10 +4,14 @@ "description": "apigee service broker for cloud foundry", "main": "index.js", "scripts": { - "start": "node server.js", - "test": "NODE_ENV=TEST istanbul cover --report cobertura --report html _mocha -- --recursive test -R spec", + "start": "NODE_ENV=production node server.js", + "start:dev": "node server.js", + "test": "NODE_ENV=TEST NODE_TLS_REJECT_UNAUTHORIZED=0 node --harmony ./node_modules/.bin/istanbul cover --report cobertura --report html ./node_modules/.bin/_mocha -- --recursive test/api.js -R spec", "posttest": "node scripts/genCoverageBadge.js" }, + "engines": { + "node": "10.12.0" + }, "repository": { "type": "git", "url": "git+https://github.com/apigee/pivotal-cf-apigee.git" @@ -19,33 +23,42 @@ }, "homepage": "https://github.com/apigee/pivotal-cf-apigee#readme", "dependencies": { + "apigee-auth": "^2.0.1", "async": "^1.5.0", "basic-auth": "^1.0.3", - "body-parser": "1.12.4", + "bluebird": "3.0.6", + "body-parser": "^1.19.0", "bunyan": "^1.5.1", - "cfenv": "^1.0.3", + "cfenv": "^1.2.2", + "command-line-args": "^5.1.1", + "dotenv": "^8.0.0", + "dtrace-provider": "^0.8.7", "es6-template-strings": "^2.0.0", - "express": "^4.13.3", + "express": "^4.17.1", "express-jsonschema": "^1.1.0", - "js-yaml": "^3.5.3", + "js-yaml": "^3.13.1", + "json-to-pretty-yaml": "^1.2.2", "jszip": "^2.5.0", "nconf": "^0.8.2", - "request": "^2.67.0", + "request": "^2.88.0", + "restler": "3.4.0", "swagger-parser": "^3.4.0", - "uuid":"^3.3.2", + "uuid": "^3.3.2", "xmlbuilder": "^4.2.1", "xmldom": "^0.1.22" }, "devDependencies": { "chai": "^3.4.1", + "chai-http": "^4.3.0", "chai-things": "^0.2.0", - "istanbul": "^0.4.4", + "istanbul": "^1.1.0-alpha.1", "istanbul-cobertura-badger": "^1.2.1", "mocha": "^2.4.5", - "nock": "^7.0.2", + "nock": "^10.0.6", "should": "^8.2.1", "standard": "^5.4.1", - "supertest": "^1.1.0" + "superagent": "^5.0.5", + "supertest": "^4.0.2" }, "standard": { "ignore": [ @@ -56,10 +69,5 @@ "describe", "it" ] - }, - "engines":{ - "node": "^10.0.0", - "npm": "^6.9.0" } - } diff --git a/apigee-cf-service-broker/policy_templates/cache/responseCache.js b/apigee-cf-service-broker/policy_templates/cache/responseCache.js index e7a98ba..fbf083f 100644 --- a/apigee-cf-service-broker/policy_templates/cache/responseCache.js +++ b/apigee-cf-service-broker/policy_templates/cache/responseCache.js @@ -15,7 +15,7 @@ */ var builder = require('xmlbuilder') -var random = require('../../util/random.js') +var random = require('../../lib/helpers/random.js') module.exports = { responseCacheTemplate: responseCacheTemplate, diff --git a/apigee-cf-service-broker/policy_templates/mediation/jsonToXml.js b/apigee-cf-service-broker/policy_templates/mediation/jsonToXml.js index faa547b..042ede5 100644 --- a/apigee-cf-service-broker/policy_templates/mediation/jsonToXml.js +++ b/apigee-cf-service-broker/policy_templates/mediation/jsonToXml.js @@ -15,7 +15,7 @@ */ var builder = require('xmlbuilder') -var random = require('../../util/random.js') +var random = require('../../lib/helpers/random.js') module.exports = { jsonToXmlTemplate: jsonToXmlTemplate, diff --git a/apigee-cf-service-broker/policy_templates/mediation/xmlToJson.js b/apigee-cf-service-broker/policy_templates/mediation/xmlToJson.js index 755d527..d4033bf 100644 --- a/apigee-cf-service-broker/policy_templates/mediation/xmlToJson.js +++ b/apigee-cf-service-broker/policy_templates/mediation/xmlToJson.js @@ -15,7 +15,7 @@ */ var builder = require('xmlbuilder') -var random = require('../../util/random.js') +var random = require('../../lib/helpers/random.js') module.exports = { xmlToJsonTemplate: xmlToJsonTemplate, diff --git a/apigee-cf-service-broker/policy_templates/quota/quota.js b/apigee-cf-service-broker/policy_templates/quota/quota.js index c57620f..ae8e629 100644 --- a/apigee-cf-service-broker/policy_templates/quota/quota.js +++ b/apigee-cf-service-broker/policy_templates/quota/quota.js @@ -15,7 +15,7 @@ */ var builder = require('xmlbuilder') -var random = require('../../util/random.js') +var random = require('../../lib/helpers/random.js') module.exports = { quotaTemplate: quotaTemplate, diff --git a/apigee-cf-service-broker/policy_templates/security/apikey.js b/apigee-cf-service-broker/policy_templates/security/apikey.js index aa18504..614cb57 100644 --- a/apigee-cf-service-broker/policy_templates/security/apikey.js +++ b/apigee-cf-service-broker/policy_templates/security/apikey.js @@ -15,7 +15,7 @@ */ var builder = require('xmlbuilder') -var random = require('../../util/random.js') +var random = require('../../lib/helpers/random.js') module.exports = { apiKeyTemplate: apiKeyTemplate, diff --git a/apigee-cf-service-broker/policy_templates/security/verifyAccessToken.js b/apigee-cf-service-broker/policy_templates/security/verifyAccessToken.js index 0aa27d5..d10ad3c 100644 --- a/apigee-cf-service-broker/policy_templates/security/verifyAccessToken.js +++ b/apigee-cf-service-broker/policy_templates/security/verifyAccessToken.js @@ -15,7 +15,7 @@ */ var builder = require('xmlbuilder') -var random = require('../../util/random.js') +var random = require('../../lib/helpers/random.js') module.exports = { verifyAccessTokenTemplate: verifyAccessTokenTemplate, diff --git a/apigee-cf-service-broker/scripts/genCoverageBadge.js b/apigee-cf-service-broker/scripts/genCoverageBadge.js index 9b55e7b..65204e2 100755 --- a/apigee-cf-service-broker/scripts/genCoverageBadge.js +++ b/apigee-cf-service-broker/scripts/genCoverageBadge.js @@ -16,7 +16,7 @@ var badger = require('istanbul-cobertura-badger') var path = require('path') -var logger = require('../helpers/logger') +var logger = require('../lib/helpers/logger') var opts = { destinationDir: path.resolve(__dirname, '..', 'test'), // REQUIRED PARAMETER! istanbulReportFile: path.resolve(__dirname, '..', 'coverage', 'cobertura-coverage.xml'), diff --git a/apigee-cf-service-broker/server.js b/apigee-cf-service-broker/server.js index 7bd53fb..590e261 100644 --- a/apigee-cf-service-broker/server.js +++ b/apigee-cf-service-broker/server.js @@ -14,29 +14,30 @@ * limitations under the License. */ - -'use strict' - -var express = require('express') -var api = require('./api/api') -var catalog = require('./api/catalog') -var service_instances = require('./api/service_instances') -var bodyParser = require('body-parser') -var logger = require('./helpers/logger') -var util = require('util') +// const fs = require('fs') +// const https = require('https'); +const express = require('express') +const bodyParser = require('body-parser') +const api = require('./lib/controllers/api/api') +const catalog = require('./lib/controllers/api/catalog') +const serviceInstances = require('./lib/controllers/api/service-instances') +const logger = require('./lib/helpers/logger') +const config = require('./config/environment') // restrict to SSL in CF -function enforceTLS (req, res, next) { - var proto = req.get('X-forwarded-proto') +const enforceTLS = (req, res, next) => { + let proto = req.get('X-forwarded-proto') + if (process.env.NODE_ENV === 'TEST') { // TODO: would be nice to really test ssl locally // if (req.secure) proto = 'https' proto = 'https' } + if (proto !== 'https') { res.status(403) - var loggerError = logger.ERR_REQ_INVALID_PROTOCOL() - var responseData = { + const loggerError = logger.ERR_REQ_INVALID_PROTOCOL() + const responseData = { msg: loggerError.message } res.json(responseData) @@ -45,18 +46,18 @@ function enforceTLS (req, res, next) { } } -var app = express() +const app = express() app.use(bodyParser.json()) app.use('/', enforceTLS, api) app.use('/v2/catalog', enforceTLS, catalog) -app.use('/v2/service_instances/', enforceTLS, service_instances) +app.use('/v2/service_instances/', enforceTLS, serviceInstances) // schema validation -app.use(function (err, req, res, next) { - var responseData +app.use((err, req, res, next) => { + let responseData if (err.name === 'JsonSchemaValidation') { - var loggerError = logger.ERR_REQ_JSON_SCHEMA_FAIL(err) + const loggerError = logger.ERR_REQ_JSON_SCHEMA_FAIL(err) res.status(400) responseData = { msg: loggerError.message, @@ -70,7 +71,14 @@ app.use(function (err, req, res, next) { } }) -var port = process.env.PORT || 8888 -app.listen(port) -logger.log.info(util.format('Listening on port %s', port)) +// https.createServer({ +// key: fs.readFileSync('./server.key'), +// cert: fs.readFileSync('./server.cert') +// }, app) +// .listen(config.port); + +app.listen(config.port) + +logger.log.info(`Listening on port ${config.port}`) + module.exports = app diff --git a/apigee-cf-service-broker/test/coverage.svg b/apigee-cf-service-broker/test/coverage.svg index b4101f2..d7585e5 100644 --- a/apigee-cf-service-broker/test/coverage.svg +++ b/apigee-cf-service-broker/test/coverage.svg @@ -2,6 +2,6 @@ 400 Bad Request

400 Bad Request

-
cloudflare-nginx
+
cloudflare
diff --git a/apigee-cf-service-broker/test/helpers/api_mocks.js b/apigee-cf-service-broker/test/helpers/api_mocks.js index 240a554..ee1f5cc 100644 --- a/apigee-cf-service-broker/test/helpers/api_mocks.js +++ b/apigee-cf-service-broker/test/helpers/api_mocks.js @@ -15,7 +15,13 @@ */ var nock = require('nock') -var config = require('../../helpers/config') +var config = require('../../config/environment') +const { LOGIN_ENDPOINT, CF_API_URL, APPS_INTERNAL_DOMAIN } = require('../../lib/providers/cf-binder') +const openApiJson = require('./openApi.json') +const fs = require('fs') +const path = require('path') +const openApiYaml = fs.readFileSync(path.resolve('./test/helpers/openApi.yaml')) + /* As per NOCK - works only once per API call */ // Auth Fail Apigee - Nock Interceptor @@ -24,6 +30,7 @@ nock(config.default.get('APIGEE_MGMT_API_URL')) .times(6) .reply(401) // Auth Success Apigee - Nock Interceptor + nock(config.default.get('APIGEE_MGMT_API_URL')) .get('/organizations/cdmo') .times(6) @@ -59,12 +66,28 @@ nock(config.default.get('APIGEE_MGMT_API_URL')) // Apigee Upload Proxy nock - edgemicro nock(config.default.get('APIGEE_MGMT_API_URL')) -.post('/organizations/cdmo/apis?action=import&name=edgemicro_cf-route-url-here', /.*/) -.times(6) -.reply(201, [ - 'default', - 'secure' -]) + .post('/organizations/cdmo/apis?action=import&name=edgemicro_cf-route-url-here', /.*/) + .times(6) + .reply(201, [ + 'default', + 'secure' + ]) + +nock(config.default.get('APIGEE_MGMT_API_URL')) + .post('/organizations/cdmo/apis?action=import&name=edgemicro_target_app_route-here', /.*/) + .times(6) + .reply(201, [ + 'default', + 'secure' + ]) + +nock(config.default.get('APIGEE_MGMT_API_URL')) + .post('/organizations/cdmo/apis?action=import&name=edgemicro_app-name-here.apps.pcf24.apigee.xyz', /.*/) + .times(6) + .reply(201, [ + 'default', + 'secure' + ]) // Apigee Upload Proxy nock nock(config.default.get('APIGEE_MGMT_API_URL')) @@ -74,23 +97,79 @@ nock(config.default.get('APIGEE_MGMT_API_URL')) 'default', 'secure' ]) +nock(config.default.get('APIGEE_MGMT_API_URL')) + .post('/organizations/cdmo/apis?action=import&name=cf-bind_resource-route-url-here.com', /.*/) + .times(6) + .reply(201, [ + 'default', + 'secure' + ]) // Apigee Get Proxy Details Nock nock(config.default.get('APIGEE_MGMT_API_URL')) -.get('/organizations/cdmo/apis/edgemicro_cf-route-url-here') -.times(6) -.reply(200, { - metaData: { - createdAt: 1453098892108, - createdBy: 'xx@xx.com', - lastModifiedAt: 1453099158391, - lastModifiedBy: 'xx@xx.com' - }, - name: 'cf-route-url-here', - revision: [ - '1' - ] -}) + .get('/organizations/cdmo/apis/edgemicro_cf-route-url-here') + .times(6) + .reply(200, { + metaData: { + createdAt: 1453098892108, + createdBy: 'xx@xx.com', + lastModifiedAt: 1453099158391, + lastModifiedBy: 'xx@xx.com' + }, + name: 'cf-route-url-here', + revision: [ + '1' + ] + }) + +nock(config.default.get('APIGEE_MGMT_API_URL')) + .get('/organizations/cdmo/apis/edgemicro_app-name-here.apps.pcf24.apigee.xyz') + .times(6) + .reply(200, { + metaData: { + createdAt: 1453098892108, + createdBy: 'xx@xx.com', + lastModifiedAt: 1453099158391, + lastModifiedBy: 'xx@xx.com' + }, + name: 'cf-route-url-here', + revision: [ + '1' + ] + }) + +nock(config.default.get('APIGEE_MGMT_API_URL')) + .get('/organizations/cdmo/apis/edgemicro_cf-bind_resource-route-url-here.com') + .times(6) + .reply(200, { + metaData: { + createdAt: 1453098892108, + createdBy: 'xx@xx.com', + lastModifiedAt: 1453099158391, + lastModifiedBy: 'xx@xx.com' + }, + name: 'cf-bind_resource-route-url-here.com', + revision: [ + '1' + ] + }) + +// https://api.enterprise.apigee.com/v1 +nock(config.default.get('APIGEE_MGMT_API_URL')) + .get('/organizations/cdmo/apis/edgemicro_target_app_route-here', /.*/) + .times(6) + .reply(200, { + metaData: { + createdAt: 1453098892108, + createdBy: 'xx@xx.com', + lastModifiedAt: 1453099158391, + lastModifiedBy: 'xx@xx.com' + }, + name: 'cf-route-url-here', + revision: [ + '1' + ] + }) // Apigee Get Proxy Details Nock nock(config.default.get('APIGEE_MGMT_API_URL')) @@ -108,10 +187,38 @@ nock(config.default.get('APIGEE_MGMT_API_URL')) '1' ] }) + +nock(config.default.get('APIGEE_MGMT_API_URL')) + .get('/organizations/cdmo/apis/cf-bind_resource-route-url-here.com') + .times(6) + .reply(200, { + metaData: { + createdAt: 1453098892108, + createdBy: 'xx@xx.com', + lastModifiedAt: 1453099158391, + lastModifiedBy: 'xx@xx.com' + }, + name: 'cf-bind_resource-route-url-here.com', + revision: [ + '1' + ] + }) + // Apigee Deploy Proxy Details Nock - edgemicro +nock(config.default.get('APIGEE_MGMT_API_URL')) + .post('/organizations/cdmo/environments/test/apis/edgemicro_app-name-here.apps.pcf24.apigee.xyz/revisions/1/deployments') + .times(6).reply(200) + nock(config.default.get('APIGEE_MGMT_API_URL')) .post('/organizations/cdmo/environments/test/apis/edgemicro_cf-route-url-here/revisions/1/deployments') .times(6).reply(200) +nock(config.default.get('APIGEE_MGMT_API_URL')) + .post('/organizations/cdmo/environments/test/apis/edgemicro_cf-bind_resource-route-url-here.com/revisions/1/deployments') + .times(6).reply(200) +nock(config.default.get('APIGEE_MGMT_API_URL')) + .post('/organizations/cdmo/environments/test/apis/edgemicro_target_app_route-here/revisions/1/deployments') + .times(6).reply(200) + // Apigee UnDeploy Proxy Details Nock - edgemicro nock(config.default.get('APIGEE_MGMT_API_URL')) .delete('/organizations/cdmo/environments/test/apis/edgemicro_cf-route-url-here/revisions/1/deployments') @@ -120,7 +227,374 @@ nock(config.default.get('APIGEE_MGMT_API_URL')) nock(config.default.get('APIGEE_MGMT_API_URL')) .post('/organizations/cdmo/environments/test/apis/cf-route-url-here/revisions/1/deployments') .times(6).reply(200) +nock(config.default.get('APIGEE_MGMT_API_URL')) + .post('/organizations/cdmo/environments/test/apis/cf-bind_resource-route-url-here.com/revisions/1/deployments') + .times(6).reply(200) + // Apigee UnDeploy Proxy Details Nock nock(config.default.get('APIGEE_MGMT_API_URL')) .delete('/organizations/cdmo/environments/test/apis/cf-route-url-here/revisions/1/deployments') - .times(6).reply(200) \ No newline at end of file + .times(6).reply(200) + +// Apigee addproduct nock +nock(config.default.get('APIGEE_MGMT_API_URL')) + .post('/organizations/cdmo/apiproducts') + .times(10) + .reply(201, { + 'apiResources': [ + '/resource' + ], + 'approvalType': 'auto', + 'attributes': [ + { + 'name': 'access', + 'value': 'public' + } + ], + 'description': '{description}', + 'displayName': '{display_name}', + 'environments': [ + 'test', + 'prod' + ], + 'name': 'api-product-name', + 'proxies': [], + 'quota': '1', + 'quotaInterval': '1', + 'quotaTimeUnit': 'minute', + 'scopes': [] + }) + +// Cloud foundry calls +// cf-cli - login to cf +nock(LOGIN_ENDPOINT) + .post('/oauth/token') + .times(10) + .reply(200, + { + access_token: 'access_token', + token_type: 'bearer', + id_token: 'idtoken', + refresh_token: 'refresh_token', + expires_in: 200, + scope: 'scope', + jti: 'jti' + }) + +// cf-cli - get spaces +nock(CF_API_URL) + .get('/v2/spaces') + .times(10) + .reply(200, { + resources: [ + { + entity: { + name: 'space-name-here' + }, + metadata: { + guid: 'space-guid-here' + } + } + ] + }) + +// cf-cli - get shared domains with apps.internal +nock(CF_API_URL) + .get('/v2/shared_domains') + .times(10) + .reply(200, { + resources: [ + { + entity: { + name: APPS_INTERNAL_DOMAIN + }, + metadata: { + guid: 'domain-guid-here' + } + }, + { + entity: { + name: config.cf.appsBaseDomain + }, + metadata: { + guid: 'cf-base-domain-guid' + } + } + ] + }) + +// cf-cli - get routes +nock(CF_API_URL) + .get('/v2/routes') + .times(10) + .reply(200, { + resources: [ + { + entity: { + host: 'target_app_route-here', + domain_guid: 'cf-base-domain-guid' + }, + metadata: { + guid: 'route-guid-here' + } + } + ] + }) + +// cf-cli - get apps +nock(CF_API_URL) + .get('/v2/apps') + .times(10) + .reply(200, { + resources: [ + { + entity: { + name: 'app-name-here' + }, + metadata: { + guid: 'app-guid-here' + } + }, + { + entity: { + name: 'c2c-mg-name' + }, + metadata: { + guid: 'app-guid-here' + } + }, + { + entity: { + name: 'cf-broker-name' + }, + metadata: { + guid: 'app-guid-here' + } + } + ] + }) + +nock(CF_API_URL) + .get('/v2/spaces/space-guid-here/apps') + .times(10) + .reply(200, { + resources: [ + { + entity: { + name: 'target_app_route-here' + }, + metadata: { + guid: 'target_app_route-here-guid' + } + }, + { + entity: { + name: 'app-name-here' + }, + metadata: { + guid: 'app-guid-here' + } + }, + { + entity: { + name: 'c2c-mg-name' + }, + metadata: { + guid: 'c2c-mg-guid' + } + }, + { + entity: { + name: 'cf-broker-name' + }, + metadata: { + guid: 'cf-broker-guid' + } + } + ] + }) + +// cf-cli - remove route +nock(CF_API_URL) + .delete('/v2/routes/route-guid-here') + .times(10) + .reply(200, {}) + +// cf-cli - add route +nock(CF_API_URL) + .post('/v2/routes') + .times(10) + .reply(201, { + entity: { + host: 'route-host-here' + }, + metadata: { + guid: 'route-guid-here' + } + }) + +// cf-cli - map-route +// /v2/apps/${appGuid}/routes/${routeGuid} +nock(CF_API_URL) + .put('/v2/apps/app-guid-here/routes/route-guid-here') + .times(10) + .reply(201, { + fake: 'fake' + }) +nock(CF_API_URL) + .put('/v2/apps/target_app_route-here-guid/routes/route-guid-here') + .times(10) + .reply(201, { + fake: 'fake' + }) + +// https://api.system.pcf24.apigee.xyz/networking/v1/external/policies +// cf-cli - add networking policy +nock(CF_API_URL) + .post('/networking/v1/external/policies') + .times(10) + .reply(200, {}) + +// apigee portal list +// https://apigee.com/portals/api/sites?orgname=cdmo +nock('https://apigee.com') + .get('/portals/api/sites?orgname=cdmo') + .times(10) + .reply(200, { + data: [ + { + id: 'portal-id-here', + name: 'Portal name here', + trashed: false, + trashedOn: null + } + ], + error_code: null, + message: 'Returning sites', + request_id: '1083343753', + status: 'success' + }) + +// https://apigee.com/organizations/yauhenikisialiou-eval/specs/folder/home +nock('https://apigee.com') + .get('/organizations/cdmo/specs/folder/home') + .times(10) + .reply(200, { + content: [ + { id: 174245, folder: 147770, kind: 'Folder', name: 'test', created: '2019-06-11T11:13:38.612Z' } + ], + created: '2019-02-26T17:07:45.805Z', + folder: 147770, + id: 147770, + kind: 'Folder', + modified: '2019-02-26T17:07:45.805Z', + name: '/orgs/yauhenikisialiou-eval root' + }) +// create folder in apigee +nock('https://apigee.com') + .post('/organizations/cdmo/specs/folder') + .times(10) + .reply(200, { + content: [], + created: '2019-06-12T13:40:06.839Z', + folder: 147770, + id: 174636, + kind: 'Folder', + modified: '2019-06-12T13:40:06.839Z', + name: 'target_app-name-here' + }) + +// apigee login +// https://login.apigee.com/oauth/token +nock('login.apigee.com') + .post('/oauth/token') + .times(10) + .reply(200, { + access_token: '123', + token_type: 'bearer' + }) + +// https://apigee.com/organizations/cdmo/specs/doc +// apigee specs create +nock('https://apigee.com') + .post('/organizations/cdmo/specs/doc') + .times(10) + .reply(201, { + id: 'spec-id-here' + }) + +nock('https://apigee.com') + .put('/organizations/cdmo/specs/doc/spec-id-here/content') + .times(10) + .reply(200, { + id: 'spec-id-here' + }) + +// apigee portals list +nock('https://apigee.com') + .get('/organizations/cdmo/portals/api/sites') + .times(10) + .reply(200, { + data: [] + }) +// apigee create portal +nock('https://apigee.com') + .post('/portals/api/sites') + .times(10) + .reply(200, { + data: { + id: 'portal-id-here', + orgname: 'cdmo' + } + }) + +// apigee portals - add spec to portal +nock('https://apigee.com') + .post('/portals/api/sites/portal-id-here/apidocs') + .times(10) + .reply(200, { + data: { + id: 'portal-id-here', + orgname: 'cdmo' + } + }) + +// apigee apiproducts +nock(config.default.get('APIGEE_MGMT_API_URL')) + .get('/organizations/cdmo/apiproducts?expand=true') + .times(10) + .reply(200, { + apiProduct: [] + }) + +// openapi app specs +const openApiSpecs = [ + 'http://localhost:8081', + 'http://route-url-here', + 'http://bind_resource-route-url-here.com', + 'http://target_app_route-here', + 'http://route-host-here.apps.internal', + 'http://target_app_route-here.cf-base-domain' +] +for (let baseUrl of openApiSpecs) { + nock(baseUrl) + .get('/openApi.json') + .times(10) + .reply(200, openApiJson) + + nock(baseUrl) + .get('/openApi.yaml') + .times(10) + .reply(200, openApiYaml) +} + +// https://cdmo-test.onprem.net/bind_resource-route-url-here.com/openapi +nock('https://cdmo-test.onprem.net') + .get('/bind_resource-route-url-here.com/openapi') + .times(10) + .reply(200, openApiJson) + +nock('https://target_app_route-here.cf-base-domain') + .get('/openapi') + .times(10) + .reply(200, openApiJson) diff --git a/apigee-cf-service-broker/test/helpers/openApi.json b/apigee-cf-service-broker/test/helpers/openApi.json new file mode 100644 index 0000000..37e9bdc --- /dev/null +++ b/apigee-cf-service-broker/test/helpers/openApi.json @@ -0,0 +1,264 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Apigee Open API Extensions Example", + "license": { + "name": "MIT" + } + }, + "host": "127.0.0.1:3000", + "basePath": "/", + "schemes": [ + "http" + ], + "consumes": [ + "application/json", + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/json", + "application/xml" + ], + "x-apigee-policies": { + "myQuotaName": { + "type": "quota", + "options": { + "allow": 15, + "timeUnit": "minute", + "interval": 1 + } + }, + "mySpikeArrest": { + "type": "spikeArrest", + "options": { + "allow": 12, + "timeUnit": "minute" + } + }, + "myResponseCache": { + "type": "responseCache", + "options": { + "time": 6000, + "identifier": "request.uri" + } + }, + "myJsonToXml": { + "type": "jsonToXml", + "options": { + "on": "response" + } + }, + "myXmlToJson": { + "type": "xmlToJson", + "options": { + "on": "response" + } + }, + "mySecureApi1": { + "type": "verifyApiKey", + "options": { + "in": "header", + "keyName": "apikey" + } + }, + "mySecureApi2": { + "type": "oAuthV2", + "options": { + "operation": "verifyAccessToken" + } + } + }, + "x-apigee-apply": { + "mySpikeArrest": { + "options": { + "on": "request", + "endPoint": "proxy", + "flow": "preFlow" + } + }, + "myQuotaName": { + "options": { + "on": "response", + "endPoint": "target", + "flow": "preFlow" + } + } + }, + "paths": { + "/": { + "get": { + "x-apigee-apply": { + "myJsonToXml": { + "options": { + "on": "response", + "endPoint": "target" + } + } + }, + "summary": "Hello World App for Cloud Foundry", + "responses": { + "200": { + "description": "A Json response with hello message" + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/hello/{name}": { + "get": { + "x-apigee-apply": { + "myResponseCache": { + "options": { + "on": "request,response", + "endPoint": "proxy" + } + } + }, + "summary": "Hello User Name greeting", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Hello user :username" + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/hello/user": { + "post": { + "x-apigee-apply": { + "myXmlToJson": { + "options": { + "on": "response", + "endPoint": "target" + } + } + }, + "summary": "Create User Info", + "parameters": [ + { + "name": "name", + "in": "formData", + "description": "User Name", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Created Message" + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + }, + "put": { + "x-apigee-apply": { + "myXmlToJson": { + "options": { + "on": "response", + "endPoint": "target" + } + } + }, + "summary": "Updated User Info", + "parameters": [ + { + "name": "name", + "in": "formData", + "description": "User Name", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Created Message" + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + }, + "delete": { + "x-apigee-apply": { + "myXmlToJson": { + "options": { + "on": "response", + "endPoint": "target" + } + } + }, + "security": [ + { + "mySecureApi1": [] + } + ], + "summary": "delete User Info", + "d": "deleteUserInfo", + "parameters": [ + { + "name": "name", + "in": "formData", + "description": "User Name", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Created Message" + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + } + }, + "definitions": { + "Error": { + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + } + } +} diff --git a/apigee-cf-service-broker/test/helpers/openApi.yaml b/apigee-cf-service-broker/test/helpers/openApi.yaml new file mode 100644 index 0000000..b953424 --- /dev/null +++ b/apigee-cf-service-broker/test/helpers/openApi.yaml @@ -0,0 +1,176 @@ +swagger: "2.0" +info: + version: 1.0.0 + title: Apigee Open API Extensions Example + license: + name: Apache +host: 127.0.0.1:3000 +basePath: / +schemes: + - http +consumes: + - application/json + - application/x-www-form-urlencoded +produces: + - application/json + - application/xml +x-apigee-policies: + myQuotaName: + type: quota + options: + allow: 15 + timeUnit: minute + interval: 1 + mySpikeArrest: + type: spikeArrest + options: + allow: 12 + timeUnit: minute + myResponseCache: + type: responseCache + options: + time: 6000 + identifier: request.uri + myJsonToXml: + type: jsonToXml + options: + on: response + myXmlToJson: + type: xmlToJson + options: + on: response + mySecureApi1: + type: verifyApiKey + options: + in: header + keyName: apikey + mySecureApi2: + type: oAuthV2 + options: + operation: verifyAccessToken +x-apigee-apply: + mySpikeArrest: + options: + on: request + endPoint: proxy + flow: preFlow + myQuotaName: + options: + on: response + endPoint: target + flow: preFlow +paths: + /: + get: + x-apigee-apply: + myJsonToXml: + options: + on: response + endPoint: target + summary: Hello World App for Cloud Foundry + operationId: helloWorld + responses: + 200: + description: A Json response with hello message + default: + description: unexpected error + schema: + $ref: "#/definitions/Error" + /hello/{name}: + get: + x-apigee-apply: + myResponseCache: + options: + on: request,response + endPoint: proxy + summary: Hello User Name greeting + operationId: greetUser + parameters: + - name: name + in: path + required: true + type: string + responses: + 200: + description: Hello user :username + default: + description: unexpected error + schema: + $ref: "#/definitions/Error" + /hello/user: + post: + x-apigee-apply: + myXmlToJson: + options: + on: response + endPoint: target + summary: Create User Info + operationId: createUserInfo + parameters: + - name: name + in: formData + description: User Name + required: true + type: string + responses: + 200: + description: Created Message + default: + description: unexpected error + schema: + $ref: "#/definitions/Error" + put: + x-apigee-apply: + myXmlToJson: + options: + on: response + endPoint: target + summary: Updated User Info + operationId: updateUserInfo + parameters: + - name: name + in: formData + description: User Name + required: true + type: string + responses: + 200: + description: Created Message + default: + description: unexpected error + schema: + $ref: "#/definitions/Error" + delete: + x-apigee-apply: + myXmlToJson: + options: + on: response + endPoint: target + security: + - mySecureApi1: [] + summary: delete User Info + operationId: deleteUserInfo + parameters: + - name: name + in: formData + description: User Name + required: true + type: string + responses: + 200: + description: Created Message + default: + description: unexpected error + schema: + $ref: "#/definitions/Error" +definitions: + Error: + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string diff --git a/apigee-cf-service-broker/test/manifest.yml b/apigee-cf-service-broker/test/manifest.yml new file mode 100644 index 0000000..e69de29 From c7ffa3ede1cd9fd574ebdc7a8104243e34b88109 Mon Sep 17 00:00:00 2001 From: ykisialiou Date: Fri, 26 Jul 2019 03:49:17 +0300 Subject: [PATCH 2/5] Add docs --- docs/setup-portal.md | 196 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 docs/setup-portal.md diff --git a/docs/setup-portal.md b/docs/setup-portal.md new file mode 100644 index 0000000..1fa50d2 --- /dev/null +++ b/docs/setup-portal.md @@ -0,0 +1,196 @@ +# Setting up Apigee Edge to proxy a Cloud Foundry app ("portal" plan) +Using code in this directory, you can install an Apigee Edge service broker that manages connections between your Cloud Foundry app and Apigee Edge. + +Use the following sections to install the Apigee service broker on Cloud Foundry, then set up a binding between a Cloud Foundry app and the Apigee service. + +1. [Ensure you have the prerequisites.](apigee-service-broker-prerequisites.md) +1. [Install the service broker](#install) to make it available in the marketplace (CF administrator/operator). +1. [Create an instance of the service broker](#instance) for your Cloud Foundry org/space (CF user). +1. [Bind or unbind](#bind) a route service to an app route as needed (CF user). + +## Step 1: Install the Apigee service broker from source + +If you're a Cloud Foundry administrator, you can install a service broker as an application (in other words, a broker-app). This is particularly useful when running a Cloud Foundry development environment. + +> For Pivotal Cloud Foundry, this broker is also packaged as a *tile* for easy installation by an Operator. See the Apigee docs for more on [installing and configuring the tile](http://docs.apigee.com/api-services/content/install-and-configure-apigee-service-broker). + +These instructions assume a local [PCF Dev](https://pivotal.io/pcf-dev) environment, at the domain `local.pcfdev.io`. If you're using another kind of Cloud Foundry host, be sure to adjust URLs accordingly. + +1. Clone this github project to get the service broker source you'll need. + ```bash + $ cd + $ git clone https://github.com/apigee/cloud-foundry-apigee.git + $ cd cloud-foundry-apigee/apigee-cf-service-broker + ``` + +2. Load dependencies and test (requires that Node.js is installed). + ```bash + $ npm install + $ npm test + ``` + +3. In the apigee-cf-service-broker directory, edit the manifest.yml file to set required variables (``org`` and ``env``) and override defaults as appropriate for your environment and Apigee Edge account. + + + Item | Purpose | Default (for SaaS Edge) + ---- | ---- | ---- + APIGEE_DASHBOARD_URL | URL for Apigee Edge management UI | `https://enterprise.apigee.com/platform/#/` + APIGEE_MGMT_API_URL | Apigee Edge Management API endpoint | `https://api.enterprise.apigee.com/v1` + APIGEE_PROXY_DOMAIN | Domain for proxy host template | `apigee.net` + APIGEE_PROXY_HOST_TEMPLATE | ES6 template literal for generated proxy host. The template that describes how the Apigee Edge host name should be generated.
This represents the hostname that clients use to make calls to your APIs. Change this value if your hostname is not created in the default way -- from your Apigee org an environment names. For example, if your APIs use a custom virtual host, you might have just a domain name:
`${domain}`
Pivotal Cloud Foundry apps use this host when making calls to your API proxy. The template generates the host name from values specified when binding the PCF app to the service(Note that without any placeholders, will be used as-is.) | `${org}-${env}.${domain}` + APIGEE_PROXY_NAME_TEMPLATE | ES6 template literal for generated proxy | `cf-${route}` + ORG | The Apigee Edge organization with proxies that will handle calls to your app. | + ENV | The Apigee Edge environment that with proxies that will handle calls to your app. | + + If you've got an HTTP(S) proxy server, you can also specify the server's URL, as shown in the example here. + + > **Note:** Cloud Foundry does not allow ``${...}`` syntax to be present in the environment variable section. So when changing `APIGEE_PROXY_HOST_TEMPLATE` or `APIGEE_PROXY_NAME_TEMPLATE`, be sure to not use ``${...}`` in your changes. + + ```yaml + env: + APIGEE_CONFIGURATIONS: | + [{“org”:”your-apigee-org1”, + “env”:”your-apigee-env1”, + “apigee_proxy_domain”:”apigee.net”,...}, + ] + HTTP_PROXY:”your HTTP proxy server URL” + HTTPS_PROXY:”your HTTPS proxy server URL” + MICROGATEWAY_APP_NAME: "the app name for microgateway, bound with portal plan, 'cf apps' output, column 'name'" + BROKER_APP_NAME: "the broker name for current broker, 'cf apps' output, column 'name'" + APPS_BASE_DOMAIN: "base apps domain. cf domains output, column 'name'" + ``` + +4. Log in to the Cloud Foundry instance where you'll be installing the Apigee service broker. + + ```bash + $ cf login -a -u -o -s + ``` + +5. Deploy the Apigee service broker from the source in this repository. + + ```bash + $ cf push + ``` + Make a note of the broker app's URL, which you'll use to create the service broker later. Here's an example: + + ``` + urls: apigee-cf-service-broker.local.pcfdev.io + ``` + +6. Choose a user name and password and store them as environment variables for the broker app. Then restage the broker app to load those variables. + + Communication with the broker is protected with a user name and password (to prevent unauthorized access to the broker app from other sources). These credentials are specified when the broker is created, and then used for each call. However, validating those credentials is the responsibility of the broker app, which does not have those credentials provided by the runtime. + + ```bash + $ cf set-env apigee-cf-service-broker SECURITY_USER_NAME + $ cf set-env apigee-cf-service-broker SECURITY_USER_PASSWORD + $ cf restage apigee-cf-service-broker + ``` + +7. Use the credentials you just established, along with the URL for the broker app, to create the service broker in Cloud Foundry. + ```bash + $ cf create-service-broker apigee-edge https://apigee-cf-service-broker.local.pcfdev.io + ``` + +8. Publish the service broker in your Cloud Foundry marketplace. + ```bash + $ cf enable-service-access apigee-edge + $ cf marketplace + $ cf marketplace -s apigee-edge + ``` + +The Apigee service broker should now be available for you to create instances and bind to an Apigee-hosted proxy. + +## Step 2: Create an instance of the Apigee service + +You create a service instance so you can bind a Cloud Foundry app's path to it. + +The service instance is created for the Cloud Foundry org/space by specifying the desired service plan and a name for the instance. For example, for the service name `myapigee` using the `portal` plan: + +```bash +$ cf create-service apigee-edge portal -c \ + '{"org":"", "env":""}' +$ cf service +``` + +>**Note:** Once you have the service broker installed, you might be interested in using the sample app included in this repository to try it out. To do this, you'd replace the following steps with those in this [tutorial](../samples/org-and-microgateway-sample). + +## Step 3: Bind the CF app's route to the Apigee service + +In this step, you bind a Cloud Foundry app's route (its address in Cloud Foundry) to the Apigee service instance you created. That way, requests to the app will be forwarded first to an Edge proxy. The `bind-route-service` command creates the proxy for you and binds the route to it. + +Each bind attempt requires authorization with Edge, passed as additional parameters to the `cf` bind command. + +1. First, get the URL of the app/route to bind. `cf routes` lists the host and domain separately; `cf apps` combines them into a FQDN, listed under "urls". For example, if the app's hostname is `test-app`, then the resulting FQDN is `test-app.local.pcfdev.io`. + +1. Get or update the authorization token using the Apigee SSO CLI script. + ```bash + $ get_token + ``` + You may be prompted for your Apigee Edge username and password, and an MFA token. This updates the token in the `~/.sso-cli/valid_token.dat` file (if that subdirectory exists -- otherwise the file is placed in the current working directory). + +1. Bind the app's route to the Apigee service instance with the domain and hostname. + + Use the [`bind-route-service`](#bind-route-service-reference) command. + The following example does two things: + it creates an API proxy on the `myorg` org and `test` environment, + then binds the Apigee route service to the proxy. + The protocol parameter specifies the protocol through which the proxy will be called. + To do its works, this command authenticates with Apigee Edge using the token in the specified .dat file: + ```bash + $ cf bind-route-service local.pcfdev.io myapigee --hostname test-app \ + -c '{"org":"myorg","env":"test", + "bearer":"'$(cat ~/.sso-cli/valid_token.dat)'", + "action":"proxy bind", + "target_app_route":"sample", + "target_app_port":"8080", + "protocol":"https"}' + ``` + +1. Log into Edge and note that the proxy, spec for app, api product, portal have been created, and that requests to your app are being routed through Edge. + + You will find a proxy whose name matches the pattern specified by the APIGEE_PROXY_NAME_TEMPLATE variable you specified with your org and env mapping in the manifest. The proxy has been deployed to the environment you specified when you created your service instance. + + In the Edge management console, begin tracing the proxy, then send requests to your app. Trace will show the traffic routing through the proxy. + + You can now configure standard Apigee Edge policies on that proxy. + +### bind-route-service reference +Use the `bind-route-service` command to generate an API proxy on Apigee Edge and to bind the Apigee Cloud Foundry service to the proxy. The command this form (be sure to use quotes and command expansion, as shown here): + +```bash +$ cf bind-route-service [--hostname ] \ +-c '{"org":"","env":"", + "bearer":"''" | "basic":"" | ":", + "action":"proxy"|"bind"|"proxy bind", + "target_app_route":"your app-name", + "target_app_port":"8080", + ["protocol":"http"|"https"]}' +``` + +Parameters for the `-c` argument specify connection details: + +Parameter | Purpose | Allowed Values +---- | ---- | ---- +`org` | Apigee Edge organization hosting the API proxy to be called | Your organization (must be reachable via the authentication token specified in the `bearer` parameter) +`env` | Apigee Edge environment to which the API proxy is (or will be) deployed | Your environment. +`bearer` | Path to a file containing an authentication token valid for your organization | An authentication token, such as one generated with Apigee's get_token command. The broker does not store any data; it requires credentials and other parameters for each individual `cf` command. Instead of a `bearer` token, credentials can also be expressed as:
  • `basic`: standard HTTP Base-64 encoded username and password for `Authorization: Basic`. Note that this is *not encrypted* and easily converted to clear text. But a jumble of digits and letters may provide some protection in case of momentary exposure (but no better than if the password is already a jumble of digits, letters, and symbols)
  • username and password in clear text
+`action` | A value specifying whether to create or bind an API proxy | `proxy` to generate an API proxy; `bind` to bind the service with the proxy; `proxy bind` to generate the proxy and bind with a single command. +`protocol` | The protocol through which the proxy should be accessed by Cloud Foundry | `http` or `https`; default is `https`. +`target_app_route` | The app name with your API, "cf apps" output, column "name" +`target_app_port` | The app port +`with_docstore` | Create a folder for app specs | Boolean, default: false + +## Unbinding the route service + +The unbind command does not accept any parameters + +```bash +$ cf unbind-route-service --hostname +``` + +## Uninstalling the service instance and broker +```bash +$ cf delete-service +$ cf delete-service-broker apigee-edge +``` \ No newline at end of file From 14c29d0c04d42b0c882850bd7a99af2a2372c780 Mon Sep 17 00:00:00 2001 From: Nosau Aliaksandr Date: Fri, 26 Jul 2019 16:47:34 +0300 Subject: [PATCH 3/5] added flag for portal plan - enable/disable cf-binding.cf creds samples moved to manifest --- .../config/environment/development.js | 6 +- .../config/environment/production.js | 6 +- ...service-binding-portal-empty-docstore.json | 2 +- .../service-instance.controller.js | 5 +- .../lib/helpers/logger.js | 6 +- .../lib/providers/cf-binder.js | 25 +- .../lib/providers/service-plans/micro-c2c.js | 4 +- .../lib/providers/service-plans/portal.js | 6 +- apigee-cf-service-broker/manifest.yml | 9 +- apigee-cf-service-broker/package.json | 2 +- apigee-cf-service-broker/test/api.js | 1534 +++++++++++------ docs/apigee-service-broker-prerequisites.md | 2 + docs/setup-portal.md | 5 +- .../public/openApi.json | 10 +- samples/org-and-microgateway-sample/server.js | 7 + 15 files changed, 1041 insertions(+), 588 deletions(-) diff --git a/apigee-cf-service-broker/config/environment/development.js b/apigee-cf-service-broker/config/environment/development.js index 54e96a0..5b63acc 100644 --- a/apigee-cf-service-broker/config/environment/development.js +++ b/apigee-cf-service-broker/config/environment/development.js @@ -9,7 +9,11 @@ module.exports = { password: process.env.CF_LOGIN_PASSWORD, appsBaseDomain: process.env.APPS_BASE_DOMAIN, microgatewayAppName: process.env.MICROGATEWAY_APP_NAME, - brokerAppName: process.env.BROKER_APP_NAME + brokerAppName: process.env.BROKER_APP_NAME, + + loginEndpoint: process.env.LOGIN_ENDPOINT, + apiUrl: process.env.CF_API_URL, + appsInternalDomain: process.env.APPS_INTERNAL_DOMAIN }, auth: { securityUserName: process.env.SECURITY_USER_NAME, diff --git a/apigee-cf-service-broker/config/environment/production.js b/apigee-cf-service-broker/config/environment/production.js index 54e96a0..5b63acc 100644 --- a/apigee-cf-service-broker/config/environment/production.js +++ b/apigee-cf-service-broker/config/environment/production.js @@ -9,7 +9,11 @@ module.exports = { password: process.env.CF_LOGIN_PASSWORD, appsBaseDomain: process.env.APPS_BASE_DOMAIN, microgatewayAppName: process.env.MICROGATEWAY_APP_NAME, - brokerAppName: process.env.BROKER_APP_NAME + brokerAppName: process.env.BROKER_APP_NAME, + + loginEndpoint: process.env.LOGIN_ENDPOINT, + apiUrl: process.env.CF_API_URL, + appsInternalDomain: process.env.APPS_INTERNAL_DOMAIN }, auth: { securityUserName: process.env.SECURITY_USER_NAME, diff --git a/apigee-cf-service-broker/json-sample/service-binding-portal-empty-docstore.json b/apigee-cf-service-broker/json-sample/service-binding-portal-empty-docstore.json index 9681c98..875d9c8 100644 --- a/apigee-cf-service-broker/json-sample/service-binding-portal-empty-docstore.json +++ b/apigee-cf-service-broker/json-sample/service-binding-portal-empty-docstore.json @@ -3,7 +3,7 @@ "service_id": "5E3F917B-9225-4BE4-802F-8F1491F714C0", "plan_id": "04B7CC7F-EE5D-4BF4-A5D7-1C637651F545", "bind_resource": { - "route": "sample-1.apps.pcf24.apigee.xyz" + "route": "sample-1.apps.gilroy.cf-app.com" }, "context": { "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400" diff --git a/apigee-cf-service-broker/lib/controllers/api/service-instances/service-instance.controller.js b/apigee-cf-service-broker/lib/controllers/api/service-instances/service-instance.controller.js index b527f04..1efb794 100644 --- a/apigee-cf-service-broker/lib/controllers/api/service-instances/service-instance.controller.js +++ b/apigee-cf-service-broker/lib/controllers/api/service-instances/service-instance.controller.js @@ -62,7 +62,7 @@ function deriveC2CParams (params, req) { const derivePortalParams = (params = {}) => { const portalParams = {} - const keys = [ 'with_docstore', 'target_app_route' ] + const keys = [ 'with_docstore', 'target_app_route', 'with_cf_binding' ] keys.forEach((key) => { if (params[key]) { @@ -72,6 +72,9 @@ const derivePortalParams = (params = {}) => { if (!params.with_docstore) { portalParams.with_docstore = false } + if (!params.with_cf_binding) { + portalParams.with_cf_binding = false + } portalParams.target_app_port = derivePort(params) return portalParams diff --git a/apigee-cf-service-broker/lib/helpers/logger.js b/apigee-cf-service-broker/lib/helpers/logger.js index 5c5af64..f4bd9cf 100644 --- a/apigee-cf-service-broker/lib/helpers/logger.js +++ b/apigee-cf-service-broker/lib/helpers/logger.js @@ -82,7 +82,8 @@ var codes = { ERR_PORTAL_PLAN_RUN_BINDING: 'E1026', ERR_BIND_RESOURCE_APP_NAME_REQURED: 'E1027', ERR_BIND_RESOURCE_TARGET_APP_NAME_REQURED: 'E1028', - ERR_MISSING_TARGET_APP_ROUTE: 'E1029' + ERR_MISSING_TARGET_APP_ROUTE: 'E1029', + ERR_CF_MICROGATEWAY_APP_NAME_UNKNOWN: '1030' } var messages = { @@ -143,7 +144,8 @@ var messages = { E1026: 'Portal plan binding failed with errors', E1027: 'For portal plan param target_app_name required', E1028: 'Parameter "target_app_name" required', - E1029: 'Parameter "target_app_route" required' + E1029: 'Parameter "target_app_route" required', + E1030: 'Microgateway app name not found in your cf space' } var getMessage = function (code) { diff --git a/apigee-cf-service-broker/lib/providers/cf-binder.js b/apigee-cf-service-broker/lib/providers/cf-binder.js index 4960800..ef701b0 100644 --- a/apigee-cf-service-broker/lib/providers/cf-binder.js +++ b/apigee-cf-service-broker/lib/providers/cf-binder.js @@ -9,16 +9,12 @@ const Apps = require(path.resolve('./lib/providers/cf-nodejs-client/model/cloudc const Networking = require(path.resolve('./lib/providers/cf-nodejs-client/model/cloudcontroller/Networking')) const logger = require(path.resolve('./lib/helpers/logger')) -const LOGIN_ENDPOINT = 'https://login.system.pcf24.apigee.xyz' -const CF_API_URL = 'https://api.system.pcf24.apigee.xyz' -const APPS_INTERNAL_DOMAIN = 'apps.internal' - -const uaaService = new CloudFoundryUsersUAA(LOGIN_ENDPOINT) -const routesService = new CloudFoundryRoutes(CF_API_URL) -const domainsService = new Domains(CF_API_URL) -const appsService = new Apps(CF_API_URL) -const networkingService = new Networking(CF_API_URL) -const servicePlansService = new ServicePlans(CF_API_URL) +const uaaService = new CloudFoundryUsersUAA(config.cf.loginEndpoint) +const routesService = new CloudFoundryRoutes(config.cf.apiUrl) +const domainsService = new Domains(config.cf.apiUrl) +const appsService = new Apps(config.cf.apiUrl) +const networkingService = new Networking(config.cf.apiUrl) +const servicePlansService = new ServicePlans(config.cf.apiUrl) /* * @description CF Binder for calls REST cf api * @@ -59,7 +55,7 @@ class CFBinder { } getAppInternalFullHostname () { - const result = `${this.appRoute.entity.host}.${APPS_INTERNAL_DOMAIN}` + const result = `${this.appRoute.entity.host}.${config.cf.appsInternalDomain}` return result } @@ -324,7 +320,7 @@ class CFBinder { const microcgatewayApp = apps.resources.find(a => a.entity.name === config.cf.microgatewayAppName) if (!microcgatewayApp) { - const error = logger.ERR_CF_EMPTY_APP() + const error = logger.ERR_CF_MICROGATEWAY_APP_NAME_UNKNOWN() return { error } } @@ -393,8 +389,5 @@ class CFBinder { } module.exports = { - CFBinder, - LOGIN_ENDPOINT, - CF_API_URL, - APPS_INTERNAL_DOMAIN + CFBinder } diff --git a/apigee-cf-service-broker/lib/providers/service-plans/micro-c2c.js b/apigee-cf-service-broker/lib/providers/service-plans/micro-c2c.js index 63f27d1..063c97c 100644 --- a/apigee-cf-service-broker/lib/providers/service-plans/micro-c2c.js +++ b/apigee-cf-service-broker/lib/providers/service-plans/micro-c2c.js @@ -1,7 +1,7 @@ const path = require('path') const logger = require(path.resolve('./lib/helpers/logger')) const config = require(path.resolve('./config/environment')) -const { CFBinder, APPS_INTERNAL_DOMAIN } = require(path.resolve('./lib/providers/cf-binder')) +const { CFBinder } = require(path.resolve('./lib/providers/cf-binder')) class Microc2c { // TODO implement me @@ -59,7 +59,7 @@ class Microc2c { targetAppRoute: param.micro_c2c.target_app_route, spaceGuid: param.space_guid, targetAppPort: param.micro_c2c.target_app_port, - domainForSearch: APPS_INTERNAL_DOMAIN + domainForSearch: config.cf.appsInternalDomain }) if (result.error) { return result diff --git a/apigee-cf-service-broker/lib/providers/service-plans/portal.js b/apigee-cf-service-broker/lib/providers/service-plans/portal.js index ec8e7f0..ff7bbfc 100644 --- a/apigee-cf-service-broker/lib/providers/service-plans/portal.js +++ b/apigee-cf-service-broker/lib/providers/service-plans/portal.js @@ -85,6 +85,10 @@ class Portal { * * */ async runBinding (param) { + if (!param.portal.with_cf_binding) { + logger.log.info('portal.runBinding.skipped') + return Promise.resolve({}) + } const cfbinder = new CFBinder() try { const loginResponse = await cfbinder.login() @@ -123,7 +127,7 @@ class Portal { } _getOpenApiSpecUrl (param) { - let url = `https://${param.portal.target_app_route}.${config.cf.appsBaseDomain}/openapi` + let url = `https://${param.portal.target_app_route}.${config.cf.appsBaseDomain}/openApi.json` return url } diff --git a/apigee-cf-service-broker/manifest.yml b/apigee-cf-service-broker/manifest.yml index 6957666..25e756f 100644 --- a/apigee-cf-service-broker/manifest.yml +++ b/apigee-cf-service-broker/manifest.yml @@ -18,6 +18,11 @@ env: ] SECURITY_USER_NAME: admin SECURITY_USER_PASSWORD: jijkjijijijijjiji== - MICROGATEWAY_APP_NAME: edgemicro-app + MICROGATEWAY_APP_NAME: edgemicro-app-1234 BROKER_APP_NAME: apigee-cf-service-broker-test - APPS_BASE_DOMAIN: apps.pcf24.apigee.xyz + APPS_BASE_DOMAIN: apps.gilroy.cf-app.com + LOGIN_ENDPOINT: https://login.sys.gilroy.cf-app.com + CF_API_URL: https://api.sys.gilroy.cf-app.com + CF_LOGIN: + CF_LOGIN_PASSWORD: + APPS_INTERNAL_DOMAIN: apps.internal diff --git a/apigee-cf-service-broker/package.json b/apigee-cf-service-broker/package.json index 5cf07b1..4361977 100644 --- a/apigee-cf-service-broker/package.json +++ b/apigee-cf-service-broker/package.json @@ -10,7 +10,7 @@ "posttest": "node scripts/genCoverageBadge.js" }, "engines": { - "node": "10.12.0" + "node": "10.16.0" }, "repository": { "type": "git", diff --git a/apigee-cf-service-broker/test/api.js b/apigee-cf-service-broker/test/api.js index ecc591c..3d735c2 100644 --- a/apigee-cf-service-broker/test/api.js +++ b/apigee-cf-service-broker/test/api.js @@ -1,437 +1,587 @@ -'use strict' -/* - * Copyright 2017 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -var chai = require('chai') -chai.use(require('chai-things')) -var expect = chai.expect -var should = require('should') // eslint-disable-line -var supertest = require('supertest') -var server = require('../server') -// Using Port 8000 to start test server -var port = 8000 -var api = supertest('http://localhost:' + port) -var app -var catalogData = require('../helpers/catalog_data') -var config = require('../helpers/config') - require('./helpers/api_mocks.js') +const path = require('path') + +process.env.MICRO_C2C_APP_NAME = 'c2c-mg-name' +process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0 +process.env.SECURITY_USER_NAME = 'tester' +process.env.SECURITY_USER_PASSWORD = 'testing' +process.env.APPS_BASE_DOMAIN = 'cf-domain-here' + +const chai = require('chai') +let { expect } = chai + +const server = require(path.resolve('./server.js')) +const chaiHttp = require('chai-http') +const catalogData = require('../lib/providers/catalog_data') +const { deriveAction, deriveProtocol } = require(path.resolve('./lib/helpers/extractors')) + +chai.use(chaiHttp) + +const config = require(path.resolve('./config/environment')) + +/* eslint-disable */ +describe('Component APIs', () => { + const authHeader = 'Basic ' + new Buffer('tester:testing').toString('base64') + + const badAuthHeader = 'Basic ' + new Buffer('admin:' + 'wrong-password').toString('base64') -describe('Component APIs', function () { - this.timeout(0) - var authHeader = 'Basic ' + new Buffer(config.default.get('SECURITY_USER_NAME') + ':' + config.default.get('SECURITY_USER_PASSWORD')).toString('base64') - var badAuthHeader = 'Basic ' + new Buffer('admin:' + 'wrong-password').toString('base64') before('Starting test server', function () { // eslint-disable-line app = server.listen(8000) }) - - describe('API Security', function () { - - it('Valid Auth should return 200', function (done) { - api.get('/') - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(200) - .end(function (err, res) { - expect(err).equal(null) - expect(res.body).to.have.property('message') - done() - }) + describe('Extractors - unit tests', () => { + describe('Protocol', () => { + it('Invalid protocol', async () => { + const result = deriveProtocol({ protocol: 'httpsm'}) + expect(result).to.have.property('error') + }) + it('Default protocol - http', async () => { + const result = deriveProtocol({}) + expect(result).to.have.property('protocol') + expect(result.protocol).to.be.eq('http') + }) + }) + describe('Action', () => { + it('Invalid action', async () => { + const result = deriveAction({ action: 'httpsm'}) + expect(result).to.have.property('errors') + }) + it('Valid actions - bind', async () => { + const result = deriveAction({ action: 'bind' }) + expect(result).to.have.property('bind') + expect(result.bind).to.be.eq(true) + }) + it('Valid actions - proxy', async () => { + const result = deriveAction({ action: 'proxy' }) + expect(result).to.have.property('proxy') + expect(result.proxy).to.be.eq(true) + }) + it('Valid actions - proxy bind', async () => { + const result = deriveAction({ action: 'bind proxy' }) + expect(result).to.have.property('proxy') + expect(result.proxy).to.be.eq(true) + expect(result).to.have.property('bind') + expect(result.bind).to.be.eq(true) + }) }) - it('Invalid Auth should return 401', function (done) { - api.get('/') - .set('Accept', 'application/json') - .set('Authorization', badAuthHeader) - .expect(401, done) + }) + describe('API Security', () => { + it('Valid Auth should return 200', async () => { + let error = false + try { + const res = await chai.request(server) + .get(`/`) + .set('Authorization', authHeader) + expect(res).to.have.status(200) + expect(res.body).to.have.property('message') + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } + }) + + it('Invalid Auth should return 401', async () => { + let error = false + try { + const res = await chai.request(server) + .get(`/`) + .set('Authorization', badAuthHeader) + expect(res).to.have.status(401) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) }) - describe('Catalog APIs', function () { - it('Invalid Auth should return 401', function (done) { - api.get('/v2/catalog') - .set('Accept', 'application/json') - .expect(401, done) - }) - it('Valid Auth should return 200', function (done) { - api.get('/v2/catalog') - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(200, done) - }) - it('Catalog API should return list of service plans', function (done) { - api.get('/v2/catalog') - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(200) - .end(function (err, res) { - expect(err).equal(null) - expect(res.body).to.have.property('services') - res.body.services.forEach(function (service) { - service.should.have.property('name') - service.should.have.property('id') - service.should.have.property('description') - service.should.have.property('bindable') - service.should.have.property('plans') - service.plans.forEach(function (plan) { - plan.should.have.property('id') - plan.should.have.property('name') - plan.should.have.property('description') - }) + + describe('Catalog APIs', () => { + it('Invalid Auth should return 401', async () => { + let error = false + try { + const res = await chai.request(server) + .get(`/v2/catalog`) + expect(res).to.have.status(401) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } + }) + + it('Valid Auth should return 200', async () => { + let error = false + try { + const res = await chai.request(server) + .get(`/v2/catalog`) + .set('Authorization', authHeader) + + expect(res).to.have.status(200) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } + }) + it('Catalog API should return list of service plans', async () => { + let error = false + try { + const res = await chai.request(server) + .get(`/v2/catalog`) + .set('Authorization', authHeader) + + expect(res).to.have.status(200) + expect(res.body).to.have.property('services') + res.body.services.forEach((service) => { + expect(service).to.have.property('name') + expect(service).to.have.property('id') + expect(service).to.have.property('description') + expect(service).to.have.property('bindable') + expect(service).to.have.property('plans') + service.plans.forEach((plan) => { + expect(plan).to.have.property('id') + expect(plan).to.have.property('name') + expect(plan).to.have.property('description') }) - done() }) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) }) - describe('Service Instance APIs', function () { - it('Invalid Auth should return 401', function (done) { - api.put('/v2/service_instances/:instance_id') - .set('Accept', 'application/json') - .expect(401, done) + describe('Service Instance APIs', () => { + it('Invalid Auth should return 401', async () => { + let error = false + try { + const res = await chai.request(server) + .put(`/v2/service_instances/:instance_id`) + + expect(res).to.have.status(401) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Patch to Service Instance should return 422', function (done) { - api.patch('/v2/service_instances/:instance_id') - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(422, done) + it('Patch to Service Instance should return 422', async () => { + let error = false + try { + const res = await chai.request(server) + .patch(`/v2/service_instances/:instance_id`) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + console.info('RES', res.body) + expect(res).to.have.status(422) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Service instance creation should return a 201 response with dashboard_url', function (done) { - var serviceInstance = { - instance_id: 'instance-guid-here', - payload: { - organization_guid: 'org-guid-here', - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - space_guid: 'space-guid-here', - parameters: { - org: 'org-name-here', - env: 'env-name-here', + + it('Service instance creation should return a 201 response with dashboard_url', async () => { + let error = false + try { + const serviceInstance = { + instance_id: 'instance-guid-here', + payload: { + organization_guid: 'org-guid-here', + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + space_guid: 'space-guid-here', + parameters: { + org: 'cdmo', + env: 'test', + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + serviceInstance.instance_id) + .send(serviceInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + expect(res).to.have.status(201) + expect(res.body).to.have.property('dashboard_url') + expect(res.body.dashboard_url).to.equal('https://onprem.com/platform/#/') + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + serviceInstance.instance_id) - .send(serviceInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(201) - .end(function (err, res) { - expect(err).equal(null) - expect(res.body).to.have.property('dashboard_url') - expect(res.body.dashboard_url).to.equal('https://enterprise.apigee.com/platform/#/') - done() - }) }) - it('Request with missing org/env mapping should return a 400 response', function (done) { - var serviceInstance = { + it('Request with missing org/env mapping should return a 400 response', async () => { + let error = false + const serviceInstance = { instance_id: 'instance-guid-here', payload: { organization_guid: 'org-guid-here', plan_id: catalogData.guid.org, service_id: 'service-guid-here', space_guid: 'space-guid-here', - parameters: { - } + parameters: {} } } - api.put('/v2/service_instances/' + serviceInstance.instance_id) - .send(serviceInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + serviceInstance.instance_id) + .send(serviceInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Request with incorrect org to env mapping should return a 400 response', function (done) { - var serviceInstance = { - instance_id: 'instance-guid-here', - payload: { - organization_guid: 'org-guid-here', - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - space_guid: 'space-guid-here', - parameters: { - org: 'invalid-org', - env: 'env-name-here', + it('Request with incorrect org to env mapping should return a 400 response', async () => { + let error = false + try { + const serviceInstance = { + instance_id: 'instance-guid-here', + payload: { + organization_guid: 'org-guid-here', + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + space_guid: 'space-guid-here', + parameters: { + org: 'invalid-org', + env: 'env-name-here', + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + serviceInstance.instance_id) + .send(serviceInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + serviceInstance.instance_id) - .send(serviceInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - it('Request with missing org should return a 400 response', function (done) { - var serviceInstance = { - instance_id: 'instance-guid-here', - payload: { - organization_guid: 'org-guid-here', - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - space_guid: 'space-guid-here', - parameters: { - env: 'env-name-here', + it('Request with missing org should return a 400 response', async () => { + let error = false + try { + const serviceInstance = { + instance_id: 'instance-guid-here', + payload: { + organization_guid: 'org-guid-here', + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + space_guid: 'space-guid-here', + parameters: { + env: 'env-name-here', + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + serviceInstance.instance_id) + .send(serviceInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + serviceInstance.instance_id) - .send(serviceInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - it('Request with missing env should return a 400 response', function (done) { - var serviceInstance = { - instance_id: 'instance-guid-here', - payload: { - organization_guid: 'org-guid-here', - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - space_guid: 'space-guid-here', - parameters: { - org: 'invalid-org', + it('Request with missing env should return a 400 response', async () => { + let error = false + try { + const serviceInstance = { + instance_id: 'instance-guid-here', + payload: { + organization_guid: 'org-guid-here', + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + space_guid: 'space-guid-here', + parameters: { + org: 'env-name-here', + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + serviceInstance.instance_id) + .send(serviceInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + serviceInstance.instance_id) - .send(serviceInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) }) - describe("Org Plan Request Validations", function(){ - it('Valid Auth on org route binding API with invalid org parameters should return 400 - target_app_port', function (done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', - target_app_port: '8080', -// protocol: 'http' + describe('Org Plan Request Validations', () => { + it('Valid Auth on org route binding API with invalid org parameters should return 400 - target_app_port', async () => { + let error = false + try { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + parameters: { + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'org-name-here', + env: 'env-name-here', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + target_app_port: '8080', + // protocol: 'http' + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - it('Valid Auth on org route binding API with invalid org parameters should return 400 - target_app_route', function (done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', - target_app_route: '8080', + it('Valid Auth on org route binding API with invalid org parameters should return 400 - target_app_route', async () => { + let error = false + try { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + parameters: { + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'org-name-here', + env: 'env-name-here', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + target_app_route: '8080', // protocol: 'http' + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - it('Valid Auth on org route binding API with invalid org parameters should return 400 - edgemicro_key', function (done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', - edgemicro_key: '8080', -// protocol: 'http' + it('Valid Auth on org route binding API with invalid org parameters should return 400 - edgemicro_key', async () => { + let error = false + try { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + parameters: { + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'org-name-here', + env: 'env-name-here', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + edgemicro_key: '8080', + // protocol: 'http' + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - it('Valid Auth on org route binding API with invalid org parameters should return 400 - edgemicro_secret', function (done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', - edgemicro_secret: '8080', -// protocol: 'http' + it('Valid Auth on org route binding API with invalid org parameters should return 400 - edgemicro_secret', async () => { + let error = false + try { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + parameters: { + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'org-name-here', + env: 'env-name-here', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + edgemicro_secret: '8080', + // protocol: 'http' + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - it('Valid Auth on org route binding API with invalid org parameters should return 400 - micro', function (done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', - micro: '8080', -// protocol: 'http' + it('Valid Auth on org route binding API with invalid org parameters should return 400 - micro', async () => { + let error = false + try { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + parameters: { + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'org-name-here', + env: 'env-name-here', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + micro: '8080', + // protocol: 'http' + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - }) - describe("Micro Plan Request Validations", function(){ - - it('Valid Auth on micro route binding API with missing micro parameter should return 400', function (done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.micro, - service_id: 'service-guid-here', - bind_resource: { - route: 'route-url-here' - }, - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', -// protocol: 'http' + describe('Micro Plan Request Validations', () => { + it('Valid Auth on micro route binding API with missing micro parameter should return 400', async () => { + let error = false + try { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.micro, + service_id: 'service-guid-here', + bind_resource: { + route: 'route-url-here' + }, + parameters: { + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'org-name-here', + env: 'env-name-here', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + // protocol: 'http' + } } } - } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) - }) - it('Valid Auth on micro route binding API with invalid micro parameters should return 400 - target_app_port', function (done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.micro, - service_id: 'service-guid-here', - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', - target_app_port: '8080', -// protocol: 'http' - } - } + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - it('Valid Auth on micro route binding API with invalid parameters should return 400 - target_app_route', function (done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.micro, - service_id: 'service-guid-here', - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', - target_app_route: '8080', -// protocol: 'http' + it('Valid Auth on micro route binding API with invalid parameters should return 400 - target_app_route', async () => { + let error = false + try { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.micro, + service_id: 'service-guid-here', + parameters: { + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'org-name-here', + env: 'env-name-here', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + target_app_route: '8080', + // protocol: 'http' + } } } + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) }) - it('Valid Auth on micro route binding API with invalid micro parameters should return 400 - edgemicro_key', function (done) { - var bindingInstance = { + it('Valid Auth on micro route binding API with invalid micro parameters should return 400 - edgemicro_key', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -449,15 +599,24 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Valid Auth on micro route binding API with invalid micro parameters should return 400 - edgemicro_secret', function (done) { - var bindingInstance = { + it('Valid Auth on micro route binding API with invalid micro parameters should return 400 - edgemicro_secret', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -475,19 +634,27 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - }) - describe("Micro coresident Plan Request Validations", function(){ + describe('Micro coresident Plan Request Validations', () => { - it('Valid Auth on coresident app binding API with missing "target_app_route" parameter should return 400', function (done) { - var bindingInstance = { + it('Valid Auth on coresident app binding API with missing "target_app_route" parameter should return 400', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -507,15 +674,24 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Valid Auth on coresident app binding API with missing "target_app_port" parameter should return 400', function (done) { - var bindingInstance = { + it('Valid Auth on coresident app binding API with missing "target_app_port" parameter should return 400', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -535,15 +711,24 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Valid Auth on coresident app binding API with missing "edgemicro_key" parameter should return 400', function (done) { - var bindingInstance = { + it('Valid Auth on coresident app binding API with missing "edgemicro_key" parameter should return 400', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -563,15 +748,24 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Valid Auth on coresident app binding API with missing "edgemicro_secret" parameter should return 400', function (done) { - var bindingInstance = { + it('Valid Auth on coresident app binding API with missing "edgemicro_secret" parameter should return 400', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -591,15 +785,24 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Valid Auth on coresident app binding API with invalid microgateway-coresident parameter "micro" should return 400', function (done) { - var bindingInstance = { + it('Valid Auth on coresident app binding API with invalid microgateway-coresident parameter "micro" should return 400', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -616,20 +819,29 @@ describe('Component APIs', function () { edgemicro_key: 'key', target_app_route: 'route-url-here', edgemicro_secret: 'secret', - micro: "micro route" + micro: 'micro route' // protocol: 'http' } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Binding with "bind-route-service" (route in bind_resource) instead of "bind-service" should return 400 with micro coresident plan', function (done) { - var bindingInstance = { + it('Binding with "bind-route-service" (route in bind_resource) instead of "bind-service" should return 400 with micro coresident plan', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -653,60 +865,83 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) }) - describe("Non Plan Based Request Content Validation", function(){ - - it('Invalid JSON req payload should return Json Schema Validation error', function (done) { - api.put('/v2/service_instances/12345/service_bindings/67890') - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .send("{'invalidJSON") - .expect(400) - .end(function (err, res) { - expect(err).equal(null) - expect(res.body).to.have.property('jsonSchemaValidation') - expect(res.body.jsonSchemaValidation).to.equal(true) - done() - }) + describe('Non Plan Based Request Content Validation', () => { + + it('Invalid JSON req payload should return Json Schema Validation error', async () => { + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/12345/service_bindings/67890') + .send('{\'invalidJSON') + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + expect(res.body.jsonSchemaValidation).to.equal(true) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Invalid Protocol on route binding API should return a 400', function(done) { - var bindingInstance = { - instance_id: 'instance-guid-here', - binding_id: 'binding-guid-here', - payload: { - plan_id: catalogData.guid.org, - service_id: 'service-guid-here', - bind_resource: { - route: 'route-url-here' - }, - parameters: { - host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'cdmo', - env: 'test', - user: 'XXXXX', - pass: 'XXXXXXX', - action: 'proxy bind', - protocol: 'htYp' - } - } - } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + it('Invalid Protocol on route binding API should return a 400', async () => { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.org, + service_id: 'service-guid-here', + bind_resource: { + route: 'route-url-here' + }, + parameters: { + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'cdmo', + env: 'test', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + protocol: 'htYp' + } + } + } + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send('{\'invalidJSON') + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + expect(res.body.jsonSchemaValidation).to.equal(true) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Valid Auth on route binding API with incorrect org/env mapping should return 400', function (done) { - var bindingInstance = { + it('Valid Auth on route binding API with incorrect org/env mapping should return 400', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -726,23 +961,41 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(400, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send('{\'invalidJSON') + .set('Accept', 'application/json') + .set('Authorization', authHeader) + + expect(res).to.have.status(400) + expect(res.body.jsonSchemaValidation).to.equal(true) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Invalid Auth should return 401', function (done) { - api.put('/v2/service_instances/:instance_id/service_bindings/:binding_id') - .set('Accept', 'application/json') - .expect(401, done) + it('Invalid Auth should return 401', async () => { + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/:instance_id/service_bindings/:binding_id') + .set('Accept', 'application/json') + expect(res).to.have.status(401) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) }) - describe('Route Binding APIs', function () { - it('Invalid Apigee Credentials should return a 407 response - http', function (done) { - var bindingInstance = { + describe('Route Binding APIs', () => { + it('Invalid Apigee Credentials should return a 400 without bind_resource response - http', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -751,9 +1004,9 @@ describe('Component APIs', function () { service_id: 'service-guid-here', space_guid: 'space-guid-here', parameters: { + org: 'cdmo', + env: 'test', host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), - org: 'org-name-here', - env: 'env-name-here', user: 'apigee-user-here', pass: 'apigee-pass-here', action: 'proxy bind', @@ -761,15 +1014,24 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(407, done) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Authorization', authHeader) + .set('Accept', 'application/json') + + expect(res).to.have.status(400) + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Valid Auth on route binding API should return 201 with route_service_url - org plan', function (done) { - var bindingInstance = { + it('Valid Auth on route binding API should return 201 with route_service_url - org plan', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -782,28 +1044,128 @@ describe('Component APIs', function () { host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), org: 'cdmo', env: 'test', - user: 'XXXXX', - pass: 'XXXXXXX', + user: 'tester', + pass: 'testing', action: 'proxy bind', -// protocol: 'http' + protocol: 'http' } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(201) - .end(function (err, res) { - expect(err).equal(null) - expect(res.body).to.have.property('route_service_url') - expect(res.body.route_service_url).to.equal('https://cdmo-test.apigee.net/route-url-here') - done() - }) + + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Authorization', authHeader) + .set('Accept', 'application/json') + + expect(res).to.have.status(201) + expect(res.body).to.have.property('route_service_url') + expect(res.body.route_service_url).to.equal('https://cdmo-test.onprem.net/route-url-here') + } catch (err) { + error = err + } finally { + error ? console.error('ERR', error) : null + expect(error).to.be.false + } }) - it('Valid Auth on route binding API should return 201 with route_service_url - micro plan', function (done) { - var bindingInstance = { + it('Valid on route binding API should return 201 with empty params - portal plan, action: proxy bind, no folder for app', async () => { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.portal, + service_id: 'service-guid-here', + context: { + space_guid: 'space-guid-here' + }, + bind_resource: { + route: 'bind_resource-route-url-here.com' + }, + parameters: { + bearer: '123', + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'cdmo', + env: 'test', + action: 'proxy bind', + target_app_route: 'target_app_route-here', + target_app_port: 80, + target_app_space_name: 'test', + protocol: 'http' + } + } + } + + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Authorization', authHeader) + .set('Accept', 'application/json') + + expect(res).to.have.status(201) + expect(res.body).to.have.property('route_service_url') + expect(res.body.route_service_url).to.equal('https://cdmo-test.onprem.net/target_app_route-here') + } catch (err) { + error = err + } finally { + error ? console.error('ERR', error) : null + expect(error).to.be.false + } + }) + + it('Valid on route binding API should return 201 with empty params - portal plan, action: proxy bind, create folder for app', async () => { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.portal, + service_id: 'service-guid-here', + context: { + space_guid: 'space-guid-here' + }, + bind_resource: { + route: 'bind_resource-route-url-here.com' + }, + parameters: { + bearer: '123', + host: config.default.get('APIGEE_PROXY_HOST_TEMPLATE'), + org: 'cdmo', + env: 'test', + action: 'proxy bind', + target_app_route: 'target_app_route-here', + target_app_port: 80, + target_app_space_name: 'test', + protocol: 'http', + with_docstore: true + } + } + } + + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Authorization', authHeader) + .set('Accept', 'application/json') + + expect(res).to.have.status(201) + expect(res.body).to.have.property('route_service_url') + expect(res.body.route_service_url).to.equal('https://cdmo-test.onprem.net/target_app_route-here') + } catch (err) { + error = err + } finally { + error ? console.error('ERR', error) : null + expect(error).to.be.false + } + }) + + it('Valid Auth on route binding API should return 201 with route_service_url - micro plan', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -824,21 +1186,26 @@ describe('Component APIs', function () { } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(201) - .end(function (err, res) { - expect(err).equal(null) - expect(res.body).to.have.property('route_service_url') - expect(res.body.route_service_url).to.equal('https://edgemicro-cf-app-url/route-url-here') - done() - }) + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Authorization', authHeader) + .set('Accept', 'application/json') + expect(res).to.have.status(201) + + expect(res.body).to.have.property('route_service_url') + expect(res.body.route_service_url).to.equal('https://edgemicro-cf-app-url/route-url-here') + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } }) - it('Valid Auth on route binding API should return 201 with route_service_url - micro coresident', function (done) { - var bindingInstance = { + it('Valid Auth on route binding API should return 201 with route_service_url - micro coresident', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here', payload: { @@ -856,71 +1223,136 @@ describe('Component APIs', function () { target_app_route: 'route-url-here', edgemicro_key: 'key', edgemicro_secret: 'secret' -// protocol: 'http' } } } - api.put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .send(bindingInstance.payload) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(201) - .end(function (err, res) { - expect(err).equal(null) - expect(res.body).to.have.property('credentials') - expect(res.body.credentials.edgemicro_key).to.equal('key') - expect(res.body.credentials.edgemicro_secret).to.equal('secret') - done() - }) + + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Authorization', authHeader) + .set('Accept', 'application/json') + expect(res).to.have.status(201) + expect(res.body).to.have.property('credentials') + expect(res.body.credentials.edgemicro_key).to.equal('key') + expect(res.body.credentials.edgemicro_secret).to.equal('secret') + } catch (err) { + error = err + } finally { + expect(error).to.be.false + } + }) + + it('Valid Auth on route binding API should return 201 with route_service_url - micro c2c', async () => { + const bindingInstance = { + instance_id: 'instance-guid-here', + binding_id: 'binding-guid-here', + payload: { + plan_id: catalogData.guid.micro_c2c, + service_id: 'service-guid-here', + bind_resource: { route: 'target_app_route-here.cf-base-domain' }, + parameters: { + org: 'cdmo', + env: 'test', + user: 'XXXXX', + pass: 'XXXXXXX', + action: 'proxy bind', + protocol: 'http', + target_app_port: 80, + target_app_route: 'app-name-here.apps.pcf24.apigee.xyz', + target_app_space_name: 'space-name-here' + } + } + } + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .send(bindingInstance.payload) + .set('Authorization', authHeader) + .set('Accept', 'application/json') + // expect(res).to.have.status(201) + expect(res.body).to.have.property('route_service_url') + } catch (err) { + error = err + } finally { + console.info('ERRintest', error) + expect(error).to.be.false + } }) }) - describe('Delete Route Binding & Delete Service Instance', function () { - it('Invalid Auth should return 401 on route binding deletion', function (done) { - api.put('/v2/service_instances/:instance_id/service_bindings/:binding_id') - .set('Accept', 'application/json') - .expect(401, done) + describe('Delete Route Binding & Delete Service Instance', () => { + it('Invalid Auth should return 401 on route binding deletion', async () => { + let error = false + try { + const res = await chai.request(server) + .put('/v2/service_instances/:instance_id/service_bindings/:binding_id') + + expect(res).to.have.status(401) + + } catch (err) { + error = err + } finally { + error ? console.info('ERRintest', error) : null + expect(error).to.be.false + } }) - it('Valid Auth on delete binding API call should return 200', function (done) { - var bindingInstance = { + it('Valid Auth on delete binding API call should return 200', async () => { + const bindingInstance = { instance_id: 'instance-guid-here', binding_id: 'binding-guid-here' } - api.del('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) - .set('Accept', 'application/json') - .set('Authorization', authHeader) - .expect(200, done) - }) - it('Invalid Auth should return 401 on service instance deletion', function (done) { - api.del('/v2/service_instances/:instance_id') - .set('Accept', 'application/json') - .expect(401, done) + + let error = false + try { + const res = await chai.request(server) + .del('/v2/service_instances/' + bindingInstance.instance_id + '/service_bindings/' + bindingInstance.binding_id) + .set('Accept', 'application/json') + .set('Authorization', authHeader) + expect(res).to.have.status(200) + } catch (err) { + error = err + } finally { + error ? console.info('ERRintest', error) : null + expect(error).to.be.false + } }) - it('Valid service instance delete should delete the instance and return 200', function (done) { - var serviceInstance = 'instance-guid-here' - api.del('/v2/service_instances/' + serviceInstance) - .set('Authorization', authHeader) - .expect(200, done) + it('Invalid Auth should return 401 on service instance deletion', async () => { + let error = false + try { + const res = await chai.request(server) + .del('/v2/service_instances/:instance_id') + .set('Accept', 'application/json') + + expect(res).to.have.status(401) + } catch (err) { + error = err + } finally { + error ? console.info('ERRintest', error) : null + expect(error).to.be.false + } }) + it('Valid service instance delete should delete the instance and return 200', async () => { + const serviceInstance = 'instance-guid-here' - }) - after(function (done) { // eslint-disable-line - this.timeout(0) - app.close() - done() - }) -}) + let error = false + try { + const res = await chai.request(server) + .del('/v2/service_instances/' + serviceInstance) + .set('Accept', 'application/json') + + expect(res).to.have.status(401) + } catch (err) { + error = err + } finally { + error ? console.info('ERRintest', error) : null + expect(error).to.be.false + } + }) -// console.log(config.default.get('APIGEE_DASHBOARD_URL')) -// console.log(config.getApigeeConfiguration("org1","tests", function(err, data){return "hi"})) -describe('Get Apigee Config', function () { - var org = 'test-org' - var env = 'test' - it("Config Module Should Return Expected Values", function(){ - chai.assert.equal(config.getApigeeConfiguration(org, env, function(err, data){if(err){console.log(err)} else{return data.get('APIGEE_DASHBOARD_URL')}}),'https://onprem.com/platform/#/') - chai.assert.equal(config.getApigeeConfiguration(org, env, function(err, data){if(err){console.log(err)} else{return data.get('APIGEE_MGMT_API_URL')}}),'https://onprem.com/v1') - chai.assert.equal(config.getApigeeConfiguration(org, env, function(err, data){if(err){console.log(err)} else{return data.get('APIGEE_PROXY_DOMAIN')}}),'onprem.net') - chai.assert.equal(config.getApigeeConfiguration(org, env, function(err, data){if(err){console.log(err)} else{return data.get('APIGEE_PROXY_HOST_TEMPLATE')}}),'${org}-${env}.${domain}') - chai.assert.equal(config.getApigeeConfiguration(org, env, function(err, data){if(err){console.log(err)} else{return data.get('APIGEE_PROXY_NAME_TEMPLATE')}}),'cf-${route}') }) }) +/* eslint-enable */ diff --git a/docs/apigee-service-broker-prerequisites.md b/docs/apigee-service-broker-prerequisites.md index c5ebf4b..b57a0a1 100644 --- a/docs/apigee-service-broker-prerequisites.md +++ b/docs/apigee-service-broker-prerequisites.md @@ -24,5 +24,7 @@ The following are prequisites for installing and using the Apigee Edge Cloud Fou - Apigee SSO CLI The broker will create the (reverse) proxy on Apigee Edge for the app's route. This requires authenticating with Edge; ideally this is done with an authorization token, generated with scripts in the [Apigee SSO CLI bundle](http://docs.apigee.com/api-services/content/using-oauth2-security-apigee-edge-management-api#installingacurlandgettokenutilities). Plain username and password may also be used if necessary. + +- Apigee organization name, created in your apigee account.You will use the name in service bindings. With Cloud Foundry, a *service broker* provides a catalog of services, and performs tasks to tie those services with applications and their routes. This broker only supports route services, to use Apigee as a reverse proxy for applications, and follows the standard route service flow. diff --git a/docs/setup-portal.md b/docs/setup-portal.md index 1fa50d2..c6e098c 100644 --- a/docs/setup-portal.md +++ b/docs/setup-portal.md @@ -177,9 +177,10 @@ Parameter | Purpose | Allowed Values `bearer` | Path to a file containing an authentication token valid for your organization | An authentication token, such as one generated with Apigee's get_token command. The broker does not store any data; it requires credentials and other parameters for each individual `cf` command. Instead of a `bearer` token, credentials can also be expressed as:
  • `basic`: standard HTTP Base-64 encoded username and password for `Authorization: Basic`. Note that this is *not encrypted* and easily converted to clear text. But a jumble of digits and letters may provide some protection in case of momentary exposure (but no better than if the password is already a jumble of digits, letters, and symbols)
  • username and password in clear text
`action` | A value specifying whether to create or bind an API proxy | `proxy` to generate an API proxy; `bind` to bind the service with the proxy; `proxy bind` to generate the proxy and bind with a single command. `protocol` | The protocol through which the proxy should be accessed by Cloud Foundry | `http` or `https`; default is `https`. -`target_app_route` | The app name with your API, "cf apps" output, column "name" -`target_app_port` | The app port +`target_app_route` | The app name with your API, "cf apps" output, column "name" +`target_app_port` | The app port `with_docstore` | Create a folder for app specs | Boolean, default: false +`with_cf_binding` | Bind all routes with cloud-foundry | Boolean, default: false ## Unbinding the route service diff --git a/samples/org-and-microgateway-sample/public/openApi.json b/samples/org-and-microgateway-sample/public/openApi.json index 81469fe..4d32598 100644 --- a/samples/org-and-microgateway-sample/public/openApi.json +++ b/samples/org-and-microgateway-sample/public/openApi.json @@ -10,7 +10,8 @@ "host": "127.0.0.1:3000", "basePath": "/", "schemes": [ - "http" + "http", + "https" ], "consumes": [ "application/json", @@ -214,13 +215,8 @@ } } }, - "security": [ - { - "mySecureApi1": [] - } - ], "summary": "delete User Info", - "d": "deleteUserInfo", + "operationId": "deleteUserInfo", "parameters": [ { "name": "name", diff --git a/samples/org-and-microgateway-sample/server.js b/samples/org-and-microgateway-sample/server.js index 3958f63..ac2e753 100644 --- a/samples/org-and-microgateway-sample/server.js +++ b/samples/org-and-microgateway-sample/server.js @@ -16,6 +16,8 @@ var express = require('express') var bodyParser = require('body-parser') var app = express() +var openApi = require('./public/openApi.json') + app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: true })) @@ -30,6 +32,11 @@ app.get('/', function (req, res) { res.json({ hello: "hello from cf app" }) }) +app.get('/openapi', function (req, res) { + res.json(openApi) +}) + + app.get('/hello', function (req, res) { res.json({ hello: "hello world" }) }) From f853a8ddc4031edf0741674b99c3b160bd85d233 Mon Sep 17 00:00:00 2001 From: Nosau Aliaksandr Date: Fri, 26 Jul 2019 16:54:42 +0300 Subject: [PATCH 4/5] edited env-example --- apigee-cf-service-broker/env-example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apigee-cf-service-broker/env-example b/apigee-cf-service-broker/env-example index 67bc383..f3b56b4 100644 --- a/apigee-cf-service-broker/env-example +++ b/apigee-cf-service-broker/env-example @@ -1,5 +1,5 @@ CF_LOGIN= CF_LOGIN_PASSWORD= -MICRO_C2C_APP_NAME= +MICROGATEWAY_APP_NAME= BROKER_APP_NAME= APPS_BASE_DOMAIN= \ No newline at end of file From 43b31fa9a19dac74ccd342915e97172c8989d119 Mon Sep 17 00:00:00 2001 From: Nosau Aliaksandr Date: Fri, 26 Jul 2019 16:56:03 +0300 Subject: [PATCH 5/5] removed unused files --- .../json-sample/cf-create-route.txt | 564 ------------------ 1 file changed, 564 deletions(-) delete mode 100644 apigee-cf-service-broker/json-sample/cf-create-route.txt diff --git a/apigee-cf-service-broker/json-sample/cf-create-route.txt b/apigee-cf-service-broker/json-sample/cf-create-route.txt deleted file mode 100644 index 129d6ce..0000000 --- a/apigee-cf-service-broker/json-sample/cf-create-route.txt +++ /dev/null @@ -1,564 +0,0 @@ -cf -v create-route dev apps.pcf24.apigee.xyz --hostname edgemicro-app-harper -REQUEST: [2019-05-31T17:41:47+03:00] -GET /v2/info HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:41:47+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 741 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:41:47 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: 79f4fcaa-4b4b-47be-4e19-bc367fce7032::9249ef92-3e3b-4b9a-a5ab-1770c5d20a32 -{ - "api_version": "2.125.0", - "app_ssh_endpoint": "ssh.system.pcf24.apigee.xyz:2222", - "app_ssh_host_key_fingerprint": "ef:5a:7f:72:24:1e:18:9c:e0:cc:39:21:a1:47:9a:cf", - "app_ssh_oauth_client": "ssh-proxy", - "authorization_endpoint": "https://login.system.pcf24.apigee.xyz", - "build": "2.4.1-build.1", - "description": "https://docs.pivotal.io/pivotalcf/2-3/pcf-release-notes/runtime-rn.html", - "doppler_logging_endpoint": "wss://doppler.system.pcf24.apigee.xyz:443", - "min_cli_version": "6.23.0", - "min_recommended_cli_version": "6.23.0", - "name": "Pivotal Application Service", - "osbapi_version": "2.14", - "routing_endpoint": "https://api.system.pcf24.apigee.xyz/routing", - "support": "https://support.pivotal.io", - "token_endpoint": "https://uaa.system.pcf24.apigee.xyz", - "version": 0 -} - - -REQUEST: [2019-05-31T17:41:47+03:00] -GET /login HTTP/1.1 -Host: login.system.pcf24.apigee.xyz -Accept: application/json -Connection: close -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:41:48+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Cache-Control: no-store -Content-Language: en-US -Content-Length: 411 -Content-Type: application/json;charset=UTF-8 -Date: Fri, 31 May 2019 14:41:47 GMT -Set-Cookie: X-Uaa-Csrf=gL1oNY6HMNxEucJCLXWTxr; Max-Age=86400; Expires=Sat, 01-Jun-2019 14:41:48 GMT; Path=/; Secure; HttpOnly -Strict-Transport-Security: max-age=31536000 ; includeSubDomains -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Frame-Options: DENY -X-Vcap-Request-Id: 1927171e-dd90-4efe-7a48-968f94a8d23d -X-Xss-Protection: 1; mode=block -{ - "app": { - "version": "4.24.0" - }, - "commit_id": "16d9900", - "entityID": "http://login.system.pcf24.apigee.xyz", - "idpDefinitions": {}, - "links": { - "login": "https://login.system.pcf24.apigee.xyz", - "passwd": "/forgot_password", - "register": "/create_account", - "uaa": "https://uaa.system.pcf24.apigee.xyz" - }, - "prompts": { - "password": "[PRIVATE DATA HIDDEN]", - "username": [ - "text", - "Email" - ] - }, - "timestamp": "2018-11-06T01:20:26+0000", - "zone_name": "uaa" -} - - -Creating route edgemicro-app-harper.apps.pcf24.apigee.xyz for org dev / space dev as brokeruser... -REQUEST: [2019-05-31T17:41:48+03:00] -GET /v2/spaces?order-by=name&q=name%3Adev&q=organization_guid%3Ad90cc2e5-3517-4504-aa87-6e68bbd15da6 HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:41:48+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 1651 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:41:48 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: fd944f2b-9ea9-41b8-5931-68d0f36eebee::dde506c2-8028-44b5-ae4d-00f66ad36722 -{ - "next_url": null, - "prev_url": null, - "resources": [ - { - "entity": { - "allow_ssh": true, - "app_events_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/app_events", - "apps_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/apps", - "auditors_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/auditors", - "developers_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/developers", - "domains_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/domains", - "events_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/events", - "isolation_segment_guid": null, - "managers_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/managers", - "name": "dev", - "organization_guid": "d90cc2e5-3517-4504-aa87-6e68bbd15da6", - "organization_url": "/v2/organizations/d90cc2e5-3517-4504-aa87-6e68bbd15da6", - "routes_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/routes", - "security_groups_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/security_groups", - "service_instances_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/service_instances", - "space_quota_definition_guid": null, - "staging_security_groups_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/staging_security_groups" - }, - "metadata": { - "created_at": "2019-04-19T14:08:18Z", - "guid": "15ecd7cf-42b0-439d-a009-57df23b9c400", - "updated_at": "2019-04-19T14:08:18Z", - "url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400" - } - } - ], - "total_pages": 1, - "total_results": 1 -} - - -REQUEST: [2019-05-31T17:41:48+03:00] -GET /v2/shared_domains?q=name+IN+apps.pcf24.apigee.xyz HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:41:48+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 531 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:41:48 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: ed779c12-aae3-4533-5ca7-9860fb05831f::794fd15d-7f7f-4f5b-bb32-34ca237eb499 -{ - "next_url": null, - "prev_url": null, - "resources": [ - { - "entity": { - "internal": false, - "name": "apps.pcf24.apigee.xyz", - "router_group_guid": null, - "router_group_type": null - }, - "metadata": { - "created_at": "2018-12-21T12:27:12Z", - "guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", - "updated_at": "2019-05-04T10:21:01Z", - "url": "/v2/shared_domains/bb8dec35-6535-4ca9-8bca-5b84230f394d" - } - } - ], - "total_pages": 1, - "total_results": 1 -} - - -REQUEST: [2019-05-31T17:41:48+03:00] -GET /v2/organizations/d90cc2e5-3517-4504-aa87-6e68bbd15da6/private_domains?q=name+IN+apps.pcf24.apigee.xyz HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:41:48+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 107 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:41:48 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: 205e7bc9-92bf-42c5-5976-baedc98a697d::a5b0e48e-6759-46e2-a780-de016c970556 -{ - "next_url": null, - "prev_url": null, - "resources": null, - "total_pages": 1, - "total_results": 0 -} - - -REQUEST: [2019-05-31T17:41:48+03:00] -GET /v2/routes?q=domain_guid%3Abb8dec35-6535-4ca9-8bca-5b84230f394d&q=host%3Aedgemicro-app-harper&q=path%3A HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:41:48+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 107 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:41:48 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: 77ff6d08-bc72-4da4-4d83-3d69e2248979::c78139c9-41f9-406e-acdf-06e75758c5c0 -{ - "next_url": null, - "prev_url": null, - "resources": null, - "total_pages": 1, - "total_results": 0 -} - - -REQUEST: [2019-05-31T17:41:48+03:00] -GET /v2/routes/reserved/domain/bb8dec35-6535-4ca9-8bca-5b84230f394d?host=edgemicro-app-harper HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:41:48+03:00] -HTTP/1.1 404 Not Found -Alt-Svc: clear -Content-Length: 86 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:41:48 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: 69b34b75-ab61-4ff3-57a6-ec48a5ca5d07::b680c427-dc73-471c-8ea7-71ff3a72c968 -{ - "code": 10000, - "description": "Unknown request", - "error_code": "CF-NotFound" -} - - -REQUEST: [2019-05-31T17:41:48+03:00] -POST /v2/routes HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -Content-Type: application/json -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) -{ - "domain_guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", - "host": "edgemicro-app-harper", - "port": null, - "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400" -} - - -RESPONSE: [2019-05-31T17:41:49+03:00] -HTTP/1.1 201 Created -Alt-Svc: clear -Content-Length: 769 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:41:49 GMT -Location: /v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295 -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: 6adb9799-0b0b-40ea-63ff-995728fb1417::f58e88ca-75cc-4117-a010-b4018f0ff75f -{ - "entity": { - "apps_url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295/apps", - "domain_guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", - "domain_url": "/v2/shared_domains/bb8dec35-6535-4ca9-8bca-5b84230f394d", - "host": "edgemicro-app-harper", - "path": "", - "port": null, - "route_mappings_url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295/route_mappings", - "service_instance_guid": null, - "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400", - "space_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400" - }, - "metadata": { - "created_at": "2019-05-31T14:41:49Z", - "guid": "1094e037-3f74-48db-a8ba-a8e71ab39295", - "updated_at": "2019-05-31T14:41:49Z", - "url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295" - } -} - - -Route edgemicro-app-harper.apps.pcf24.apigee.xyz has been created. -OK - - -cf -v create-route dev apps.pcf24.apigee.xyz --hostname edgemicro-app-harper -REQUEST: [2019-05-31T17:51:57+03:00] -GET /v2/info HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:51:58+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 741 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:51:57 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: d79df8b0-994d-473f-75b9-6c389858cf85::de2c8c08-567b-4160-890d-95839226d721 -{ - "api_version": "2.125.0", - "app_ssh_endpoint": "ssh.system.pcf24.apigee.xyz:2222", - "app_ssh_host_key_fingerprint": "ef:5a:7f:72:24:1e:18:9c:e0:cc:39:21:a1:47:9a:cf", - "app_ssh_oauth_client": "ssh-proxy", - "authorization_endpoint": "https://login.system.pcf24.apigee.xyz", - "build": "2.4.1-build.1", - "description": "https://docs.pivotal.io/pivotalcf/2-3/pcf-release-notes/runtime-rn.html", - "doppler_logging_endpoint": "wss://doppler.system.pcf24.apigee.xyz:443", - "min_cli_version": "6.23.0", - "min_recommended_cli_version": "6.23.0", - "name": "Pivotal Application Service", - "osbapi_version": "2.14", - "routing_endpoint": "https://api.system.pcf24.apigee.xyz/routing", - "support": "https://support.pivotal.io", - "token_endpoint": "https://uaa.system.pcf24.apigee.xyz", - "version": 0 -} - - -REQUEST: [2019-05-31T17:51:58+03:00] -GET /login HTTP/1.1 -Host: login.system.pcf24.apigee.xyz -Accept: application/json -Connection: close -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:51:58+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Cache-Control: no-store -Content-Language: en-US -Content-Length: 411 -Content-Type: application/json;charset=UTF-8 -Date: Fri, 31 May 2019 14:51:57 GMT -Set-Cookie: X-Uaa-Csrf=eeC7q2JU4o6gP4ziWKWNij; Max-Age=86400; Expires=Sat, 01-Jun-2019 14:51:58 GMT; Path=/; Secure; HttpOnly -Strict-Transport-Security: max-age=31536000 ; includeSubDomains -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Frame-Options: DENY -X-Vcap-Request-Id: 80ced4fc-126f-44f1-59af-76abb7b133fc -X-Xss-Protection: 1; mode=block -{ - "app": { - "version": "4.24.0" - }, - "commit_id": "16d9900", - "entityID": "http://login.system.pcf24.apigee.xyz", - "idpDefinitions": {}, - "links": { - "login": "https://login.system.pcf24.apigee.xyz", - "passwd": "/forgot_password", - "register": "/create_account", - "uaa": "https://uaa.system.pcf24.apigee.xyz" - }, - "prompts": { - "password": "[PRIVATE DATA HIDDEN]", - "username": [ - "text", - "Email" - ] - }, - "timestamp": "2018-11-06T01:20:26+0000", - "zone_name": "uaa" -} - - -Creating route edgemicro-app-harper.apps.pcf24.apigee.xyz for org dev / space dev as brokeruser... -REQUEST: [2019-05-31T17:51:58+03:00] -GET /v2/spaces?order-by=name&q=name%3Adev&q=organization_guid%3Ad90cc2e5-3517-4504-aa87-6e68bbd15da6 HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:51:58+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 1651 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:51:58 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: e47b0fd5-862e-4035-6538-74d3a91347c2::04af1293-4e62-405c-ac0e-21e6b8083e36 -{ - "next_url": null, - "prev_url": null, - "resources": [ - { - "entity": { - "allow_ssh": true, - "app_events_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/app_events", - "apps_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/apps", - "auditors_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/auditors", - "developers_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/developers", - "domains_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/domains", - "events_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/events", - "isolation_segment_guid": null, - "managers_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/managers", - "name": "dev", - "organization_guid": "d90cc2e5-3517-4504-aa87-6e68bbd15da6", - "organization_url": "/v2/organizations/d90cc2e5-3517-4504-aa87-6e68bbd15da6", - "routes_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/routes", - "security_groups_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/security_groups", - "service_instances_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/service_instances", - "space_quota_definition_guid": null, - "staging_security_groups_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400/staging_security_groups" - }, - "metadata": { - "created_at": "2019-04-19T14:08:18Z", - "guid": "15ecd7cf-42b0-439d-a009-57df23b9c400", - "updated_at": "2019-04-19T14:08:18Z", - "url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400" - } - } - ], - "total_pages": 1, - "total_results": 1 -} - - -REQUEST: [2019-05-31T17:51:58+03:00] -GET /v2/shared_domains?q=name+IN+apps.pcf24.apigee.xyz HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:51:58+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 531 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:51:58 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: f5392969-f180-4278-5b59-3526f28be7db::cebb0407-42a5-4779-9efc-8784966720d8 -{ - "next_url": null, - "prev_url": null, - "resources": [ - { - "entity": { - "internal": false, - "name": "apps.pcf24.apigee.xyz", - "router_group_guid": null, - "router_group_type": null - }, - "metadata": { - "created_at": "2018-12-21T12:27:12Z", - "guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", - "updated_at": "2019-05-04T10:21:01Z", - "url": "/v2/shared_domains/bb8dec35-6535-4ca9-8bca-5b84230f394d" - } - } - ], - "total_pages": 1, - "total_results": 1 -} - - -REQUEST: [2019-05-31T17:51:58+03:00] -GET /v2/organizations/d90cc2e5-3517-4504-aa87-6e68bbd15da6/private_domains?q=name+IN+apps.pcf24.apigee.xyz HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:51:58+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 107 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:51:58 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: bb493b94-833c-4c9a-6217-01a4acce8c81::5c98f3bc-e401-4e54-945f-8abeeb8634b0 -{ - "next_url": null, - "prev_url": null, - "resources": null, - "total_pages": 1, - "total_results": 0 -} - - -REQUEST: [2019-05-31T17:51:58+03:00] -GET /v2/routes?q=domain_guid%3Abb8dec35-6535-4ca9-8bca-5b84230f394d&q=host%3Aedgemicro-app-harper&q=path%3A HTTP/1.1 -Host: api.system.pcf24.apigee.xyz -Accept: application/json -Authorization: [PRIVATE DATA HIDDEN] -User-Agent: cf/6.44.1+c3b20bfbe.2019-05-08 (go1.12.5; amd64 linux) - -RESPONSE: [2019-05-31T17:51:59+03:00] -HTTP/1.1 200 OK -Alt-Svc: clear -Content-Length: 956 -Content-Type: application/json;charset=utf-8 -Date: Fri, 31 May 2019 14:51:58 GMT -Server: nginx -Via: 1.1 google -X-Content-Type-Options: nosniff -X-Vcap-Request-Id: 98560c58-72fa-4a97-4f96-785017f82668::7d405fa9-0e37-4098-8f59-986424a6c707 -{ - "next_url": null, - "prev_url": null, - "resources": [ - { - "entity": { - "apps_url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295/apps", - "domain_guid": "bb8dec35-6535-4ca9-8bca-5b84230f394d", - "domain_url": "/v2/shared_domains/bb8dec35-6535-4ca9-8bca-5b84230f394d", - "host": "edgemicro-app-harper", - "path": "", - "port": null, - "route_mappings_url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295/route_mappings", - "service_instance_guid": null, - "space_guid": "15ecd7cf-42b0-439d-a009-57df23b9c400", - "space_url": "/v2/spaces/15ecd7cf-42b0-439d-a009-57df23b9c400" - }, - "metadata": { - "created_at": "2019-05-31T14:41:49Z", - "guid": "1094e037-3f74-48db-a8ba-a8e71ab39295", - "updated_at": "2019-05-31T14:41:49Z", - "url": "/v2/routes/1094e037-3f74-48db-a8ba-a8e71ab39295" - } - } - ], - "total_pages": 1, - "total_results": 1 -} - - -Route edgemicro-app-harper.apps.pcf24.apigee.xyz already exists. - -OK