Commit af227a7b authored by Roger Meier's avatar Roger Meier 🐋
Browse files

Merge branch 'feat/mdsp-client-agent' into 'master'

feat: mindsphere agent onboarding and data upload

See merge request !26
parents 4bfecb00 9273f851
Pipeline #56186076 passed with stages
in 10 minutes and 16 seconds
......@@ -48,6 +48,7 @@ test:
- yarn test --no-progress --code-coverage
- yarn --cwd server
- yarn --cwd devops/devopsadmin
- yarn --cwd agent
- yarn license:all
- export BASE_URL=http://$(hostname -i):3000
- yarn e2e
......
......@@ -27,6 +27,8 @@ The demo consists of:
- [devopsadmin app](devops/devopsadmin)
- [Prometheus on CloudFoundry](devops/prometheus)
- [Grafana on CloudFoundry](devops/grafana)
- a [sample agent](agent) that can be used to simulate an actual device sending
IoT data to the MindSphere APIs
Additionally, [tooling to ease ssh connectivity to running cf applications](tools/README.md)
is provided.
......
/agentconfig.json
/assetdata.json
/.mc/
# DevOps Demo Agent
This is a sample showing how to onboard an agent and upload data (data points,
events, files).
The demo is based on the starter code generated by the
[mindconnect-nodejs library](https://github.com/mindsphere/mindconnect-nodejs)
and uses this library for connectivity.
## Prerequisites
It's required to create two assets in the MindSphere Asset Manager with the
[same configuration as the sample in mindconnect-nodejs](https://github.com/mindsphere/mindconnect-nodejs#step-0-create-an-asset-type-and-aspect-types)
for this to work:
```
AspectType 'Environment'
Variables
'Humidity' INT %
'Pressure' DOUBLE kPA
'Temperature' DOUBLE ºC
AspectType 'Vibration'
Variables
'Acceleration' DOUBLE mm/s^2
'Displacement' DOUBLE mm
'Frequency' DOUBLE Hz
'Velocity' DOUBLE mm/s
AssetType 'TestAssetType'
Aspects
'EnvironmentData': Type 'Environment'
'VibrationData': Type 'Vibration'
Asset 'TestAsset'
Type: 'TestAssetType'
Asset 'TestAgent'
Type: 'MindConnect Lib'
```
- The first Asset is the actual instantiation of the defined Aspects + Aspect
Types, the type will be whatever Asset Type you defined earlier in the
Asset Manager
- The second Asset is the Agent, and must be of type `core.mclib`. We need to
define all the Aspects again in the agent, and then need to map them to the
actual values in the first Asset
1. Create the Aspect Types with their Variables
1. Create an Asset Type that references the Aspect Types you created earlier
1. Create the first Asset with type the Asset Type created earlier
1. Create the second Asset (the Agent) with type `MindConnect Lib`:
- Choose a security profile and generate the onboarding key json
- Copy the key data, you'll need it later for the `agentconfig.json` file
1. Configure the Agent:
- In the *Configuration* tab, creating a Data Source for each of the Aspect
Types instantiated earlier, adding inside Data Points matching each of the
Variables of the Aspect Type (the name can be chosen freely, but the Data
Type and Unit must match)
- Then in the *Data mappings* tab, link each of the variables (Data Points)
to the Aspects of the Asset. You'll have to click the *Link variable* link
and then search for the Asset. Please note that you will only be able to
link Data Points that are compatible (type and units match)
After this you will have an Agent linked to the Asset, and you will be able to
deliver data points to the Asset via the Agent.
## How to run
1. Install the dependencies
```sh
yarn install
```
1. Download the [initial JSON token of your agent](https://developer.mindsphere.io/howto/howto-agent-onboard.html#getting-the-boarding-configuration)
and save it as `agentconfig.json`. If you prefer to do this manually,
you can use `agentconfig.sample.json` as a template
1. Copy the file `assetmanager.sample.json` to `assetmanager.json` and adapt the
identifiers of the Asset and the Data Points. You can find them in the Asset
and Agent configurations of the MindSphere Asset Manager
1. Run the code. The script will perform the agent onboarding and upload
timeseries data, create an event and upload a file
```sh
yarn start
```
1. Now you can go to the MindSphere Fleet Manager to view the uploaded data
## Notes
The timeseries data in MindSphere can be assigned to either the Agent or the
Assets. There's use cases in which it is useful to map from a single agent to
one or multiple assets, e.g. when you have an environment temperature sensor
data and you want to assign that timeseries data to all the assets which are
in the room.
The files and the events don't require mappings and they can be assigned
directly to the assets.
It is in most cases the best option to keep everything in the actual Asset and
not to upload any data to the Agent. The Agent has other interesting data
though, like the *Online Status*
## TODOs
- Perform the Agent onboarding automatically via API calls to the
*Agent Management Service*
{
"content": {
"baseUrl": "https://southgate.eu1.mindsphere.io",
"iat": "<yourtoken>",
"clientCredentialProfile": [
"SHARED_SECRET"
],
"clientId": "<youragentid>",
"tenant": "<yourtenant>"
},
"expiration": "<yourexpiration>"
}
{
"assetId": "<changeme>",
"dataPoints": {
"environment": {
"temperatureId": "<changeme>",
"humidityId": "<changeme>",
"pressureId": "<changeme>"
},
"vibration": {
"accelerationId": "<changeme>",
"displacementId": "<changeme>",
"frequencyId": "<changeme>",
"velocityId": "<changeme>"
}
}
}
/*
Copyright Siemens AG 2019
SPDX-License-Identifier: MIT
*/
const {MindConnectAgent, retry} = require('@mindconnect/mindconnect-nodejs');
(async function () {
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const configuration = require('./agentconfig.json');
const assetdata = require('./assetdata.json');
const agent = new MindConnectAgent(configuration);
const log = (text) => {
console.log(`[${new Date().toISOString()}] ${text.toString()}`);
};
const RETRYTIMES = 5; // retry the operation before giving up and throwing exception
for (let index = 0; index < 5; index++) {
try {
log(`Iteration : ${index}`);
// onboarding the agent
if (!agent.IsOnBoarded()) {
// wrapping the call in the retry function makes the agent a bit more resilient
// if you don't want to retry the operations you can always just call await agent.OnBoard(); instead.
await retry(RETRYTIMES, () => agent.OnBoard());
log('Agent onboarded');
}
if (!agent.HasDataSourceConfiguration()) {
await retry(RETRYTIMES, () => agent.GetDataSourceConfiguration());
log('Configuration acquired');
}
const values = [
{
'dataPointId': assetdata.dataPoints.environment.temperatureId,
'qualityCode': '0',
'value': (Math.sin(index) * (20 + index % 2) + 25).toString()
},
{
'dataPointId': assetdata.dataPoints.environment.pressureId,
'qualityCode': '0',
'value': (Math.cos(index) * (20 + index % 25) + 25).toString()
},
{
'dataPointId': assetdata.dataPoints.environment.humidityId,
'qualityCode': '0',
'value': ((index + 30) % 100).toString()
},
{
'dataPointId': assetdata.dataPoints.vibration.accelerationId,
'qualityCode': '0',
'value': (1000.0 + index).toString()
},
{
'dataPointId': assetdata.dataPoints.vibration.frequencyId,
'qualityCode': '0',
'value': (60.0 + (index * 0.1)).toString()
},
{
'dataPointId': assetdata.dataPoints.vibration.displacementId,
'qualityCode': '0',
'value': (index % 10).toString()
},
{
'dataPointId': assetdata.dataPoints.vibration.velocityId,
'qualityCode': '0',
'value': (50.0 + index).toString()
}
];
// same like above, you can also just call await agent.PostData(values) if you don't want to retry the operation
// this is how to send the data with specific timestamp
// await agent.PostData(values, new Date(Date.now() - 86400 * 1000));
await retry(RETRYTIMES, () => agent.PostData(values));
log('Data posted');
await sleep(1000);
const event = {
// 'entityId': agent.ClientId(), // use assetid if you want to send event somewhere else :)
'entityId': assetdata.assetId,
'sourceType': 'Event',
'sourceId': 'application',
'source': 'Meowz',
'severity': 20, // 0-99 : 20:error, 30:warning, 40: information
'timestamp': new Date().toISOString(),
'description': 'Test'
};
// send event with current timestamp; you can also just call agent.PostEvent(event) if you don't want to retry the operation
await retry(RETRYTIMES, () => agent.PostEvent(event));
log('event posted');
await sleep(1000);
// upload file; you can also just call await agent.Upload(...) if you don't want to retry the operation
await retry(RETRYTIMES, () => agent.Upload('README.md', 'application/json', 'Demo File', true, assetdata.assetId));
log('file uploaded');
await sleep(1000);
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const bulk = [
{
'timestamp': yesterday.toISOString(),
'values': [
{
'dataPointId': assetdata.dataPoints.environment.temperatureId,
'qualityCode': '0',
'value': '10'
},
{
'dataPointId': assetdata.dataPoints.environment.pressureId,
'qualityCode': '0',
'value': '10'
},
{
'dataPointId': assetdata.dataPoints.environment.humidityId,
'qualityCode': '0',
'value': '10'
}
]
},
{
'timestamp': new Date().toISOString(),
'values': [
{
'dataPointId': assetdata.dataPoints.environment.temperatureId,
'qualityCode': '0',
'value': '10'
},
{
'dataPointId': assetdata.dataPoints.environment.pressureId,
'qualityCode': '0',
'value': '10'
},
{
'dataPointId': assetdata.dataPoints.environment.humidityId,
'qualityCode': '0',
'value': '10'
}
]
}
];
await retry(RETRYTIMES, () => agent.BulkPostData(bulk));
log('bulk data uploaded');
await sleep(1000);
} catch (err) {
// add proper error handling (e.g. store data somewhere, retry later etc. )
console.error(err);
}
}
})();
{
"name": "devops-agent",
"version": "0.1.0",
"description": "Sample MindConnect NodeJS Agent",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"author": "Diego Louzán <diego.louzan.ext@siemens.com>",
"contributors": [
"Roger Meier <r.meier@siemens.com>"
],
"license": "MIT",
"private": true,
"engines": {
"node": "^8.11.1",
"npm": "^5.6.0"
},
"dependencies": {
"@mindconnect/mindconnect-nodejs": "^3.3.0"
}
}
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@mindconnect/mindconnect-nodejs@^3.3.0":
version "3.3.0"
resolved "https://registry.yarnpkg.com/@mindconnect/mindconnect-nodejs/-/mindconnect-nodejs-3.3.0.tgz#32c49890ff32541cb7429ba34674a7f7e1e062a8"
integrity sha512-i/9VN8zQZiFe0JN2kfhAeGPEdUboTQB2Zg8E9LryjNBNXFn99Yt46fWBEP28PhMqNyMAuUJGZf2OF6URdCz8mA==
dependencies:
ajv "^6.9.2"
ajv-keywords "^3.4.0"
async-lock "^1.1.4"
buffer-concat "^1.0.0"
chalk "^2.4.2"
commander "^2.19.0"
csvtojson "^2.0.8"
debug "^4.1.1"
https-proxy-agent "^2.2.1"
json-groupby "^1.1.0"
jsonwebtoken "^8.5.0"
lodash "^4.17.11"
mime-types "^2.1.22"
node-fetch "^1.7.3"
rsa-pem-to-jwk "^1.1.3"
url-search-params-polyfill "^5.0.0"
uuid "^3.3.2"
agent-base@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==
dependencies:
es6-promisify "^5.0.0"
ajv-keywords@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d"
integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==
ajv@^6.9.2:
version "6.10.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
dependencies:
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-styles@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
async-lock@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.1.4.tgz#863aff9d5c243f75034349be7df9c3ceb7a54254"
integrity sha512-9vsVXt+mIvb8rV0G6V1x68Bvp/VksPJoZJxF/n/l9N60chNJ44opPr9WdZZfAV3leUdXt4xNvfyNWyY/j5enBA==
bluebird@^3.5.1:
version "3.5.3"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7"
integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==
buffer-concat@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-concat/-/buffer-concat-1.0.0.tgz#2defadadcb145e0ad3c0b961cde1910b118d1fe6"
integrity sha1-Le+trcsUXgrTwLlhzeGRCxGNH+Y=
buffer-equal-constant-time@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=
chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
color-convert@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
commander@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
csvtojson@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/csvtojson/-/csvtojson-2.0.8.tgz#d889f19576b2b33ead235490d2e5c9791481e8d3"
integrity sha512-DC6YFtsJiA7t/Yz+KjzT6GXuKtU/5gRbbl7HJqvDVVir+dxdw2/1EgwfgJdnsvUT7lOnON5DvGftKuYWX1nMOQ==
dependencies:
bluebird "^3.5.1"
lodash "^4.17.3"
strip-bom "^2.0.0"
debug@^3.1.0:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
dependencies:
ms "^2.1.1"
debug@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
ecdsa-sig-formatter@1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz#1c595000f04a8897dfb85000892a0f4c33af86c3"
integrity sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=
dependencies:
safe-buffer "^5.0.1"
encoding@^0.1.11:
version "0.1.12"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=
dependencies:
iconv-lite "~0.4.13"
es6-promise@^4.0.3:
version "4.2.5"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
es6-promisify@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
dependencies:
es6-promise "^4.0.3"
escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
fast-deep-equal@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
https-proxy-agent@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==
dependencies:
agent-base "^4.1.0"
debug "^3.1.0"
iconv-lite@~0.4.13:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
is-stream@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
json-groupby@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/json-groupby/-/json-groupby-1.1.0.tgz#7af5e0ed70118dd21ea41fa92fa75365f979f55a"
integrity sha1-evXg7XARjdIepB+pL6dTZfl59Vo=
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
jsonwebtoken@^8.5.0:
version "8.5.0"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz#ebd0ca2a69797816e1c5af65b6c759787252947e"
integrity sha512-IqEycp0znWHNA11TpYi77bVgyBO/pGESDh7Ajhas+u0ttkGkKYIIAjniL4Bw5+oVejVF+SYkaI7XKfwCCyeTuA==
dependencies:
jws "^3.2.1"
lodash.includes "^4.3.0"
lodash.isboolean "^3.0.3"
lodash.isinteger "^4.0.4"
lodash.isnumber "^3.0.3"
lodash.isplainobject "^4.0.6"
lodash.isstring "^4.0.1"
lodash.once "^4.0.0"
ms "^2.1.1"
semver "^5.6.0"
jwa@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.2.0.tgz#606da70c1c6d425cad329c77c99f2df2a981489a"
integrity sha512-Grku9ZST5NNQ3hqNUodSkDfEBqAmGA1R8yiyPHOnLzEKI0GaCQC/XhFmsheXYuXzFQJdILbh+lYBiliqG5R/Vg==
dependencies:
buffer-equal-constant-time "1.0.1"
ecdsa-sig-formatter "1.0.10"
safe-buffer "^5.0.1"
jws@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.1.tgz#d79d4216a62c9afa0a3d5e8b5356d75abdeb2be5"
integrity sha512-bGA2omSrFUkd72dhh05bIAN832znP4wOU3lfuXtRBuGTbsmNmDXMQg28f0Vsxaxgk4myF5YkKQpz6qeRpMgX9g==
dependencies:
jwa "^1.2.0"
safe-buffer "^5.0.1"
lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=
lodash.isboolean@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=
lodash.isinteger@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=
lodash.isnumber@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"
integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=
lodash.isplainobject@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
lodash.isstring@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
lodash.once@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=
lodash@^4.17.11, lodash@^4.17.3:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
mime-db@~1.38.0:
version "1.38.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad"
integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==
mime-types@^2.1.22:
version "2.1.22"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd"
integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
dependencies:
mime-db "~1.38.0"
ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"