diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..00854360fd60fab5947a4425ab04a981139dd5a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*~ +.swp +.bak +node_modules/ +pkg/ +vendor/ +dist/ +bin +examples/demo1/bin diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000000000000000000000000000000000000..a0b6465f89521fb709221a2f85bfe1c29f02a808 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,34 @@ +linters: + disable-all: true + enable: + - deadcode + # - depguard + # - dupl + - errcheck + # - gochecknoglobals + # - gochecknoinits + # - goconst + # - gocritic + # - gocyclo + # - gofmt + - goimports + # - golint + # - gosec + - gosimple + - govet + - ineffassign + # - interfacer + # - lll + # - maligned + # - misspell + # - nakedret + # - prealloc + # - scopelint + - staticcheck + - structcheck + # - stylecheck + - typecheck + # - unconvert + # - unparam + - unused + - varcheck \ No newline at end of file diff --git a/.meepctl-repocfg.yaml b/.meepctl-repocfg.yaml index 4f926d173dc3f75b7891f885292fa40c29459d9f..451ec352a7d9f87a595d80b2538a445d0e882412 100644 --- a/.meepctl-repocfg.yaml +++ b/.meepctl-repocfg.yaml @@ -6,62 +6,86 @@ repo: meep-user: service-account: charts/meep-user/meep-user-serviceaccount.yaml cluster-role-binding: charts/meep-user/meep-user-clusterrolebinding.yaml + codecov: false + lint: false meep-ctrl-engine: - src: src/meep-ctrl-engine + src: go-apps/meep-ctrl-engine bin: bin/meep-ctrl-engine chart: charts/meep-ctrl-engine - meep-initializer: - src: src/meep-initializer - bin: bin/meep-initializer - chart: charts/meep-initializer + codecov: true + lint: true + docker-data: + static: bin/meep-frontend + meep-frontend: + src: js-apps/meep-frontend + bin: bin/meep-frontend + codecov: false + lint: true + local-deps: + meep-ctrl-engine-api: js-packages/meep-ctrl-engine-client + meep-webhook: + src: go-apps/meep-webhook + bin: bin/meep-webhook + chart: charts/meep-webhook + build-flags: + - -mod=vendor + codecov: false + lint: true meep-mg-manager: - src: src/meep-mg-manager + src: go-apps/meep-mg-manager bin: bin/meep-mg-manager chart: charts/meep-mg-manager + codecov: true + lint: true meep-mon-engine: - src: src/meep-mon-engine + src: go-apps/meep-mon-engine bin: bin/meep-mon-engine chart: charts/meep-mon-engine + build-flags: + - -mod=vendor + codecov: true + lint: true meep-tc-engine: - src: src/meep-tc-engine + src: go-apps/meep-tc-engine bin: bin/meep-tc-engine chart: charts/meep-tc-engine + codecov: true + lint: true meep-tc-sidecar: - src: src/meep-tc-sidecar + src: go-apps/meep-tc-sidecar bin: bin/meep-tc-sidecar + codecov: false + lint: true meep-virt-engine: - src: src/meep-virt-engine + src: go-apps/meep-virt-engine bin: bin/meep-virt-engine chart: charts/meep-virt-engine template: charts/meep-virt-engine/virt-templates + codecov: true + lint: true dep: elastic: es: - version: 1.9.1 - values: charts/elasticsearch/elastic-values.yaml chart: incubator/elasticsearch + version: "1.9.1" + values: charts/elasticsearch/elastic-values.yaml pv: charts/elasticsearch/meep-pv-es.yaml es-curator: chart: charts/elasticsearch-curator kibana: - version: 0.14.5 - values: charts/kibana/kibana-values.yaml - chart: stable/kibana + chart: charts/kibana filebeat: - version: 1.0.2 - values: charts/filebeat/filebeat-values.yaml chart: stable/filebeat + version: "1.0.2" + values: charts/filebeat/values.yaml metricbeat: - template: charts/metricbeat/values-template.yaml - values: charts/metricbeat/values.yaml chart: charts/metricbeat couchdb: chart: charts/couchdb - pv: charts/couchdb/meep-pv-couchdb.yaml redis: - version: 4.0.1 - values: charts/redis/redis-values.yaml chart: stable/redis + version: "4.0.1" + values: charts/redis/values.yaml k8s: kube-state-metrics: chart: charts/kube-state-metrics diff --git a/README.md b/README.md index 23bcad60730f0e07321ac2d5c59d81a6bfd6f5ae..c0bbee1903f8b1fb16acd3ff7c03e82bc3f3a440 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,84 @@ -# AdvantEDGE +![AdvantEDGE-logo](./docs/images/AdvantEDGE-logo_Blue-01.png) -AdvantEDGE is a Mobile Edge Emulation Platform (MEEP) that runs on Docker & Kubernetes +AdvantEDGE is a Mobile Edge Emulation Platform (MEEP) that runs on Docker & Kubernetes. -MEEP provides an environment to experiment with Mobile Edge Computing (MEC) technologies and edge / fog deployment models in short and agile iterations. +> AdvantEDGE provides an emulation environment, enabling experimentation with Edge Computing Technologies, Applications, and Services. The platform facilitates users to explore edge / fog deployment models and their impact to applications and services in short and agile iterations. + +## Motivation -## Motivations - [x] **Accelerate Mobile Edge Computing adoption** - [x] **Discover new edge application use cases & services** -- [x] **Answer these questions:** - * Where should my application components be located in the network? - * What are network characteristics limitations of my application? - * How will my application behave when the user moves in the network? +- [x] **Help to answer questions such as:** + - Where should my application components be located in the edge network? + - How do network characteristics (such as latency, jitter, and packet loss) impact my application or service? + - How will my application behave when the user moves within and across access networks? + +## Intended Users + +- [x] **Edge Application Developers** +- [x] **Edge Network and Service Designers** +- [x] **Edge Researchers** +- [x] **Technologists that are simply interestied learning how the Edge works** + +## Concepts + +An understanding of some AdvantEDGE concepts is helpful towards effectively using the platform and understanding how it works. + +Before getting started we recommend familiarity with key [AdvantEDGE concepts](docs/concepts.md) ## Getting started -* [Setup runtime environment (Ubuntu/Dockers/Kubernetes/Helm)](docs/setup_runtime.md) -* Clone the AdvanteDGE repo
+- [Setup runtime environment (Ubuntu/Dockers/Kubernetes/Helm)](docs/setup_runtime.md) + +- Clone the AdvantEDGE repo + ``` + git clone https://github.com//AdvantEDGE.git + ``` + > **Note:** Assumes local gitdir = `~/AdvantEDGE` + +- Obtain AdvantEDGE binaries + - [Build from source](#building) + - Optionally use pre-built binaries (from GitHub release) + ``` + # Get bin folder tarball from desired release + cd ~/AdvantEDGE + tar -zxvf advantedge..linux-amd64.tar.gz + ``` + +- Setup [*meepctl*](docs/meepctl/meepctl.md) tool + - Copy to an executable path + ``` + sudo cp ~/AdvantEDGE/bin/meepctl/meepctl /usr/local/bin/ + ``` + - Configure + ``` + meepctl config set --ip --gitdir /home//AdvantEDGE + ``` + +- [Deploy AdvantEDGE](docs/deploy.md) + +- [Use AdvantEDGE](docs/use.md) + +## Building + +- [Setup development environment (Ubuntu/Go/Node.js/NPM/Linters)](docs/setup_dev.md) + +- Clone the AdvantEDGE repo
`git clone https://github.com//AdvantEDGE.git`
(*assuming local gitdir =* `~/AdvantEDGE`) -* Setup [*meepctl*](docs/meepctl/meepctl.md) tool - 1. Copy to an executable path
- `sudo cp ~/AdvantEDGE/bin/meepctl/meepctl /usr/local/bin/` - 2. Configure
- `meepctl config set --ip --gitdir /home//AdvantEDGE` +- [Build AdvantEDGE](docs/build.md) -* [Deploy AdvantEDGE](docs/deploy.md) +## Testing -* [Use AdvantEDGE](docs/use.md) - -## Concepts -The following AdvantEDGE concepts are described [here](docs/concepts.md) -- [x] Micro-service Architecture -- [x] Macro-network Model -- [x] Network characteristics -- [x] Network mobility -- [x] External UE support +The AdvantEDGE platform test procedures are described [here](docs/testing.md) ## Upstream communication + We use GitHub issues. So just open an issue in the repo to provide user feedback, report software bugs or request enhancements. ## Licensing + Currently licensed under the *AdvantEDGE Limited Evaluation and Use License Agreement* diff --git a/bin/meep-ctrl-engine/Dockerfile b/bin/meep-ctrl-engine/Dockerfile deleted file mode 100644 index 60f3acda551b7c5a50c0f7a0991045e4191d98cb..0000000000000000000000000000000000000000 --- a/bin/meep-ctrl-engine/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2017 The Kubernetes Authors. -# -# 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. - -FROM debian:9.6-slim -COPY ./meep-ctrl-engine /meep-ctrl-engine -COPY ./static /static -ENTRYPOINT /meep-ctrl-engine diff --git a/bin/meep-ctrl-engine/meep-ctrl-engine b/bin/meep-ctrl-engine/meep-ctrl-engine deleted file mode 100755 index 81fa3541d1ff447762c5dbb132f8471d70c8b43d..0000000000000000000000000000000000000000 Binary files a/bin/meep-ctrl-engine/meep-ctrl-engine and /dev/null differ diff --git a/bin/meep-ctrl-engine/static/api/favicon-16x16.png b/bin/meep-ctrl-engine/static/api/favicon-16x16.png deleted file mode 100644 index 0f7e13b0d9903d27a9129950b1dad362361504e4..0000000000000000000000000000000000000000 Binary files a/bin/meep-ctrl-engine/static/api/favicon-16x16.png and /dev/null differ diff --git a/bin/meep-ctrl-engine/static/api/favicon-32x32.png b/bin/meep-ctrl-engine/static/api/favicon-32x32.png deleted file mode 100644 index b0a3352ffd3fec6f2afb4cfcc34ec3a2976f45e3..0000000000000000000000000000000000000000 Binary files a/bin/meep-ctrl-engine/static/api/favicon-32x32.png and /dev/null differ diff --git a/bin/meep-ctrl-engine/static/api/index.html b/bin/meep-ctrl-engine/static/api/index.html deleted file mode 100644 index cb78c50dfd90bdf251134d7f1b9a49757503553c..0000000000000000000000000000000000000000 --- a/bin/meep-ctrl-engine/static/api/index.html +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - Swagger UI - - - - - - - -
- - - - - - diff --git a/bin/meep-ctrl-engine/static/api/oauth2-redirect.html b/bin/meep-ctrl-engine/static/api/oauth2-redirect.html deleted file mode 100644 index fb68399d264fc3755ba3d19713803ce0805f5b50..0000000000000000000000000000000000000000 --- a/bin/meep-ctrl-engine/static/api/oauth2-redirect.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - diff --git a/bin/meep-ctrl-engine/static/api/swagger-ui-bundle.js b/bin/meep-ctrl-engine/static/api/swagger-ui-bundle.js deleted file mode 100644 index d42fdade3a1001e5a9a5fa4a2474b2bd759f2795..0000000000000000000000000000000000000000 --- a/bin/meep-ctrl-engine/static/api/swagger-ui-bundle.js +++ /dev/null @@ -1,93 +0,0 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SwaggerUIBundle=t():e.SwaggerUIBundle=t()}(this,function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=446)}([function(e,t,n){"use strict";e.exports=n(75)},function(e,t,n){e.exports=n(854)()},function(e,t,n){"use strict";t.__esModule=!0,t.default=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t,n){"use strict";t.__esModule=!0;var r,o=n(262),i=(r=o)&&r.__esModule?r:{default:r};t.default=function(){function e(e,t){for(var n=0;n>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?C(e)+t:t}function A(){return!0}function O(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function P(e,t){return M(e,t,0)}function T(e,t){return M(e,t,t)}function M(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var I=0,j=1,N=2,R="function"==typeof Symbol&&Symbol.iterator,D="@@iterator",L=R||D;function U(e){this.next=e}function q(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function F(){return{value:void 0,done:!0}}function z(e){return!!H(e)}function B(e){return e&&"function"==typeof e.next}function V(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(R&&e[R]||e[D]);if("function"==typeof t)return t}function W(e){return e&&"number"==typeof e.length}function J(e){return null===e||void 0===e?ie():a(e)?e.toSeq():function(e){var t=se(e)||"object"==typeof e&&new te(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}(e)}function Y(e){return null===e||void 0===e?ie().toKeyedSeq():a(e)?u(e)?e.toSeq():e.fromEntrySeq():ae(e)}function K(e){return null===e||void 0===e?ie():a(e)?u(e)?e.entrySeq():e.toIndexedSeq():ue(e)}function G(e){return(null===e||void 0===e?ie():a(e)?u(e)?e.entrySeq():e:ue(e)).toSetSeq()}U.prototype.toString=function(){return"[Iterator]"},U.KEYS=I,U.VALUES=j,U.ENTRIES=N,U.prototype.inspect=U.prototype.toSource=function(){return this.toString()},U.prototype[L]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return le(this,e,t,!0)},J.prototype.__iterator=function(e,t){return ce(this,e,t,!0)},t(Y,J),Y.prototype.toKeyedSeq=function(){return this},t(K,J),K.of=function(){return K(arguments)},K.prototype.toIndexedSeq=function(){return this},K.prototype.toString=function(){return this.__toString("Seq [","]")},K.prototype.__iterate=function(e,t){return le(this,e,t,!1)},K.prototype.__iterator=function(e,t){return ce(this,e,t,!1)},t(G,J),G.of=function(){return G(arguments)},G.prototype.toSetSeq=function(){return this},J.isSeq=oe,J.Keyed=Y,J.Set=G,J.Indexed=K;var $,Z,X,Q="@@__IMMUTABLE_SEQ__@@";function ee(e){this._array=e,this.size=e.length}function te(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function ne(e){this._iterable=e,this.size=e.length||e.size}function re(e){this._iterator=e,this._iteratorCache=[]}function oe(e){return!(!e||!e[Q])}function ie(){return $||($=new ee([]))}function ae(e){var t=Array.isArray(e)?new ee(e).fromEntrySeq():B(e)?new re(e).fromEntrySeq():z(e)?new ne(e).fromEntrySeq():"object"==typeof e?new te(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function ue(e){var t=se(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function se(e){return W(e)?new ee(e):B(e)?new re(e):z(e)?new ne(e):void 0}function le(e,t,n,r){var o=e._cache;if(o){for(var i=o.length-1,a=0;a<=i;a++){var u=o[n?i-a:a];if(!1===t(u[1],r?u[0]:a,e))return a+1}return a}return e.__iterateUncached(t,n)}function ce(e,t,n,r){var o=e._cache;if(o){var i=o.length-1,a=0;return new U(function(){var e=o[n?i-a:a];return a++>i?{value:void 0,done:!0}:q(t,r?e[0]:a-1,e[1])})}return e.__iteratorUncached(t,n)}function fe(e,t){return t?function e(t,n,r,o){if(Array.isArray(n))return t.call(o,r,K(n).map(function(r,o){return e(t,r,o,n)}));if(de(n))return t.call(o,r,Y(n).map(function(r,o){return e(t,r,o,n)}));return n}(t,e,"",{"":e}):pe(e)}function pe(e){return Array.isArray(e)?K(e).map(pe).toList():de(e)?Y(e).map(pe).toMap():e}function de(e){return e&&(e.constructor===Object||void 0===e.constructor)}function he(e,t){if(e===t||e!=e&&t!=t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if((e=e.valueOf())===(t=t.valueOf())||e!=e&&t!=t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function ve(e,t){if(e===t)return!0;if(!a(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||u(e)!==u(t)||s(e)!==s(t)||c(e)!==c(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!l(e);if(c(e)){var r=e.entries();return t.every(function(e,t){var o=r.next().value;return o&&he(o[1],e)&&(n||he(o[0],t))})&&r.next().done}var o=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{o=!0;var i=e;e=t,t=i}var f=!0,p=t.__iterate(function(t,r){if(n?!e.has(t):o?!he(t,e.get(r,g)):!he(e.get(r,g),t))return f=!1,!1});return f&&e.size===p}function me(e,t){if(!(this instanceof me))return new me(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(Z)return Z;Z=this}}function ye(e,t){if(!e)throw new Error(t)}function ge(e,t,n){if(!(this instanceof ge))return new ge(e,t,n);if(ye(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),tr?{value:void 0,done:!0}:q(e,o,n[t?r-o++:o++])})},t(te,Y),te.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},te.prototype.has=function(e){return this._object.hasOwnProperty(e)},te.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,o=r.length-1,i=0;i<=o;i++){var a=r[t?o-i:i];if(!1===e(n[a],a,this))return i+1}return i},te.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,o=r.length-1,i=0;return new U(function(){var a=r[t?o-i:i];return i++>o?{value:void 0,done:!0}:q(e,a,n[a])})},te.prototype[h]=!0,t(ne,K),ne.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=V(this._iterable),r=0;if(B(n))for(var o;!(o=n.next()).done&&!1!==e(o.value,r++,this););return r},ne.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=V(this._iterable);if(!B(n))return new U(F);var r=0;return new U(function(){var t=n.next();return t.done?t:q(e,r++,t.value)})},t(re,K),re.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n,r=this._iterator,o=this._iteratorCache,i=0;i=r.length){var t=n.next();if(t.done)return t;r[o]=t.value}return q(e,o,r[o++])})},t(me,K),me.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},me.prototype.get=function(e,t){return this.has(e)?this._value:t},me.prototype.includes=function(e){return he(this._value,e)},me.prototype.slice=function(e,t){var n=this.size;return O(e,t,n)?this:new me(this._value,T(t,n)-P(e,n))},me.prototype.reverse=function(){return this},me.prototype.indexOf=function(e){return he(this._value,e)?0:-1},me.prototype.lastIndexOf=function(e){return he(this._value,e)?this.size:-1},me.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?{value:void 0,done:!0}:q(e,i++,a)})},ge.prototype.equals=function(e){return e instanceof ge?this._start===e._start&&this._end===e._end&&this._step===e._step:ve(this,e)},t(be,n),t(_e,be),t(we,be),t(Ee,be),be.Keyed=_e,be.Indexed=we,be.Set=Ee;var xe="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){var n=65535&(e|=0),r=65535&(t|=0);return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0};function Se(e){return e>>>1&1073741824|3221225471&e}function Ce(e){if(!1===e||null===e||void 0===e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null===e||void 0===e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!=e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)n^=e/=4294967295;return Se(n)}if("string"===t)return e.length>je?function(e){var t=De[e];void 0===t&&(t=ke(e),Re===Ne&&(Re=0,De={}),Re++,De[e]=t);return t}(e):ke(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return function(e){var t;if(Te&&void 0!==(t=Pe.get(e)))return t;if(void 0!==(t=e[Ie]))return t;if(!Oe){if(void 0!==(t=e.propertyIsEnumerable&&e.propertyIsEnumerable[Ie]))return t;if(void 0!==(t=function(e){if(e&&e.nodeType>0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}(e)))return t}t=++Me,1073741824&Me&&(Me=0);if(Te)Pe.set(e,t);else{if(void 0!==Ae&&!1===Ae(e))throw new Error("Non-extensible objects are not allowed as keys.");if(Oe)Object.defineProperty(e,Ie,{enumerable:!1,configurable:!1,writable:!1,value:t});else if(void 0!==e.propertyIsEnumerable&&e.propertyIsEnumerable===e.constructor.prototype.propertyIsEnumerable)e.propertyIsEnumerable=function(){return this.constructor.prototype.propertyIsEnumerable.apply(this,arguments)},e.propertyIsEnumerable[Ie]=t;else{if(void 0===e.nodeType)throw new Error("Unable to set a non-enumerable property on object.");e[Ie]=t}}return t}(e);if("function"==typeof e.toString)return ke(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function ke(e){for(var t=0,n=0;n=t.length)throw new Error("Missing value for key: "+t[n]);e.set(t[n],t[n+1])}})},Ue.prototype.toString=function(){return this.__toString("Map {","}")},Ue.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},Ue.prototype.set=function(e,t){return Qe(this,e,t)},Ue.prototype.setIn=function(e,t){return this.updateIn(e,g,function(){return t})},Ue.prototype.remove=function(e){return Qe(this,e,g)},Ue.prototype.deleteIn=function(e){return this.updateIn(e,function(){return g})},Ue.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},Ue.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=function e(t,n,r,o){var i=t===g;var a=n.next();if(a.done){var u=i?r:t,s=o(u);return s===u?t:s}ye(i||t&&t.set,"invalid keyPath");var l=a.value;var c=i?g:t.get(l,g);var f=e(c,n,r,o);return f===c?t:f===g?t.remove(l):(i?Xe():t).set(l,f)}(this,nn(e),t,n);return r===g?void 0:r},Ue.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):Xe()},Ue.prototype.merge=function(){return rt(this,void 0,arguments)},Ue.prototype.mergeWith=function(t){return rt(this,t,e.call(arguments,1))},Ue.prototype.mergeIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,Xe(),function(e){return"function"==typeof e.merge?e.merge.apply(e,n):n[n.length-1]})},Ue.prototype.mergeDeep=function(){return rt(this,ot,arguments)},Ue.prototype.mergeDeepWith=function(t){var n=e.call(arguments,1);return rt(this,it(t),n)},Ue.prototype.mergeDeepIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,Xe(),function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,n):n[n.length-1]})},Ue.prototype.sort=function(e){return Pt(Wt(this,e))},Ue.prototype.sortBy=function(e,t){return Pt(Wt(this,t,e))},Ue.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},Ue.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new x)},Ue.prototype.asImmutable=function(){return this.__ensureOwner()},Ue.prototype.wasAltered=function(){return this.__altered},Ue.prototype.__iterator=function(e,t){return new Ke(this,e,t)},Ue.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},Ue.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Ze(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Ue.isMap=qe;var Fe,ze="@@__IMMUTABLE_MAP__@@",Be=Ue.prototype;function Ve(e,t){this.ownerID=e,this.entries=t}function He(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function We(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function Je(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function Ye(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function Ke(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&$e(e._root)}function Ge(e,t){return q(e,t[0],t[1])}function $e(e,t){return{node:e,index:0,__prev:t}}function Ze(e,t,n,r){var o=Object.create(Be);return o.size=e,o._root=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Xe(){return Fe||(Fe=Ze(0))}function Qe(e,t,n){var r,o;if(e._root){var i=w(b),a=w(_);if(r=et(e._root,e.__ownerID,0,void 0,t,n,i,a),!a.value)return e;o=e.size+(i.value?n===g?-1:1:0)}else{if(n===g)return e;o=1,r=new Ve(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?Ze(o,r):Xe()}function et(e,t,n,r,o,i,a,u){return e?e.update(t,n,r,o,i,a,u):i===g?e:(E(u),E(a),new Ye(t,r,[o,i]))}function tt(e){return e.constructor===Ye||e.constructor===Je}function nt(e,t,n,r,o){if(e.keyHash===r)return new Je(t,r,[e.entry,o]);var i,a=(0===n?e.keyHash:e.keyHash>>>n)&y,u=(0===n?r:r>>>n)&y;return new He(t,1<>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function st(e,t,n,r){var o=r?e:S(e);return o[t]=n,o}Be[ze]=!0,Be.delete=Be.remove,Be.removeIn=Be.deleteIn,Ve.prototype.get=function(e,t,n,r){for(var o=this.entries,i=0,a=o.length;i=lt)return function(e,t,n,r){e||(e=new x);for(var o=new Ye(e,Ce(n),[n,r]),i=0;i>>e)&y),i=this.bitmap;return 0==(i&o)?r:this.nodes[ut(i&o-1)].get(e+v,t,n,r)},He.prototype.update=function(e,t,n,r,o,i,a){void 0===n&&(n=Ce(r));var u=(0===t?n:n>>>t)&y,s=1<=ct)return function(e,t,n,r,o){for(var i=0,a=new Array(m),u=0;0!==n;u++,n>>>=1)a[u]=1&n?t[i++]:void 0;return a[r]=o,new We(e,i+1,a)}(e,p,l,u,h);if(c&&!h&&2===p.length&&tt(p[1^f]))return p[1^f];if(c&&h&&1===p.length&&tt(h))return h;var b=e&&e===this.ownerID,_=c?h?l:l^s:l|s,w=c?h?st(p,f,h,b):function(e,t,n){var r=e.length-1;if(n&&t===r)return e.pop(),e;for(var o=new Array(r),i=0,a=0;a>>e)&y,i=this.nodes[o];return i?i.get(e+v,t,n,r):r},We.prototype.update=function(e,t,n,r,o,i,a){void 0===n&&(n=Ce(r));var u=(0===t?n:n>>>t)&y,s=o===g,l=this.nodes,c=l[u];if(s&&!c)return this;var f=et(c,e,t+v,n,r,o,i,a);if(f===c)return this;var p=this.count;if(c){if(!f&&--p0&&r=0&&e=e.size||t<0)return e.withMutations(function(e){t<0?kt(e,t).set(0,n):kt(e,0,t+1).set(t,n)});t+=e._origin;var r=e._tail,o=e._root,i=w(_);t>=Ot(e._capacity)?r=xt(r,e.__ownerID,0,t,n,i):o=xt(o,e.__ownerID,e._level,t,n,i);if(!i.value)return e;if(e.__ownerID)return e._root=o,e._tail=r,e.__hash=void 0,e.__altered=!0,e;return wt(e._origin,e._capacity,e._level,o,r)}(this,e,t)},pt.prototype.remove=function(e){return this.has(e)?0===e?this.shift():e===this.size-1?this.pop():this.splice(e,1):this},pt.prototype.insert=function(e,t){return this.splice(e,0,t)},pt.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=this._origin=this._capacity=0,this._level=v,this._root=this._tail=null,this.__hash=void 0,this.__altered=!0,this):Et()},pt.prototype.push=function(){var e=arguments,t=this.size;return this.withMutations(function(n){kt(n,0,t+e.length);for(var r=0;r>>t&y;if(r>=this.array.length)return new mt([],e);var o,i=0===r;if(t>0){var a=this.array[r];if((o=a&&a.removeBefore(e,t-v,n))===a&&i)return this}if(i&&!o)return this;var u=St(this,e);if(!i)for(var s=0;s>>t&y;if(o>=this.array.length)return this;if(t>0){var i=this.array[o];if((r=i&&i.removeAfter(e,t-v,n))===i&&o===this.array.length-1)return this}var a=St(this,e);return a.array.splice(o+1),r&&(a.array[o]=r),a};var yt,gt,bt={};function _t(e,t){var n=e._origin,r=e._capacity,o=Ot(r),i=e._tail;return a(e._root,e._level,0);function a(e,u,s){return 0===u?function(e,a){var u=a===o?i&&i.array:e&&e.array,s=a>n?0:n-a,l=r-a;l>m&&(l=m);return function(){if(s===l)return bt;var e=t?--l:s++;return u&&u[e]}}(e,s):function(e,o,i){var u,s=e&&e.array,l=i>n?0:n-i>>o,c=1+(r-i>>o);c>m&&(c=m);return function(){for(;;){if(u){var e=u();if(e!==bt)return e;u=null}if(l===c)return bt;var n=t?--c:l++;u=a(s&&s[n],o-v,i+(n<>>n&y,s=e&&u0){var l=e&&e.array[u],c=xt(l,t,n-v,r,o,i);return c===l?e:((a=St(e,t)).array[u]=c,a)}return s&&e.array[u]===o?e:(E(i),a=St(e,t),void 0===o&&u===a.array.length-1?a.array.pop():a.array[u]=o,a)}function St(e,t){return t&&e&&t===e.ownerID?e:new mt(e?e.array.slice():[],t)}function Ct(e,t){if(t>=Ot(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&y],r-=v;return n}}function kt(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new x,o=e._origin,i=e._capacity,a=o+t,u=void 0===n?i:n<0?i+n:o+n;if(a===o&&u===i)return e;if(a>=u)return e.clear();for(var s=e._level,l=e._root,c=0;a+c<0;)l=new mt(l&&l.array.length?[void 0,l]:[],r),c+=1<<(s+=v);c&&(a+=c,o+=c,u+=c,i+=c);for(var f=Ot(i),p=Ot(u);p>=1<f?new mt([],r):d;if(d&&p>f&&av;g-=v){var b=f>>>g&y;m=m.array[b]=St(m.array[b],r)}m.array[f>>>v&y]=d}if(u=p)a-=p,u-=p,s=v,l=null,h=h&&h.removeBefore(r,0,a);else if(a>o||p>>s&y;if(_!==p>>>s&y)break;_&&(c+=(1<o&&(l=l.removeBefore(r,s,a-c)),l&&pi&&(i=l.size),a(s)||(l=l.map(function(e){return fe(e)})),r.push(l)}return i>e.size&&(e=e.setSize(i)),at(e,t,r)}function Ot(e){return e>>v<=m&&a.size>=2*i.size?(r=(o=a.filter(function(e,t){return void 0!==e&&u!==t})).toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=o.__ownerID=e.__ownerID)):(r=i.remove(t),o=u===a.size-1?a.pop():a.set(u,void 0))}else if(s){if(n===a.get(u)[1])return e;r=i,o=a.set(u,[t,n])}else r=i.set(t,a.size),o=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=o,e.__hash=void 0,e):Mt(r,o)}function Nt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function Rt(e){this._iter=e,this.size=e.size}function Dt(e){this._iter=e,this.size=e.size}function Lt(e){this._iter=e,this.size=e.size}function Ut(e){var t=Qt(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=en,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===N){var r=e.__iterator(t,n);return new U(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===j?I:j,n)},t}function qt(e,t,n){var r=Qt(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,o){var i=e.get(r,g);return i===g?o:t.call(n,i,r,e)},r.__iterateUncached=function(r,o){var i=this;return e.__iterate(function(e,o,a){return!1!==r(t.call(n,e,o,a),o,i)},o)},r.__iteratorUncached=function(r,o){var i=e.__iterator(N,o);return new U(function(){var o=i.next();if(o.done)return o;var a=o.value,u=a[0];return q(r,u,t.call(n,a[1],u,e),o)})},r}function Ft(e,t){var n=Qt(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=Ut(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=en,n.__iterate=function(t,n){var r=this;return e.__iterate(function(e,n){return t(e,n,r)},!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function zt(e,t,n,r){var o=Qt(e);return r&&(o.has=function(r){var o=e.get(r,g);return o!==g&&!!t.call(n,o,r,e)},o.get=function(r,o){var i=e.get(r,g);return i!==g&&t.call(n,i,r,e)?i:o}),o.__iterateUncached=function(o,i){var a=this,u=0;return e.__iterate(function(e,i,s){if(t.call(n,e,i,s))return u++,o(e,r?i:u-1,a)},i),u},o.__iteratorUncached=function(o,i){var a=e.__iterator(N,i),u=0;return new U(function(){for(;;){var i=a.next();if(i.done)return i;var s=i.value,l=s[0],c=s[1];if(t.call(n,c,l,e))return q(o,r?l:u++,c,i)}})},o}function Bt(e,t,n,r){var o=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=o:n|=0),O(t,n,o))return e;var i=P(t,o),a=T(n,o);if(i!=i||a!=a)return Bt(e.toSeq().cacheResult(),t,n,r);var u,s=a-i;s==s&&(u=s<0?0:s);var l=Qt(e);return l.size=0===u?u:e.size&&u||void 0,!r&&oe(e)&&u>=0&&(l.get=function(t,n){return(t=k(this,t))>=0&&tu)return{value:void 0,done:!0};var e=o.next();return r||t===j?e:q(t,s-1,t===I?void 0:e.value[1],e)})},l}function Vt(e,t,n,r){var o=Qt(e);return o.__iterateUncached=function(o,i){var a=this;if(i)return this.cacheResult().__iterate(o,i);var u=!0,s=0;return e.__iterate(function(e,i,l){if(!u||!(u=t.call(n,e,i,l)))return s++,o(e,r?i:s-1,a)}),s},o.__iteratorUncached=function(o,i){var a=this;if(i)return this.cacheResult().__iterator(o,i);var u=e.__iterator(N,i),s=!0,l=0;return new U(function(){var e,i,c;do{if((e=u.next()).done)return r||o===j?e:q(o,l++,o===I?void 0:e.value[1],e);var f=e.value;i=f[0],c=f[1],s&&(s=t.call(n,c,i,a))}while(s);return o===N?e:q(o,i,c,e)})},o}function Ht(e,t,n){var r=Qt(e);return r.__iterateUncached=function(r,o){var i=0,u=!1;return function e(s,l){var c=this;s.__iterate(function(o,s){return(!t||l0}function Kt(e,t,r){var o=Qt(e);return o.size=new ee(r).map(function(e){return e.size}).min(),o.__iterate=function(e,t){for(var n,r=this.__iterator(j,t),o=0;!(n=r.next()).done&&!1!==e(n.value,o++,this););return o},o.__iteratorUncached=function(e,o){var i=r.map(function(e){return e=n(e),V(o?e.reverse():e)}),a=0,u=!1;return new U(function(){var n;return u||(n=i.map(function(e){return e.next()}),u=n.some(function(e){return e.done})),u?{value:void 0,done:!0}:q(e,a++,t.apply(null,n.map(function(e){return e.value})))})},o}function Gt(e,t){return oe(e)?t:e.constructor(t)}function $t(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function Zt(e){return Le(e.size),C(e)}function Xt(e){return u(e)?r:s(e)?o:i}function Qt(e){return Object.create((u(e)?Y:s(e)?K:G).prototype)}function en(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):J.prototype.cacheResult.call(this)}function tn(e,t){return e>t?1:e=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):An(e,t)},En.prototype.pushAll=function(e){if(0===(e=o(e)).size)return this;Le(e.size);var t=this.size,n=this._head;return e.reverse().forEach(function(e){t++,n={value:e,next:n}}),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):An(t,n)},En.prototype.pop=function(){return this.slice(1)},En.prototype.unshift=function(){return this.push.apply(this,arguments)},En.prototype.unshiftAll=function(e){return this.pushAll(e)},En.prototype.shift=function(){return this.pop.apply(this,arguments)},En.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):On()},En.prototype.slice=function(e,t){if(O(e,t,this.size))return this;var n=P(e,this.size);if(T(t,this.size)!==this.size)return we.prototype.slice.call(this,e,t);for(var r=this.size-n,o=this._head;n--;)o=o.next;return this.__ownerID?(this.size=r,this._head=o,this.__hash=void 0,this.__altered=!0,this):An(r,o)},En.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?An(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},En.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},En.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new U(function(){if(r){var t=r.value;return r=r.next,q(e,n++,t)}return{value:void 0,done:!0}})},En.isStack=xn;var Sn,Cn="@@__IMMUTABLE_STACK__@@",kn=En.prototype;function An(e,t,n,r){var o=Object.create(kn);return o.size=e,o._head=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function On(){return Sn||(Sn=An(0))}function Pn(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}kn[Cn]=!0,kn.withMutations=Be.withMutations,kn.asMutable=Be.asMutable,kn.asImmutable=Be.asImmutable,kn.wasAltered=Be.wasAltered,n.Iterator=U,Pn(n,{toArray:function(){Le(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate(function(t,n){e[n]=t}),e},toIndexedSeq:function(){return new Rt(this)},toJS:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJS?e.toJS():e}).__toJS()},toJSON:function(){return this.toSeq().map(function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e}).__toJS()},toKeyedSeq:function(){return new Nt(this,!0)},toMap:function(){return Ue(this.toKeyedSeq())},toObject:function(){Le(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e},toOrderedMap:function(){return Pt(this.toKeyedSeq())},toOrderedSet:function(){return mn(u(this)?this.valueSeq():this)},toSet:function(){return sn(u(this)?this.valueSeq():this)},toSetSeq:function(){return new Dt(this)},toSeq:function(){return s(this)?this.toIndexedSeq():u(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return En(u(this)?this.valueSeq():this)},toList:function(){return pt(u(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){return Gt(this,function(e,t){var n=u(e),o=[e].concat(t).map(function(e){return a(e)?n&&(e=r(e)):e=n?ae(e):ue(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===o.length)return e;if(1===o.length){var i=o[0];if(i===e||n&&u(i)||s(e)&&s(i))return i}var l=new ee(o);return n?l=l.toKeyedSeq():s(e)||(l=l.toSetSeq()),(l=l.flatten(!0)).size=o.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),l}(this,e.call(arguments,0)))},includes:function(e){return this.some(function(t){return he(t,e)})},entries:function(){return this.__iterator(N)},every:function(e,t){Le(this.size);var n=!0;return this.__iterate(function(r,o,i){if(!e.call(t,r,o,i))return n=!1,!1}),n},filter:function(e,t){return Gt(this,zt(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return Le(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){Le(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate(function(r){n?n=!1:t+=e,t+=null!==r&&void 0!==r?r.toString():""}),t},keys:function(){return this.__iterator(I)},map:function(e,t){return Gt(this,qt(this,e,t))},reduce:function(e,t,n){var r,o;return Le(this.size),arguments.length<2?o=!0:r=t,this.__iterate(function(t,i,a){o?(o=!1,r=t):r=e.call(n,r,t,i,a)}),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return Gt(this,Ft(this,!0))},slice:function(e,t){return Gt(this,Bt(this,e,t,!0))},some:function(e,t){return!this.every(Nn(e),t)},sort:function(e){return Gt(this,Wt(this,e))},values:function(){return this.__iterator(j)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some(function(){return!0})},count:function(e,t){return C(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return function(e,t,n){var r=Ue().asMutable();return e.__iterate(function(o,i){r.update(t.call(n,o,i,e),0,function(e){return e+1})}),r.asImmutable()}(this,e,t)},equals:function(e){return ve(this,e)},entrySeq:function(){var e=this;if(e._cache)return new ee(e._cache);var t=e.toSeq().map(jn).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(Nn(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate(function(n,o,i){if(e.call(t,n,o,i))return r=[o,n],!1}),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(A)},flatMap:function(e,t){return Gt(this,function(e,t,n){var r=Xt(e);return e.toSeq().map(function(o,i){return r(t.call(n,o,i,e))}).flatten(!0)}(this,e,t))},flatten:function(e){return Gt(this,Ht(this,e,!0))},fromEntrySeq:function(){return new Lt(this)},get:function(e,t){return this.find(function(t,n){return he(n,e)},void 0,t)},getIn:function(e,t){for(var n,r=this,o=nn(e);!(n=o.next()).done;){var i=n.value;if((r=r&&r.get?r.get(i,g):g)===g)return t}return r},groupBy:function(e,t){return function(e,t,n){var r=u(e),o=(c(e)?Pt():Ue()).asMutable();e.__iterate(function(i,a){o.update(t.call(n,i,a,e),function(e){return(e=e||[]).push(r?[a,i]:i),e})});var i=Xt(e);return o.map(function(t){return Gt(e,i(t))})}(this,e,t)},has:function(e){return this.get(e,g)!==g},hasIn:function(e){return this.getIn(e,g)!==g},isSubset:function(e){return e="function"==typeof e.includes?e:n(e),this.every(function(t){return e.includes(t)})},isSuperset:function(e){return(e="function"==typeof e.isSubset?e:n(e)).isSubset(this)},keyOf:function(e){return this.findKey(function(t){return he(t,e)})},keySeq:function(){return this.toSeq().map(In).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return Jt(this,e)},maxBy:function(e,t){return Jt(this,t,e)},min:function(e){return Jt(this,e?Rn(e):Un)},minBy:function(e,t){return Jt(this,t?Rn(t):Un,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return Gt(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return Gt(this,Vt(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(Nn(e),t)},sortBy:function(e,t){return Gt(this,Wt(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return Gt(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return Gt(this,function(e,t,n){var r=Qt(e);return r.__iterateUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterate(r,o);var a=0;return e.__iterate(function(e,o,u){return t.call(n,e,o,u)&&++a&&r(e,o,i)}),a},r.__iteratorUncached=function(r,o){var i=this;if(o)return this.cacheResult().__iterator(r,o);var a=e.__iterator(N,o),u=!0;return new U(function(){if(!u)return{value:void 0,done:!0};var e=a.next();if(e.done)return e;var o=e.value,s=o[0],l=o[1];return t.call(n,l,s,i)?r===N?e:q(r,s,l,e):(u=!1,{value:void 0,done:!0})})},r}(this,e,t))},takeUntil:function(e,t){return this.takeWhile(Nn(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=function(e){if(e.size===1/0)return 0;var t=c(e),n=u(e),r=t?1:0;return function(e,t){return t=xe(t,3432918353),t=xe(t<<15|t>>>-15,461845907),t=xe(t<<13|t>>>-13,5),t=xe((t=(t+3864292196|0)^e)^t>>>16,2246822507),t=Se((t=xe(t^t>>>13,3266489909))^t>>>16)}(e.__iterate(n?t?function(e,t){r=31*r+qn(Ce(e),Ce(t))|0}:function(e,t){r=r+qn(Ce(e),Ce(t))|0}:t?function(e){r=31*r+Ce(e)|0}:function(e){r=r+Ce(e)|0}),r)}(this))}});var Tn=n.prototype;Tn[f]=!0,Tn[L]=Tn.values,Tn.__toJS=Tn.toArray,Tn.__toStringMapper=Dn,Tn.inspect=Tn.toSource=function(){return this.toString()},Tn.chain=Tn.flatMap,Tn.contains=Tn.includes,Pn(r,{flip:function(){return Gt(this,Ut(this))},mapEntries:function(e,t){var n=this,r=0;return Gt(this,this.toSeq().map(function(o,i){return e.call(t,[i,o],r++,n)}).fromEntrySeq())},mapKeys:function(e,t){var n=this;return Gt(this,this.toSeq().flip().map(function(r,o){return e.call(t,r,o,n)}).flip())}});var Mn=r.prototype;function In(e,t){return t}function jn(e,t){return[t,e]}function Nn(e){return function(){return!e.apply(this,arguments)}}function Rn(e){return function(){return-e.apply(this,arguments)}}function Dn(e){return"string"==typeof e?JSON.stringify(e):String(e)}function Ln(){return S(arguments)}function Un(e,t){return et?-1:0}function qn(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}return Mn[p]=!0,Mn[L]=Tn.entries,Mn.__toJS=Tn.toObject,Mn.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+Dn(e)},Pn(o,{toKeyedSeq:function(){return new Nt(this,!1)},filter:function(e,t){return Gt(this,zt(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return Gt(this,Ft(this,!1))},slice:function(e,t){return Gt(this,Bt(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=P(e,e<0?this.count():this.size);var r=this.slice(0,e);return Gt(this,1===n?r:r.concat(S(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return Gt(this,Ht(this,e,!1))},get:function(e,t){return(e=k(this,e))<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=k(this,e))>=0&&(void 0!==this.size?this.size===1/0||e5e3)return e.textContent;return function(e){for(var n,r,o,i,a,u=e.textContent,s=0,l=u[0],c=1,f=e.innerHTML="",p=0;r=n,n=p<7&&"\\"==n?1:c;){if(c=l,l=u[++s],i=f.length>1,!c||p>8&&"\n"==c||[/\S/.test(c),1,1,!/[$\w]/.test(c),("/"==n||"\n"==n)&&i,'"'==n&&i,"'"==n&&i,u[s-4]+r+n=="--\x3e",r+n=="*/"][p])for(f&&(e.appendChild(a=t.createElement("span")).setAttribute("style",["color: #555; font-weight: bold;","","","color: #555;",""][p?p<3?2:p>6?4:p>3?3:+/^(a(bstract|lias|nd|rguments|rray|s(m|sert)?|uto)|b(ase|egin|ool(ean)?|reak|yte)|c(ase|atch|har|hecked|lass|lone|ompl|onst|ontinue)|de(bugger|cimal|clare|f(ault|er)?|init|l(egate|ete)?)|do|double|e(cho|ls?if|lse(if)?|nd|nsure|num|vent|x(cept|ec|p(licit|ort)|te(nds|nsion|rn)))|f(allthrough|alse|inal(ly)?|ixed|loat|or(each)?|riend|rom|unc(tion)?)|global|goto|guard|i(f|mp(lements|licit|ort)|n(it|clude(_once)?|line|out|stanceof|t(erface|ernal)?)?|s)|l(ambda|et|ock|ong)|m(icrolight|odule|utable)|NaN|n(amespace|ative|ext|ew|il|ot|ull)|o(bject|perator|r|ut|verride)|p(ackage|arams|rivate|rotected|rotocol|ublic)|r(aise|e(adonly|do|f|gister|peat|quire(_once)?|scue|strict|try|turn))|s(byte|ealed|elf|hort|igned|izeof|tatic|tring|truct|ubscript|uper|ynchronized|witch)|t(emplate|hen|his|hrows?|ransient|rue|ry|ype(alias|def|id|name|of))|u(n(checked|def(ined)?|ion|less|signed|til)|se|sing)|v(ar|irtual|oid|olatile)|w(char_t|hen|here|hile|ith)|xor|yield)$/.test(f):0]),a.appendChild(t.createTextNode(f))),o=p&&p<7?p:o,f="",p=11;![1,/[\/{}[(\-+*=<>:;|\\.,?!&@~]/.test(c),/[\])]/.test(c),/[$\w]/.test(c),"/"==c&&o<2&&"<"!=n,'"'==c,"'"==c,c+l+u[s+1]+u[s+2]=="\x3c!--",c+l=="/*",c+l=="//","#"==c][--p];);f+=c}}(e)},t.mapToList=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"key";var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:l.default.Map();if(!l.default.Map.isMap(t)||!t.size)return l.default.List();Array.isArray(n)||(n=[n]);if(n.length<1)return t.merge(r);var a=l.default.List();var u=n[0];var s=!0;var c=!1;var f=void 0;try{for(var p,d=(0,i.default)(t.entries());!(s=(p=d.next()).done);s=!0){var h=p.value,v=(0,o.default)(h,2),m=v[0],y=v[1],g=e(y,n.slice(1),r.set(u,m));a=l.default.List.isList(g)?a.concat(g):a.push(g)}}catch(e){c=!0,f=e}finally{try{!s&&d.return&&d.return()}finally{if(c)throw f}}return a},t.extractFileNameFromContentDispositionHeader=function(e){var t=/filename="([^;]*);?"/i.exec(e);null===t&&(t=/filename=([^;]*);?/i.exec(e));if(null!==t&&t.length>1)return t[1];return null},t.pascalCase=C,t.pascalCaseFilename=function(e){return C(e.replace(/\.[^./]*$/,""))},t.sanitizeUrl=function(e){if("string"!=typeof e||""===e)return"";return(0,c.sanitizeUrl)(e)},t.getAcceptControllingResponse=function(e){if(!l.default.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=e.find(function(e,t){return t.startsWith("2")&&(0,u.default)(e.get("content")||{}).length>0}),n=e.get("default")||l.default.OrderedMap(),r=(n.get("content")||l.default.OrderedMap()).keySeq().toJS().length?n:null;return t||r},t.deeplyStripKey=function e(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){return!0};if("object"!==(void 0===t?"undefined":(0,s.default)(t))||Array.isArray(t)||null===t||!n)return t;var o=(0,a.default)({},t);(0,u.default)(o).forEach(function(t){t===n&&r(o[t],t)?delete o[t]:o[t]=e(o[t],n,r)});return o},t.stringify=function(e){if("string"==typeof e)return e;e.toJS&&(e=e.toJS());if("object"===(void 0===e?"undefined":(0,s.default)(e))&&null!==e)try{return(0,r.default)(e,null,2)}catch(t){return String(e)}return e.toString()},t.numberToString=function(e){if("number"==typeof e)return e.toString();return e};var l=_(n(7)),c=n(572),f=_(n(573)),p=_(n(281)),d=_(n(285)),h=_(n(288)),v=_(n(651)),m=_(n(105)),y=n(192),g=_(n(32)),b=_(n(724));function _(e){return e&&e.__esModule?e:{default:e}}var w="default",E=t.isImmutable=function(e){return l.default.Iterable.isIterable(e)};function x(e){return Array.isArray(e)?e:[e]}function S(e){return!!e&&"object"===(void 0===e?"undefined":(0,s.default)(e))}t.memoize=d.default;function C(e){return(0,p.default)((0,f.default)(e))}t.propChecker=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[];return(0,u.default)(e).length!==(0,u.default)(t).length||((0,v.default)(e,function(e,n){if(r.includes(n))return!1;var o=t[n];return l.default.Iterable.isIterable(e)?!l.default.is(e,o):("object"!==(void 0===e?"undefined":(0,s.default)(e))||"object"!==(void 0===o?"undefined":(0,s.default)(o)))&&e!==o})||n.some(function(n){return!(0,m.default)(e[n],t[n])}))};var k=t.validateMaximum=function(e,t){if(e>t)return"Value must be less than Maximum"},A=t.validateMinimum=function(e,t){if(et)return"Value must be less than MaxLength"},D=t.validateMinLength=function(e,t){if(e.length2&&void 0!==arguments[2]&&arguments[2],r=[],o=t&&"body"===e.get("in")?e.get("value_xml"):e.get("value"),i=e.get("required"),a=n?e.get("schema"):e;if(!a)return r;var u=a.get("maximum"),c=a.get("minimum"),f=a.get("type"),p=a.get("format"),d=a.get("maxLength"),h=a.get("minLength"),v=a.get("pattern");if(f&&(i||o)){var m="string"===f&&o,y="array"===f&&Array.isArray(o)&&o.length,b="array"===f&&l.default.List.isList(o)&&o.count(),_="file"===f&&o instanceof g.default.File,w="boolean"===f&&(o||!1===o),E="number"===f&&(o||0===o),x="integer"===f&&(o||0===o),S=!1;if(n&&"object"===f)if("object"===(void 0===o?"undefined":(0,s.default)(o)))S=!0;else if("string"==typeof o)try{JSON.parse(o),S=!0}catch(e){return r.push("Parameter string value must be valid JSON"),r}var C=[m,y,b,_,w,E,x,S].some(function(e){return!!e});if(i&&!C)return r.push("Required field is not provided"),r;if(v){var U=L(o,v);U&&r.push(U)}if(d||0===d){var q=R(o,d);q&&r.push(q)}if(h){var F=D(o,h);F&&r.push(F)}if(u||0===u){var z=k(o,u);z&&r.push(z)}if(c||0===c){var B=A(o,c);B&&r.push(B)}if("string"===f){var V=void 0;if(!(V="date-time"===p?j(o):"uuid"===p?N(o):I(o)))return r;r.push(V)}else if("boolean"===f){var H=M(o);if(!H)return r;r.push(H)}else if("number"===f){var W=O(o);if(!W)return r;r.push(W)}else if("integer"===f){var J=P(o);if(!J)return r;r.push(J)}else if("array"===f){var Y;if(!b||!o.count())return r;Y=a.getIn(["items","type"]),o.forEach(function(e,t){var n=void 0;"number"===Y?n=O(e):"integer"===Y?n=P(e):"string"===Y&&(n=I(e)),n&&r.push({index:t,error:n})})}else if("file"===f){var K=T(o);if(!K)return r;r.push(K)}}return r},t.getSampleSchema=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(/xml/.test(t)){if(!e.xml||!e.xml.name){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated --\x3e':null;var o=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=o[1]}return(0,y.memoizedCreateXMLExample)(e,n)}var i=(0,y.memoizedSampleFromSchema)(e,n);return"object"===(void 0===i?"undefined":(0,s.default)(i))?(0,r.default)(i,null,2):i},t.parseSearch=function(){var e={},t=g.default.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)n.hasOwnProperty(r)&&(r=n[r].split("="),e[decodeURIComponent(r[0])]=r[1]&&decodeURIComponent(r[1])||"")}return e},t.serializeSearch=function(e){return(0,u.default)(e).map(function(t){return encodeURIComponent(t)+"="+encodeURIComponent(e[t])}).join("&")},t.btoa=function(t){return(t instanceof e?t:new e(t.toString(),"utf-8")).toString("base64")},t.sorters={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},t.buildFormData=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},t.shallowEqualKeys=function(e,t,n){return!!(0,h.default)(n,function(n){return(0,m.default)(e[n],t[n])})};var U=t.createDeepLinkPath=function(e){return"string"==typeof e||e instanceof String?e.trim().replace(/\s/g,"_"):""};t.escapeDeepLinkPath=function(e){return(0,b.default)(U(e))},t.getExtensions=function(e){return e.filter(function(e,t){return/^x-/.test(t)})},t.getCommonExtensions=function(e){return e.filter(function(e,t){return/^pattern|maxLength|minLength|maximum|minimum/.test(t)})}}).call(t,n(54).Buffer)},function(e,t,n){"use strict";var r=n(34);e.exports=r},function(e,t,n){"use strict";e.exports=function(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r>",i={listOf:function(e){return l(e,"List",r.List.isList)},mapOf:function(e,t){return c(e,t,"Map",r.Map.isMap)},orderedMapOf:function(e,t){return c(e,t,"OrderedMap",r.OrderedMap.isOrderedMap)},setOf:function(e){return l(e,"Set",r.Set.isSet)},orderedSetOf:function(e){return l(e,"OrderedSet",r.OrderedSet.isOrderedSet)},stackOf:function(e){return l(e,"Stack",r.Stack.isStack)},iterableOf:function(e){return l(e,"Iterable",r.Iterable.isIterable)},recordOf:function(e){return u(function(t,n,o,i,u){for(var s=arguments.length,l=Array(s>5?s-5:0),c=5;c6?s-6:0),c=6;c5?l-5:0),f=5;f5?i-5:0),u=5;u key("+c[f]+")"].concat(a));if(d instanceof Error)return d}})).apply(void 0,i);var s})}function f(e){var t=void 0===arguments[1]?"Iterable":arguments[1],n=void 0===arguments[2]?r.Iterable.isIterable:arguments[2];return u(function(r,o,i,u,s){for(var l=arguments.length,c=Array(l>5?l-5:0),f=5;f?@[\]^_`{|}~-])/g;function a(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function u(e){if(e>65535){var t=55296+((e-=65536)>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}var s=/&([a-z#][a-z0-9]{1,31});/gi,l=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,c=n(417);function f(e,t){var n=0;return o(c,t)?c[t]:35===t.charCodeAt(0)&&l.test(t)&&a(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?u(n):e}var p=/[&<>"]/,d=/[&<>"]/g,h={"&":"&","<":"<",">":">",'"':"""};function v(e){return h[e]}t.assign=function(e){return[].slice.call(arguments,1).forEach(function(t){if(t){if("object"!=typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e},t.isString=function(e){return"[object String]"===function(e){return Object.prototype.toString.call(e)}(e)},t.has=o,t.unescapeMd=function(e){return e.indexOf("\\")<0?e:e.replace(i,"$1")},t.isValidEntityCode=a,t.fromCodePoint=u,t.replaceEntities=function(e){return e.indexOf("&")<0?e:e.replace(s,f)},t.escapeHtml=function(e){return p.test(e)?e.replace(d,v):e}},function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},function(e,t,n){var r=n(33),o=n(60),i=n(58),a=n(73),u=n(120),s=function(e,t,n){var l,c,f,p,d=e&s.F,h=e&s.G,v=e&s.S,m=e&s.P,y=e&s.B,g=h?r:v?r[t]||(r[t]={}):(r[t]||{}).prototype,b=h?o:o[t]||(o[t]={}),_=b.prototype||(b.prototype={});for(l in h&&(n=t),n)f=((c=!d&&g&&void 0!==g[l])?g:n)[l],p=y&&c?u(f,r):m&&"function"==typeof f?u(Function.call,f):f,g&&a(g,l,f,e&s.U),b[l]!=f&&i(b,l,p),m&&_[l]!=f&&(_[l]=f)};r.core=o,s.F=1,s.G=2,s.S=4,s.P=8,s.B=16,s.W=32,s.U=64,s.R=128,e.exports=s},function(e,t,n){var r=n(29),o=n(101),i=n(53),a=/"/g,u=function(e,t,n,r){var o=String(i(e)),u="<"+t;return""!==n&&(u+=" "+n+'="'+String(r).replace(a,""")+'"'),u+">"+o+""};e.exports=function(e,t){var n={};n[e]=t(u),r(r.P+r.F*o(function(){var t=""[e]('"');return t!==t.toLowerCase()||t.split('"').length>3}),"String",n)}},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";var r,o=n(91),i=(r=o)&&r.__esModule?r:{default:r};e.exports=function(){var e={location:{},history:{},open:function(){},close:function(){},File:function(){}};if("undefined"==typeof window)return e;try{e=window;var t=!0,n=!1,r=void 0;try{for(var o,a=(0,i.default)(["File","Blob","FormData"]);!(t=(o=a.next()).done);t=!0){var u=o.value;u in window&&(e[u]=window[u])}}catch(e){n=!0,r=e}finally{try{!t&&a.return&&a.return()}finally{if(n)throw r}}}catch(e){console.error(e)}return e}()},function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},function(e,t,n){"use strict";function r(e){return function(){return e}}var o=function(){};o.thatReturns=r,o.thatReturnsFalse=r(!1),o.thatReturnsTrue=r(!0),o.thatReturnsNull=r(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(e){return e},e.exports=o},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=i(n(25));t.isOAS3=a,t.isSwagger2=function(e){var t=e.get("swagger");if("string"!=typeof t)return!1;return t.startsWith("2.0")},t.OAS3ComponentWrapFactory=function(e){return function(t,n){return function(i){if(n&&n.specSelectors&&n.specSelectors.specJson){var u=n.specSelectors.specJson();return a(u)?o.default.createElement(e,(0,r.default)({},i,n,{Ori:t})):o.default.createElement(t,i)}return console.warn("OAS3 wrapper: couldn't get spec"),null}}};var o=i(n(0));function i(e){return e&&e.__esModule?e:{default:e}}function a(e){var t=e.get("openapi");return"string"==typeof t&&(t.startsWith("3.0.")&&t.length>4)}},function(e,t,n){var r=n(28);e.exports=function(e){if(!r(e))throw TypeError(e+" is not an object!");return e}},function(e,t,n){var r=n(279),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();e.exports=i},function(e,t){e.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},function(e,t,n){"use strict";var r=null;e.exports={debugTool:r}},function(e,t,n){var r=n(36),o=n(238),i=n(157),a=Object.defineProperty;t.f=n(44)?Object.defineProperty:function(e,t,n){if(r(e),t=i(t,!0),r(n),o)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t,n){e.exports={default:n(517),__esModule:!0}},function(e,t,n){e.exports={default:n(518),__esModule:!0}},function(e,t,n){"use strict";var r=n(11),o=n(13),i=n(355),a=n(69),u=n(356),s=n(88),l=n(147),c=n(8),f=[],p=0,d=i.getPooled(),h=!1,v=null;function m(){E.ReactReconcileTransaction&&v||r("123")}var y=[{initialize:function(){this.dirtyComponentsLength=f.length},close:function(){this.dirtyComponentsLength!==f.length?(f.splice(0,this.dirtyComponentsLength),w()):f.length=0}},{initialize:function(){this.callbackQueue.reset()},close:function(){this.callbackQueue.notifyAll()}}];function g(){this.reinitializeTransaction(),this.dirtyComponentsLength=null,this.callbackQueue=i.getPooled(),this.reconcileTransaction=E.ReactReconcileTransaction.getPooled(!0)}function b(e,t){return e._mountOrder-t._mountOrder}function _(e){var t=e.dirtyComponentsLength;t!==f.length&&r("124",t,f.length),f.sort(b),p++;for(var n=0;n - * @license MIT - */ -var r=n(529),o=n(530),i=n(261);function a(){return s.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function u(e,t){if(a()=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|e}function h(e,t){if(s.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return F(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return z(e).length;default:if(r)return F(e).length;t=(""+t).toLowerCase(),r=!0}}function v(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function m(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=s.from(t,r)),s.isBuffer(t))return 0===t.length?-1:y(e,t,n,r,o);if("number"==typeof t)return t&=255,s.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):y(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function y(e,t,n,r,o){var i,a=1,u=e.length,s=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,u/=2,s/=2,n/=2}function l(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(o){var c=-1;for(i=n;iu&&(n=u-s),i=n;i>=0;i--){for(var f=!0,p=0;po&&(r=o):r=o;var i=t.length;if(i%2!=0)throw new TypeError("Invalid hex string");r>i/2&&(r=i/2);for(var a=0;a>8,o=n%256,i.push(o),i.push(r);return i}(t,e.length-n),e,n,r)}function S(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function C(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:l>223?3:l>191?2:1;if(o+f<=n)switch(f){case 1:l<128&&(c=l);break;case 2:128==(192&(i=e[o+1]))&&(s=(31&l)<<6|63&i)>127&&(c=s);break;case 3:i=e[o+1],a=e[o+2],128==(192&i)&&128==(192&a)&&(s=(15&l)<<12|(63&i)<<6|63&a)>2047&&(s<55296||s>57343)&&(c=s);break;case 4:i=e[o+1],a=e[o+2],u=e[o+3],128==(192&i)&&128==(192&a)&&128==(192&u)&&(s=(15&l)<<18|(63&i)<<12|(63&a)<<6|63&u)>65535&&s<1114112&&(c=s)}null===c?(c=65533,f=1):c>65535&&(c-=65536,r.push(c>>>10&1023|55296),c=56320|1023&c),r.push(c),o+=f}return function(e){var t=e.length;if(t<=k)return String.fromCharCode.apply(String,e);var n="",r=0;for(;rthis.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return P(this,t,n);case"utf8":case"utf-8":return C(this,t,n);case"ascii":return A(this,t,n);case"latin1":case"binary":return O(this,t,n);case"base64":return S(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return T(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}.apply(this,arguments)},s.prototype.equals=function(e){if(!s.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===s.compare(this,e)},s.prototype.inspect=function(){var e="",n=t.INSPECT_MAX_BYTES;return this.length>0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},s.prototype.compare=function(e,t,n,r,o){if(!s.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,o>>>=0,this===e)return 0;for(var i=o-r,a=n-t,u=Math.min(i,a),l=this.slice(r,o),c=e.slice(t,n),f=0;fo)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var i=!1;;)switch(r){case"hex":return g(this,e,t,n);case"utf8":case"utf-8":return b(this,e,t,n);case"ascii":return _(this,e,t,n);case"latin1":case"binary":return w(this,e,t,n);case"base64":return E(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return x(this,e,t,n);default:if(i)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),i=!0}},s.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var k=4096;function A(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",i=t;in)throw new RangeError("Trying to access beyond buffer length")}function I(e,t,n,r,o,i){if(!s.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function j(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,i=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function N(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,i=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function R(e,t,n,r,o,i){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function D(e,t,n,r,i){return i||R(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function L(e,t,n,r,i){return i||R(e,0,n,8),o.write(e,t,n,r,52,8),n+8}s.prototype.slice=function(e,t){var n,r=this.length;if(e=~~e,t=void 0===t?r:~~t,e<0?(e+=r)<0&&(e=0):e>r&&(e=r),t<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},s.prototype.readUInt8=function(e,t){return t||M(e,1,this.length),this[e]},s.prototype.readUInt16LE=function(e,t){return t||M(e,2,this.length),this[e]|this[e+1]<<8},s.prototype.readUInt16BE=function(e,t){return t||M(e,2,this.length),this[e]<<8|this[e+1]},s.prototype.readUInt32LE=function(e,t){return t||M(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},s.prototype.readUInt32BE=function(e,t){return t||M(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},s.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||M(e,t,this.length);for(var r=this[e],o=1,i=0;++i=(o*=128)&&(r-=Math.pow(2,8*t)),r},s.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||M(e,t,this.length);for(var r=t,o=1,i=this[e+--r];r>0&&(o*=256);)i+=this[e+--r]*o;return i>=(o*=128)&&(i-=Math.pow(2,8*t)),i},s.prototype.readInt8=function(e,t){return t||M(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},s.prototype.readInt16LE=function(e,t){t||M(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},s.prototype.readInt16BE=function(e,t){t||M(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},s.prototype.readInt32LE=function(e,t){return t||M(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},s.prototype.readInt32BE=function(e,t){return t||M(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},s.prototype.readFloatLE=function(e,t){return t||M(e,4,this.length),o.read(this,e,!0,23,4)},s.prototype.readFloatBE=function(e,t){return t||M(e,4,this.length),o.read(this,e,!1,23,4)},s.prototype.readDoubleLE=function(e,t){return t||M(e,8,this.length),o.read(this,e,!0,52,8)},s.prototype.readDoubleBE=function(e,t){return t||M(e,8,this.length),o.read(this,e,!1,52,8)},s.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||I(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,i=0;for(this[t]=255&e;++i=0&&(i*=256);)this[t+o]=e/i&255;return t+n},s.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,1,255,0),s.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},s.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,2,65535,0),s.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):j(this,e,t,!0),t+2},s.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,2,65535,0),s.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):j(this,e,t,!1),t+2},s.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,4,4294967295,0),s.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):N(this,e,t,!0),t+4},s.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,4,4294967295,0),s.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},s.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);I(this,e,t,n,o-1,-o)}var i=0,a=1,u=0;for(this[t]=255&e;++i>0)-u&255;return t+n},s.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);I(this,e,t,n,o-1,-o)}var i=n-1,a=1,u=0;for(this[t+i]=255&e;--i>=0&&(a*=256);)e<0&&0===u&&0!==this[t+i+1]&&(u=1),this[t+i]=(e/a>>0)-u&255;return t+n},s.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,1,127,-128),s.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},s.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,2,32767,-32768),s.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):j(this,e,t,!0),t+2},s.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,2,32767,-32768),s.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):j(this,e,t,!1),t+2},s.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,4,2147483647,-2147483648),s.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):N(this,e,t,!0),t+4},s.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||I(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),s.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):N(this,e,t,!1),t+4},s.prototype.writeFloatLE=function(e,t,n){return D(this,e,t,!0,n)},s.prototype.writeFloatBE=function(e,t,n){return D(this,e,t,!1,n)},s.prototype.writeDoubleLE=function(e,t,n){return L(this,e,t,!0,n)},s.prototype.writeDoubleBE=function(e,t,n){return L(this,e,t,!1,n)},s.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(i<1e3||!s.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(i=t;i55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&i.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&i.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&i.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&i.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;i.push(n)}else if(n<2048){if((t-=2)<0)break;i.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;i.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return i}function z(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(U,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function B(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(t,n(31))},function(e,t){var n,r,o=e.exports={};function i(){throw new Error("setTimeout has not been defined")}function a(){throw new Error("clearTimeout has not been defined")}function u(e){if(n===setTimeout)return setTimeout(e,0);if((n===i||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:i}catch(e){n=i}try{r="function"==typeof clearTimeout?clearTimeout:a}catch(e){r=a}}();var s,l=[],c=!1,f=-1;function p(){c&&s&&(c=!1,s.length?l=s.concat(l):f=-1,l.length&&d())}function d(){if(!c){var e=u(p);c=!0;for(var t=l.length;t;){for(s=l,l=[];++f1)for(var n=1;n1?t-1:0),r=1;r2?n-2:0),o=2;o1){for(var h=Array(d),v=0;v1){for(var y=Array(m),g=0;g=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}},function(e,t,n){"use strict";function r(e){return void 0===e||null===e}e.exports.isNothing=r,e.exports.isObject=function(e){return"object"==typeof e&&null!==e},e.exports.toArray=function(e){return Array.isArray(e)?e:r(e)?[]:[e]},e.exports.repeat=function(e,t){var n,r="";for(n=0;n=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},function(e,t,n){e.exports=!n(101)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t){e.exports={}},function(e,t,n){var r=n(119),o=Math.min;e.exports=function(e){return e>0?o(r(e),9007199254740991):0}},function(e,t,n){"use strict";e.exports=function(e){for(var t=arguments.length-1,n="Minified React error #"+e+"; visit http://facebook.github.io/react/docs/error-decoder.html?invariant="+e,r=0;r0?o(r(e),9007199254740991):0}},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t,n){var r=n(59),o=n(460),i=n(461),a=Object.defineProperty;t.f=n(100)?Object.defineProperty:function(e,t,n){if(r(e),t=i(t,!0),r(n),o)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(121);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,o){return e.call(t,n,r,o)}}return function(){return e.apply(t,arguments)}}},function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},function(e,t,n){var r=n(466),o=n(53);e.exports=function(e){return r(o(e))}},function(e,t,n){"use strict";var r=n(58),o=n(73),i=n(101),a=n(53),u=n(17);e.exports=function(e,t,n){var s=u(e),l=n(a,s,""[e]),c=l[0],f=l[1];i(function(){var t={};return t[s]=function(){return 7},7!=""[e](t)})&&(o(String.prototype,e,c),r(RegExp.prototype,s,2==t?function(e,t){return f.call(e,this,t)}:function(e){return f.call(e,this)}))}},function(e,t,n){var r=n(116)("meta"),o=n(28),i=n(52),a=n(40).f,u=0,s=Object.isExtensible||function(){return!0},l=!n(51)(function(){return s(Object.preventExtensions({}))}),c=function(e){a(e,r,{value:{i:"O"+ ++u,w:{}}})},f=e.exports={KEY:r,NEED:!1,fastKey:function(e,t){if(!o(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!i(e,r)){if(!s(e))return"F";if(!t)return"E";c(e)}return e[r].i},getWeak:function(e,t){if(!i(e,r)){if(!s(e))return!0;if(!t)return!1;c(e)}return e[r].w},onFreeze:function(e){return l&&f.NEED&&s(e)&&!i(e,r)&&c(e),e}}},function(e,t){t.f={}.propertyIsEnumerable},function(e,t,n){"use strict";var r={};e.exports=r},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.CLEAR_BY=t.CLEAR=t.NEW_AUTH_ERR=t.NEW_SPEC_ERR_BATCH=t.NEW_SPEC_ERR=t.NEW_THROWN_ERR_BATCH=t.NEW_THROWN_ERR=void 0,t.newThrownErr=function(e){return{type:a,payload:(0,i.default)(e)}},t.newThrownErrBatch=function(e){return{type:u,payload:e}},t.newSpecErr=function(e){return{type:s,payload:e}},t.newSpecErrBatch=function(e){return{type:l,payload:e}},t.newAuthErr=function(e){return{type:c,payload:e}},t.clear=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:f,payload:e}},t.clearBy=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!0};return{type:p,payload:e}};var r,o=n(179),i=(r=o)&&r.__esModule?r:{default:r};var a=t.NEW_THROWN_ERR="err_new_thrown_err",u=t.NEW_THROWN_ERR_BATCH="err_new_thrown_err_batch",s=t.NEW_SPEC_ERR="err_new_spec_err",l=t.NEW_SPEC_ERR_BATCH="err_new_spec_err_batch",c=t.NEW_AUTH_ERR="err_new_auth_err",f=t.CLEAR="err_clear",p=t.CLEAR_BY="err_clear_by"},function(e,t,n){var r=n(62),o=n(47),i="[object Symbol]";e.exports=function(e){return"symbol"==typeof e||o(e)&&r(e)==i}},function(e,t,n){var r=n(63)(Object,"create");e.exports=r},function(e,t,n){var r=n(601),o=n(602),i=n(603),a=n(604),u=n(605);function s(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&eb;b++)if((m=t?g(a(h=e[b])[0],h[1]):g(e[b]))===l||m===c)return m}else for(v=y.call(e);!(h=v.next()).done;)if((m=o(v,g,h.value,t))===l||m===c)return m}).BREAK=l,t.RETURN=c},function(e,t,n){"use strict";var r=n(86);e.exports=r.DEFAULT=new r({include:[n(108)],explicit:[n(758),n(759),n(760)]})},function(e,t,n){var r=n(345),o=n(105),i=Object.prototype.hasOwnProperty;e.exports=function(e,t,n){var a=e[t];i.call(e,t)&&o(a,n)&&(void 0!==n||t in e)||r(e,t,n)}},function(e,t,n){"use strict";var r=n(11),o=(n(8),{}),i={reinitializeTransaction:function(){this.transactionWrappers=this.getTransactionWrappers(),this.wrapperInitData?this.wrapperInitData.length=0:this.wrapperInitData=[],this._isInTransaction=!1},_isInTransaction:!1,getTransactionWrappers:null,isInTransaction:function(){return!!this._isInTransaction},perform:function(e,t,n,o,i,a,u,s){var l,c;this.isInTransaction()&&r("27");try{this._isInTransaction=!0,l=!0,this.initializeAll(0),c=e.call(t,n,o,i,a,u,s),l=!1}finally{try{if(l)try{this.closeAll(0)}catch(e){}else this.closeAll(0)}finally{this._isInTransaction=!1}}return c},initializeAll:function(e){for(var t=this.transactionWrappers,n=e;n]/,s=n(218)(function(e,t){if(e.namespaceURI!==i.svg||"innerHTML"in e)e.innerHTML=t;else{(r=r||document.createElement("div")).innerHTML=""+t+"";for(var n=r.firstChild;n.firstChild;)e.appendChild(n.firstChild)}});if(o.canUseDOM){var l=document.createElement("div");l.innerHTML=" ",""===l.innerHTML&&(s=function(e,t){if(e.parentNode&&e.parentNode.replaceChild(e,e),a.test(t)||"<"===t[0]&&u.test(t)){e.innerHTML=String.fromCharCode(65279)+t;var n=e.firstChild;1===n.data.length?e.removeChild(n):n.deleteData(0,1)}else e.innerHTML=t}),l=null}e.exports=s},function(e,t,n){"use strict";var r=/["'&<>]/;e.exports=function(e){return"boolean"==typeof e||"number"==typeof e?""+e:function(e){var t,n=""+e,o=r.exec(n);if(!o)return n;var i="",a=0,u=0;for(a=o.index;adocument.F=Object<\/script>"),e.close(),s=e.F;r--;)delete s.prototype[i[r]];return s()};e.exports=Object.create||function(e,t){var n;return null!==e?(u.prototype=r(e),n=new u,u.prototype=null,n[a]=e):n=s(),void 0===t?n:o(n,t)}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(162)("keys"),o=n(116);e.exports=function(e){return r[e]||(r[e]=o(e))}},function(e,t,n){var r=n(21),o=r["__core-js_shared__"]||(r["__core-js_shared__"]={});e.exports=function(e){return o[e]||(o[e]={})}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var r=n(165),o=n(19)("iterator"),i=n(70);e.exports=n(15).getIteratorMethod=function(e){if(void 0!=e)return e[o]||e["@@iterator"]||i[r(e)]}},function(e,t,n){var r=n(93),o=n(19)("toStringTag"),i="Arguments"==r(function(){return arguments}());e.exports=function(e){var t,n,a;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),o))?n:i?r(t):"Object"==(a=r(t))&&"function"==typeof t.callee?"Arguments":a}},function(e,t,n){var r=n(99),o=n(17)("toStringTag"),i="Arguments"==r(function(){return arguments}());e.exports=function(e){var t,n,a;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),o))?n:i?r(t):"Object"==(a=r(t))&&"function"==typeof t.callee?"Arguments":a}},function(e,t){var n=0,r=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+r).toString(36))}},function(e,t,n){var r=n(74),o=n(33).document,i=r(o)&&r(o.createElement);e.exports=function(e){return i?o.createElement(e):{}}},function(e,t,n){var r=n(242)("keys"),o=n(167);e.exports=function(e){return r[e]||(r[e]=o(e))}},function(e,t,n){var r=n(117).f,o=n(118),i=n(17)("toStringTag");e.exports=function(e,t,n){e&&!o(e=n?e:e.prototype,i)&&r(e,i,{configurable:!0,value:t})}},function(e,t,n){"use strict";var r=n(121);e.exports.f=function(e){return new function(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=r(t),this.reject=r(n)}(e)}},function(e,t,n){var r=n(256),o=n(53);e.exports=function(e,t,n){if(r(t))throw TypeError("String#"+n+" doesn't accept regex!");return String(o(e))}},function(e,t,n){var r=n(17)("match");e.exports=function(e){var t=/./;try{"/./"[e](t)}catch(n){try{return t[r]=!1,!"/./"[e](t)}catch(e){}}return!0}},function(e,t,n){t.f=n(19)},function(e,t,n){var r=n(21),o=n(15),i=n(114),a=n(174),u=n(40).f;e.exports=function(e){var t=o.Symbol||(o.Symbol=i?{}:r.Symbol||{});"_"==e.charAt(0)||e in t||u(t,e,{value:a.f(e)})}},function(e,t){t.f=Object.getOwnPropertySymbols},function(e,t){},function(e,t,n){"use strict";(function(t){ -/*! - * @description Recursive object extending - * @author Viacheslav Lotsmanov - * @license MIT - * - * The MIT License (MIT) - * - * Copyright (c) 2013-2018 Viacheslav Lotsmanov - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -function n(e){return e instanceof t||e instanceof Date||e instanceof RegExp}function r(e){if(e instanceof t){var n=t.alloc?t.alloc(e.length):new t(e.length);return e.copy(n),n}if(e instanceof Date)return new Date(e.getTime());if(e instanceof RegExp)return new RegExp(e);throw new Error("Unexpected situation")}function o(e,t){return"__proto__"===t?void 0:e[t]}var i=e.exports=function(){if(arguments.length<1||"object"!=typeof arguments[0])return!1;if(arguments.length<2)return arguments[0];var e,t,a=arguments[0];return Array.prototype.slice.call(arguments,1).forEach(function(u){"object"!=typeof u||null===u||Array.isArray(u)||Object.keys(u).forEach(function(s){return t=o(a,s),(e=o(u,s))===a?void 0:"object"!=typeof e||null===e?void(a[s]=e):Array.isArray(e)?void(a[s]=function e(t){var o=[];return t.forEach(function(t,a){"object"==typeof t&&null!==t?Array.isArray(t)?o[a]=e(t):n(t)?o[a]=r(t):o[a]=i({},t):o[a]=t}),o}(e)):n(e)?void(a[s]=r(e)):"object"!=typeof t||null===t||Array.isArray(t)?void(a[s]=i({},e)):void(a[s]=i(t,e))})}),a}}).call(t,n(54).Buffer)},function(e,t,n){"use strict";e.exports=function(e){return"object"==typeof e?function e(t,n){var r;r=Array.isArray(t)?[]:{};n.push(t);Object.keys(t).forEach(function(o){var i=t[o];"function"!=typeof i&&(i&&"object"==typeof i?-1!==n.indexOf(t[o])?r[o]="[Circular]":r[o]=e(t[o],n.slice(0)):r[o]=i)});"string"==typeof t.name&&(r.name=t.name);"string"==typeof t.message&&(r.message=t.message);"string"==typeof t.stack&&(r.stack=t.stack);return r}(e,[]):"function"==typeof e?"[Function: "+(e.name||"anonymous")+"]":e}},function(e,t,n){var r=n(590),o=n(606),i=n(608),a=n(609),u=n(610);function s(e){var t=-1,n=null==e?0:e.length;for(this.clear();++t-1&&e%1==0&&e<=n}},function(e,t){e.exports=function(e){return function(t){return e(t)}}},function(e,t,n){(function(e){var r=n(279),o="object"==typeof t&&t&&!t.nodeType&&t,i=o&&"object"==typeof e&&e&&!e.nodeType&&e,a=i&&i.exports===o&&r.process,u=function(){try{var e=i&&i.require&&i.require("util").types;return e||a&&a.binding&&a.binding("util")}catch(e){}}();e.exports=u}).call(t,n(134)(e))},function(e,t,n){var r=n(24),o=n(128),i=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,a=/^\w*$/;e.exports=function(e,t){if(r(e))return!1;var n=typeof e;return!("number"!=n&&"symbol"!=n&&"boolean"!=n&&null!=e&&!o(e))||a.test(e)||!i.test(e)||null!=t&&e in Object(t)}},function(e,t){e.exports=function(e){return e}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.memoizedSampleFromSchema=t.memoizedCreateXMLExample=t.sampleXmlFromSchema=t.inferSchema=t.sampleFromSchema=void 0,t.createXMLExample=f;var r=n(9),o=a(n(657)),i=a(n(670));function a(e){return e&&e.__esModule?e:{default:e}}var u={string:function(){return"string"},string_email:function(){return"user@example.com"},"string_date-time":function(){return(new Date).toISOString()},number:function(){return 0},number_float:function(){return 0},integer:function(){return 0},boolean:function(e){return"boolean"!=typeof e.default||e.default}},s=function(e){var t=e=(0,r.objectify)(e),n=t.type,o=t.format,i=u[n+"_"+o]||u[n];return(0,r.isFunc)(i)?i(e):"Unknown Type: "+e.type},l=t.sampleFromSchema=function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=(0,r.objectify)(t),i=o.type,a=o.example,u=o.properties,l=o.additionalProperties,c=o.items,f=n.includeReadOnly,p=n.includeWriteOnly;if(void 0!==a)return(0,r.deeplyStripKey)(a,"$$ref",function(e){return"string"==typeof e&&e.indexOf("#")>-1});if(!i)if(u)i="object";else{if(!c)return;i="array"}if("object"===i){var d=(0,r.objectify)(u),h={};for(var v in d)d[v]&&d[v].deprecated||d[v]&&d[v].readOnly&&!f||d[v]&&d[v].writeOnly&&!p||(h[v]=e(d[v],n));if(!0===l)h.additionalProp1={};else if(l)for(var m=(0,r.objectify)(l),y=e(m,n),g=1;g<4;g++)h["additionalProp"+g]=y;return h}return"array"===i?Array.isArray(c.anyOf)?c.anyOf.map(function(t){return e(t,n)}):Array.isArray(c.oneOf)?c.oneOf.map(function(t){return e(t,n)}):[e(c,n)]:t.enum?t.default?t.default:(0,r.normalizeArray)(t.enum)[0]:"file"!==i?s(t):void 0},c=(t.inferSchema=function(e){return e.schema&&(e=e.schema),e.properties&&(e.type="object"),e},t.sampleXmlFromSchema=function e(t){var n,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=(0,r.objectify)(t),a=i.type,u=i.properties,l=i.additionalProperties,c=i.items,f=i.example,p=o.includeReadOnly,d=o.includeWriteOnly,h=i.default,v={},m={},y=t.xml,g=y.name,b=y.prefix,_=y.namespace,w=i.enum,E=void 0;if(!a)if(u||l)a="object";else{if(!c)return;a="array"}(g=g||"notagname",n=(b?b+":":"")+g,_)&&(m[b?"xmlns:"+b:"xmlns"]=_);if("array"===a&&c){if(c.xml=c.xml||y||{},c.xml.name=c.xml.name||y.name,y.wrapped)return v[n]=[],Array.isArray(f)?f.forEach(function(t){c.example=t,v[n].push(e(c,o))}):Array.isArray(h)?h.forEach(function(t){c.default=t,v[n].push(e(c,o))}):v[n]=[e(c,o)],m&&v[n].push({_attr:m}),v;var x=[];return Array.isArray(f)?(f.forEach(function(t){c.example=t,x.push(e(c,o))}),x):Array.isArray(h)?(h.forEach(function(t){c.default=t,x.push(e(c,o))}),x):e(c,o)}if("object"===a){var S=(0,r.objectify)(u);for(var C in v[n]=[],f=f||{},S)if(S.hasOwnProperty(C)&&(!S[C].readOnly||p)&&(!S[C].writeOnly||d))if(S[C].xml=S[C].xml||{},S[C].xml.attribute){var k=Array.isArray(S[C].enum)&&S[C].enum[0],A=S[C].example,O=S[C].default;m[S[C].xml.name||C]=void 0!==A&&A||void 0!==f[C]&&f[C]||void 0!==O&&O||k||s(S[C])}else{S[C].xml.name=S[C].xml.name||C,void 0===S[C].example&&void 0!==f[C]&&(S[C].example=f[C]);var P=e(S[C]);Array.isArray(P)?v[n]=v[n].concat(P):v[n].push(P)}return!0===l?v[n].push({additionalProp:"Anything can be here"}):l&&v[n].push({additionalProp:s(l)}),m&&v[n].push({_attr:m}),v}return E=void 0!==f?f:void 0!==h?h:Array.isArray(w)?w[0]:s(t),v[n]=m?[{_attr:m},E]:E,v});function f(e,t){var n=c(e,t);if(n)return(0,o.default)(n,{declaration:!0,indent:"\t"})}t.memoizedCreateXMLExample=(0,i.default)(f),t.memoizedSampleFromSchema=(0,i.default)(l)},function(e,t){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function r(e){return"function"==typeof e}function o(e){return"object"==typeof e&&null!==e}function i(e){return void 0===e}e.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,n,a,u,s,l;if(this._events||(this._events={}),"error"===e&&(!this._events.error||o(this._events.error)&&!this._events.error.length)){if((t=arguments[1])instanceof Error)throw t;var c=new Error('Uncaught, unspecified "error" event. ('+t+")");throw c.context=t,c}if(i(n=this._events[e]))return!1;if(r(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:u=Array.prototype.slice.call(arguments,1),n.apply(this,u)}else if(o(n))for(u=Array.prototype.slice.call(arguments,1),a=(l=n.slice()).length,s=0;s0&&this._events[e].length>a&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace()),this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){if(!r(t))throw TypeError("listener must be a function");var n=!1;function o(){this.removeListener(e,o),n||(n=!0,t.apply(this,arguments))}return o.listener=t,this.on(e,o),this},n.prototype.removeListener=function(e,t){var n,i,a,u;if(!r(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(a=(n=this._events[e]).length,i=-1,n===t||r(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(u=a;u-- >0;)if(n[u]===t||n[u].listener&&n[u].listener===t){i=u;break}if(i<0)return this;1===n.length?(n.length=0,delete this._events[e]):n.splice(i,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r(n=this._events[e]))this.removeListener(e,n);else if(n)for(;n.length;)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){return this._events&&this._events[e]?r(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.prototype.listenerCount=function(e){if(this._events){var t=this._events[e];if(r(t))return 1;if(t)return t.length}return 0},n.listenerCount=function(e,t){return e.listenerCount(t)}},function(e,t,n){(t=e.exports=n(306)).Stream=t,t.Readable=t,t.Writable=n(195),t.Duplex=n(65),t.Transform=n(311),t.PassThrough=n(665)},function(e,t,n){"use strict";(function(t,r,o){var i=n(140);function a(e){var t=this;this.next=null,this.entry=null,this.finish=function(){!function(e,t,n){var r=e.entry;e.entry=null;for(;r;){var o=r.callback;t.pendingcb--,o(n),r=r.next}t.corkedRequestsFree?t.corkedRequestsFree.next=e:t.corkedRequestsFree=e}(t,e)}}e.exports=g;var u,s=!t.browser&&["v0.10","v0.9."].indexOf(t.version.slice(0,5))>-1?r:i.nextTick;g.WritableState=y;var l=n(106);l.inherits=n(81);var c={deprecate:n(664)},f=n(307),p=n(141).Buffer,d=o.Uint8Array||function(){};var h,v=n(308);function m(){}function y(e,t){u=u||n(65),e=e||{};var r=t instanceof u;this.objectMode=!!e.objectMode,r&&(this.objectMode=this.objectMode||!!e.writableObjectMode);var o=e.highWaterMark,l=e.writableHighWaterMark,c=this.objectMode?16:16384;this.highWaterMark=o||0===o?o:r&&(l||0===l)?l:c,this.highWaterMark=Math.floor(this.highWaterMark),this.finalCalled=!1,this.needDrain=!1,this.ending=!1,this.ended=!1,this.finished=!1,this.destroyed=!1;var f=!1===e.decodeStrings;this.decodeStrings=!f,this.defaultEncoding=e.defaultEncoding||"utf8",this.length=0,this.writing=!1,this.corked=0,this.sync=!0,this.bufferProcessing=!1,this.onwrite=function(e){!function(e,t){var n=e._writableState,r=n.sync,o=n.writecb;if(function(e){e.writing=!1,e.writecb=null,e.length-=e.writelen,e.writelen=0}(n),t)!function(e,t,n,r,o){--t.pendingcb,n?(i.nextTick(o,r),i.nextTick(S,e,t),e._writableState.errorEmitted=!0,e.emit("error",r)):(o(r),e._writableState.errorEmitted=!0,e.emit("error",r),S(e,t))}(e,n,r,t,o);else{var a=E(n);a||n.corked||n.bufferProcessing||!n.bufferedRequest||w(e,n),r?s(_,e,n,a,o):_(e,n,a,o)}}(t,e)},this.writecb=null,this.writelen=0,this.bufferedRequest=null,this.lastBufferedRequest=null,this.pendingcb=0,this.prefinished=!1,this.errorEmitted=!1,this.bufferedRequestCount=0,this.corkedRequestsFree=new a(this)}function g(e){if(u=u||n(65),!(h.call(g,this)||this instanceof u))return new g(e);this._writableState=new y(e,this),this.writable=!0,e&&("function"==typeof e.write&&(this._write=e.write),"function"==typeof e.writev&&(this._writev=e.writev),"function"==typeof e.destroy&&(this._destroy=e.destroy),"function"==typeof e.final&&(this._final=e.final)),f.call(this)}function b(e,t,n,r,o,i,a){t.writelen=r,t.writecb=a,t.writing=!0,t.sync=!0,n?e._writev(o,t.onwrite):e._write(o,i,t.onwrite),t.sync=!1}function _(e,t,n,r){n||function(e,t){0===t.length&&t.needDrain&&(t.needDrain=!1,e.emit("drain"))}(e,t),t.pendingcb--,r(),S(e,t)}function w(e,t){t.bufferProcessing=!0;var n=t.bufferedRequest;if(e._writev&&n&&n.next){var r=t.bufferedRequestCount,o=new Array(r),i=t.corkedRequestsFree;i.entry=n;for(var u=0,s=!0;n;)o[u]=n,n.isBuf||(s=!1),n=n.next,u+=1;o.allBuffers=s,b(e,t,!0,t.length,o,"",i.finish),t.pendingcb++,t.lastBufferedRequest=null,i.next?(t.corkedRequestsFree=i.next,i.next=null):t.corkedRequestsFree=new a(t),t.bufferedRequestCount=0}else{for(;n;){var l=n.chunk,c=n.encoding,f=n.callback;if(b(e,t,!1,t.objectMode?1:l.length,l,c,f),n=n.next,t.bufferedRequestCount--,t.writing)break}null===n&&(t.lastBufferedRequest=null)}t.bufferedRequest=n,t.bufferProcessing=!1}function E(e){return e.ending&&0===e.length&&null===e.bufferedRequest&&!e.finished&&!e.writing}function x(e,t){e._final(function(n){t.pendingcb--,n&&e.emit("error",n),t.prefinished=!0,e.emit("prefinish"),S(e,t)})}function S(e,t){var n=E(t);return n&&(!function(e,t){t.prefinished||t.finalCalled||("function"==typeof e._final?(t.pendingcb++,t.finalCalled=!0,i.nextTick(x,e,t)):(t.prefinished=!0,e.emit("prefinish")))}(e,t),0===t.pendingcb&&(t.finished=!0,e.emit("finish"))),n}l.inherits(g,f),y.prototype.getBuffer=function(){for(var e=this.bufferedRequest,t=[];e;)t.push(e),e=e.next;return t},function(){try{Object.defineProperty(y.prototype,"buffer",{get:c.deprecate(function(){return this.getBuffer()},"_writableState.buffer is deprecated. Use _writableState.getBuffer instead.","DEP0003")})}catch(e){}}(),"function"==typeof Symbol&&Symbol.hasInstance&&"function"==typeof Function.prototype[Symbol.hasInstance]?(h=Function.prototype[Symbol.hasInstance],Object.defineProperty(g,Symbol.hasInstance,{value:function(e){return!!h.call(this,e)||this===g&&(e&&e._writableState instanceof y)}})):h=function(e){return e instanceof this},g.prototype.pipe=function(){this.emit("error",new Error("Cannot pipe, not readable"))},g.prototype.write=function(e,t,n){var r,o=this._writableState,a=!1,u=!o.objectMode&&(r=e,p.isBuffer(r)||r instanceof d);return u&&!p.isBuffer(e)&&(e=function(e){return p.from(e)}(e)),"function"==typeof t&&(n=t,t=null),u?t="buffer":t||(t=o.defaultEncoding),"function"!=typeof n&&(n=m),o.ended?function(e,t){var n=new Error("write after end");e.emit("error",n),i.nextTick(t,n)}(this,n):(u||function(e,t,n,r){var o=!0,a=!1;return null===n?a=new TypeError("May not write null values to stream"):"string"==typeof n||void 0===n||t.objectMode||(a=new TypeError("Invalid non-string/buffer chunk")),a&&(e.emit("error",a),i.nextTick(r,a),o=!1),o}(this,o,e,n))&&(o.pendingcb++,a=function(e,t,n,r,o,i){if(!n){var a=function(e,t,n){e.objectMode||!1===e.decodeStrings||"string"!=typeof t||(t=p.from(t,n));return t}(t,r,o);r!==a&&(n=!0,o="buffer",r=a)}var u=t.objectMode?1:r.length;t.length+=u;var s=t.length-1))throw new TypeError("Unknown encoding: "+e);return this._writableState.defaultEncoding=e,this},Object.defineProperty(g.prototype,"writableHighWaterMark",{enumerable:!1,get:function(){return this._writableState.highWaterMark}}),g.prototype._write=function(e,t,n){n(new Error("_write() is not implemented"))},g.prototype._writev=null,g.prototype.end=function(e,t,n){var r=this._writableState;"function"==typeof e?(n=e,e=null,t=null):"function"==typeof t&&(n=t,t=null),null!==e&&void 0!==e&&this.write(e,t),r.corked&&(r.corked=1,this.uncork()),r.ending||r.finished||function(e,t,n){t.ending=!0,S(e,t),n&&(t.finished?i.nextTick(n):e.once("finish",n));t.ended=!0,e.writable=!1}(this,r,n)},Object.defineProperty(g.prototype,"destroyed",{get:function(){return void 0!==this._writableState&&this._writableState.destroyed},set:function(e){this._writableState&&(this._writableState.destroyed=e)}}),g.prototype.destroy=v.destroy,g.prototype._undestroy=v.undestroy,g.prototype._destroy=function(e,t){this.end(),t(e)}}).call(t,n(55),n(309).setImmediate,n(31))},function(e,t,n){"use strict";e.exports=function(e){return"function"==typeof e}},function(e,t,n){"use strict";e.exports=n(691)()?Array.from:n(692)},function(e,t,n){"use strict";var r=n(705),o=n(67),i=n(82),a=Array.prototype.indexOf,u=Object.prototype.hasOwnProperty,s=Math.abs,l=Math.floor;e.exports=function(e){var t,n,c,f;if(!r(e))return a.apply(this,arguments);for(n=o(i(this).length),c=arguments[1],t=c=isNaN(c)?0:c>=0?l(c):o(this.length)-l(s(c));t1&&void 0!==arguments[1])||arguments[1];return e=(0,r.normalizeArray)(e),{type:u,payload:{thing:e,shown:t}}},t.changeMode=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=(0,r.normalizeArray)(e),{type:a,payload:{thing:e,mode:t}}};var r=n(9),o=t.UPDATE_LAYOUT="layout_update_layout",i=t.UPDATE_FILTER="layout_update_filter",a=t.UPDATE_MODE="layout_update_mode",u=t.SHOW="layout_show"},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.validateBeforeExecute=t.canExecuteScheme=t.operationScheme=t.hasHost=t.operationWithMeta=t.parameterWithMeta=t.parameterInclusionSettingFor=t.parameterWithMetaByIdentity=t.allowTryItOutFor=t.mutatedRequestFor=t.requestFor=t.responseFor=t.mutatedRequests=t.requests=t.responses=t.taggedOperations=t.operationsWithTags=t.tagDetails=t.tags=t.operationsWithRootInherited=t.schemes=t.host=t.basePath=t.definitions=t.findDefinition=t.securityDefinitions=t.security=t.produces=t.consumes=t.operations=t.paths=t.semver=t.version=t.externalDocs=t.info=t.isOAS3=t.spec=t.specJsonWithResolvedSubtrees=t.specResolvedSubtree=t.specResolved=t.specJson=t.specSource=t.specStr=t.url=t.lastError=void 0;var r,o=n(83),i=(r=o)&&r.__esModule?r:{default:r};t.getParameter=function(e,t,n,r){return t=t||[],e.getIn(["meta","paths"].concat((0,i.default)(t),["parameters"]),(0,s.fromJS)([])).find(function(e){return s.Map.isMap(e)&&e.get("name")===n&&e.get("in")===r})||(0,s.Map)()},t.parameterValues=function(e,t,n){return t=t||[],P.apply(void 0,[e].concat((0,i.default)(t))).get("parameters",(0,s.List)()).reduce(function(e,t){var r=n&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set(t.get("in")+"."+t.get("name"),r)},(0,s.fromJS)({}))},t.parametersIncludeIn=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(s.List.isList(e))return e.some(function(e){return s.Map.isMap(e)&&e.get("in")===t})},t.parametersIncludeType=T,t.contentTypeValues=function(e,t){t=t||[];var n=d(e).getIn(["paths"].concat((0,i.default)(t)),(0,s.fromJS)({})),r=e.getIn(["meta","paths"].concat((0,i.default)(t)),(0,s.fromJS)({})),o=M(e,t),a=n.get("parameters")||new s.List,u=r.get("consumes_value")?r.get("consumes_value"):T(a,"file")?"multipart/form-data":T(a,"formData")?"application/x-www-form-urlencoded":void 0;return(0,s.fromJS)({requestContentType:u,responseContentType:o})},t.operationConsumes=function(e,t){return t=t||[],d(e).getIn(["paths"].concat((0,i.default)(t),["consumes"]),(0,s.fromJS)({}))},t.currentProducesFor=M;var a=n(57),u=n(9),s=n(7);var l=["get","put","post","delete","options","head","patch","trace"],c=function(e){return e||(0,s.Map)()},f=(t.lastError=(0,a.createSelector)(c,function(e){return e.get("lastError")}),t.url=(0,a.createSelector)(c,function(e){return e.get("url")}),t.specStr=(0,a.createSelector)(c,function(e){return e.get("spec")||""}),t.specSource=(0,a.createSelector)(c,function(e){return e.get("specSource")||"not-editor"}),t.specJson=(0,a.createSelector)(c,function(e){return e.get("json",(0,s.Map)())})),p=(t.specResolved=(0,a.createSelector)(c,function(e){return e.get("resolved",(0,s.Map)())}),t.specResolvedSubtree=function(e,t){return e.getIn(["resolvedSubtrees"].concat((0,i.default)(t)),void 0)},function e(t,n){return s.Map.isMap(t)&&s.Map.isMap(n)?n.get("$$ref")?n:(0,s.OrderedMap)().mergeWith(e,t,n):n}),d=t.specJsonWithResolvedSubtrees=(0,a.createSelector)(c,function(e){return(0,s.OrderedMap)().mergeWith(p,e.get("json"),e.get("resolvedSubtrees"))}),h=t.spec=function(e){return f(e)},v=(t.isOAS3=(0,a.createSelector)(h,function(){return!1}),t.info=(0,a.createSelector)(h,function(e){return j(e&&e.get("info"))})),m=(t.externalDocs=(0,a.createSelector)(h,function(e){return j(e&&e.get("externalDocs"))}),t.version=(0,a.createSelector)(v,function(e){return e&&e.get("version")})),y=(t.semver=(0,a.createSelector)(m,function(e){return/v?([0-9]*)\.([0-9]*)\.([0-9]*)/i.exec(e).slice(1)}),t.paths=(0,a.createSelector)(d,function(e){return e.get("paths")})),g=t.operations=(0,a.createSelector)(y,function(e){if(!e||e.size<1)return(0,s.List)();var t=(0,s.List)();return e&&e.forEach?(e.forEach(function(e,n){if(!e||!e.forEach)return{};e.forEach(function(e,r){l.indexOf(r)<0||(t=t.push((0,s.fromJS)({path:n,method:r,operation:e,id:r+"-"+n})))})}),t):(0,s.List)()}),b=t.consumes=(0,a.createSelector)(h,function(e){return(0,s.Set)(e.get("consumes"))}),_=t.produces=(0,a.createSelector)(h,function(e){return(0,s.Set)(e.get("produces"))}),w=(t.security=(0,a.createSelector)(h,function(e){return e.get("security",(0,s.List)())}),t.securityDefinitions=(0,a.createSelector)(h,function(e){return e.get("securityDefinitions")}),t.findDefinition=function(e,t){var n=e.getIn(["resolvedSubtrees","definitions",t],null),r=e.getIn(["json","definitions",t],null);return n||r||null},t.definitions=(0,a.createSelector)(h,function(e){return e.get("definitions")||(0,s.Map)()}),t.basePath=(0,a.createSelector)(h,function(e){return e.get("basePath")}),t.host=(0,a.createSelector)(h,function(e){return e.get("host")}),t.schemes=(0,a.createSelector)(h,function(e){return e.get("schemes",(0,s.Map)())}),t.operationsWithRootInherited=(0,a.createSelector)(g,b,_,function(e,t,n){return e.map(function(e){return e.update("operation",function(e){if(e){if(!s.Map.isMap(e))return;return e.withMutations(function(e){return e.get("consumes")||e.update("consumes",function(e){return(0,s.Set)(e).merge(t)}),e.get("produces")||e.update("produces",function(e){return(0,s.Set)(e).merge(n)}),e})}return(0,s.Map)()})})})),E=t.tags=(0,a.createSelector)(h,function(e){return e.get("tags",(0,s.List)())}),x=t.tagDetails=function(e,t){return(E(e)||(0,s.List)()).filter(s.Map.isMap).find(function(e){return e.get("name")===t},(0,s.Map)())},S=t.operationsWithTags=(0,a.createSelector)(w,E,function(e,t){return e.reduce(function(e,t){var n=(0,s.Set)(t.getIn(["operation","tags"]));return n.count()<1?e.update("default",(0,s.List)(),function(e){return e.push(t)}):n.reduce(function(e,n){return e.update(n,(0,s.List)(),function(e){return e.push(t)})},e)},t.reduce(function(e,t){return e.set(t.get("name"),(0,s.List)())},(0,s.OrderedMap)()))}),C=(t.taggedOperations=function(e){return function(t){var n=(0,t.getConfigs)(),r=n.tagsSorter,o=n.operationsSorter;return S(e).sortBy(function(e,t){return t},function(e,t){var n="function"==typeof r?r:u.sorters.tagsSorter[r];return n?n(e,t):null}).map(function(t,n){var r="function"==typeof o?o:u.sorters.operationsSorter[o],i=r?t.sort(r):t;return(0,s.Map)({tagDetails:x(e,n),operations:i})})}},t.responses=(0,a.createSelector)(c,function(e){return e.get("responses",(0,s.Map)())})),k=t.requests=(0,a.createSelector)(c,function(e){return e.get("requests",(0,s.Map)())}),A=t.mutatedRequests=(0,a.createSelector)(c,function(e){return e.get("mutatedRequests",(0,s.Map)())}),O=(t.responseFor=function(e,t,n){return C(e).getIn([t,n],null)},t.requestFor=function(e,t,n){return k(e).getIn([t,n],null)},t.mutatedRequestFor=function(e,t,n){return A(e).getIn([t,n],null)},t.allowTryItOutFor=function(){return!0},t.parameterWithMetaByIdentity=function(e,t,n){var r=d(e).getIn(["paths"].concat((0,i.default)(t),["parameters"]),(0,s.OrderedMap)()),o=e.getIn(["meta","paths"].concat((0,i.default)(t),["parameters"]),(0,s.OrderedMap)());return r.map(function(e){var t=o.get(n.get("name")+"."+n.get("in")),r=o.get(n.get("name")+"."+n.get("in")+".hash-"+n.hashCode());return(0,s.OrderedMap)().merge(e,t,r)}).find(function(e){return e.get("in")===n.get("in")&&e.get("name")===n.get("name")},(0,s.OrderedMap)())}),P=(t.parameterInclusionSettingFor=function(e,t,n,r){var o=n+"."+r;return e.getIn(["meta","paths"].concat((0,i.default)(t),["parameter_inclusions",o]),!1)},t.parameterWithMeta=function(e,t,n,r){var o=d(e).getIn(["paths"].concat((0,i.default)(t),["parameters"]),(0,s.OrderedMap)()).find(function(e){return e.get("in")===r&&e.get("name")===n},(0,s.OrderedMap)());return O(e,t,o)},t.operationWithMeta=function(e,t,n){var r=d(e).getIn(["paths",t,n],(0,s.OrderedMap)()),o=e.getIn(["meta","paths",t,n],(0,s.OrderedMap)()),i=r.get("parameters",(0,s.List)()).map(function(r){return O(e,[t,n],r)});return(0,s.OrderedMap)().merge(r,o).set("parameters",i)});t.hasHost=(0,a.createSelector)(h,function(e){var t=e.get("host");return"string"==typeof t&&t.length>0&&"/"!==t[0]});function T(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(s.List.isList(e))return e.some(function(e){return s.Map.isMap(e)&&e.get("type")===t})}function M(e,t){t=t||[];var n=d(e).getIn(["paths"].concat((0,i.default)(t)),null);if(null!==n){var r=e.getIn(["meta","paths"].concat((0,i.default)(t),["produces_value"]),null),o=n.getIn(["produces",0],null);return r||o||"application/json"}}var I=t.operationScheme=function(e,t,n){var r=e.get("url").match(/^([a-z][a-z0-9+\-.]*):/),o=Array.isArray(r)?r[1]:null;return e.getIn(["scheme",t,n])||e.getIn(["scheme","_defaultScheme"])||o||""};t.canExecuteScheme=function(e,t,n){return["http","https"].indexOf(I(e,t,n))>-1},t.validateBeforeExecute=function(e,t){t=t||[];var n=!0;return e.getIn(["meta","paths"].concat((0,i.default)(t),["parameters"]),(0,s.fromJS)([])).forEach(function(e){var t=e.get("errors");t&&t.count()&&(n=!1)}),n};function j(e){return s.Map.isMap(e)?e:new s.Map}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.execute=t.executeRequest=t.logRequest=t.setMutatedRequest=t.setRequest=t.setResponse=t.updateEmptyParamInclusion=t.validateParams=t.invalidateResolvedSubtreeCache=t.updateResolvedSubtree=t.requestResolvedSubtree=t.resolveSpec=t.parseToJson=t.SET_SCHEME=t.UPDATE_RESOLVED_SUBTREE=t.UPDATE_RESOLVED=t.UPDATE_OPERATION_META_VALUE=t.CLEAR_VALIDATE_PARAMS=t.CLEAR_REQUEST=t.CLEAR_RESPONSE=t.LOG_REQUEST=t.SET_MUTATED_REQUEST=t.SET_REQUEST=t.SET_RESPONSE=t.VALIDATE_PARAMS=t.UPDATE_EMPTY_PARAM_INCLUSION=t.UPDATE_PARAM=t.UPDATE_JSON=t.UPDATE_URL=t.UPDATE_SPEC=void 0;var r=b(n(25)),o=b(n(84)),i=b(n(23)),a=b(n(42)),u=b(n(203)),s=b(n(339)),l=b(n(340)),c=b(n(45));t.updateSpec=function(e){var t=L(e).replace(/\t/g," ");if("string"==typeof e)return{type:_,payload:t}},t.updateResolved=function(e){return{type:N,payload:e}},t.updateUrl=function(e){return{type:w,payload:e}},t.updateJsonSpec=function(e){return{type:E,payload:e}},t.changeParam=function(e,t,n,r,o){return{type:x,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:o}}},t.changeParamByIdentity=function(e,t,n,r){return{type:x,payload:{path:e,param:t,value:n,isXml:r}}},t.clearValidateParams=function(e){return{type:I,payload:{pathMethod:e}}},t.changeConsumesValue=function(e,t){return{type:j,payload:{path:e,value:t,key:"consumes_value"}}},t.changeProducesValue=function(e,t){return{type:j,payload:{path:e,value:t,key:"produces_value"}}},t.clearResponse=function(e,t){return{type:T,payload:{path:e,method:t}}},t.clearRequest=function(e,t){return{type:M,payload:{path:e,method:t}}},t.setScheme=function(e,t,n){return{type:D,payload:{scheme:e,path:t,method:n}}};var f=b(n(207)),p=n(7),d=b(n(209)),h=b(n(179)),v=b(n(343)),m=b(n(764)),y=b(n(766)),g=n(9);function b(e){return e&&e.__esModule?e:{default:e}}var _=t.UPDATE_SPEC="spec_update_spec",w=t.UPDATE_URL="spec_update_url",E=t.UPDATE_JSON="spec_update_json",x=t.UPDATE_PARAM="spec_update_param",S=t.UPDATE_EMPTY_PARAM_INCLUSION="spec_update_empty_param_inclusion",C=t.VALIDATE_PARAMS="spec_validate_param",k=t.SET_RESPONSE="spec_set_response",A=t.SET_REQUEST="spec_set_request",O=t.SET_MUTATED_REQUEST="spec_set_mutated_request",P=t.LOG_REQUEST="spec_log_request",T=t.CLEAR_RESPONSE="spec_clear_response",M=t.CLEAR_REQUEST="spec_clear_request",I=t.CLEAR_VALIDATE_PARAMS="spec_clear_validate_param",j=t.UPDATE_OPERATION_META_VALUE="spec_update_operation_meta_value",N=t.UPDATE_RESOLVED="spec_update_resolved",R=t.UPDATE_RESOLVED_SUBTREE="spec_update_resolved_subtree",D=t.SET_SCHEME="set_scheme",L=function(e){return(0,v.default)(e)?e:""};t.parseToJson=function(e){return function(t){var n=t.specActions,r=t.specSelectors,o=t.errActions,i=r.specStr,a=null;try{e=e||i(),o.clear({source:"parser"}),a=f.default.safeLoad(e)}catch(e){return console.error(e),o.newSpecErr({source:"parser",level:"error",message:e.reason,line:e.mark&&e.mark.line?e.mark.line+1:void 0})}return a&&"object"===(void 0===a?"undefined":(0,c.default)(a))?n.updateJsonSpec(a):{}}};var U=!1,q=(t.resolveSpec=function(e,t){return function(n){var r=n.specActions,o=n.specSelectors,i=n.errActions,a=n.fn,u=a.fetch,s=a.resolve,l=a.AST,c=void 0===l?{}:l,f=n.getConfigs;U||(console.warn("specActions.resolveSpec is deprecated since v3.10.0 and will be removed in v4.0.0; use requestResolvedSubtree instead!"),U=!0);var p=f(),d=p.modelPropertyMacro,h=p.parameterMacro,v=p.requestInterceptor,m=p.responseInterceptor;void 0===e&&(e=o.specJson()),void 0===t&&(t=o.url());var y=c.getLineNumberForPath?c.getLineNumberForPath:function(){},g=o.specStr();return s({fetch:u,spec:e,baseDoc:t,modelPropertyMacro:d,parameterMacro:h,requestInterceptor:v,responseInterceptor:m}).then(function(e){var t=e.spec,n=e.errors;if(i.clear({type:"thrown"}),Array.isArray(n)&&n.length>0){var o=n.map(function(e){return console.error(e),e.line=e.fullPath?y(g,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",Object.defineProperty(e,"message",{enumerable:!0,value:e.message}),e});i.newThrownErrBatch(o)}return r.updateResolved(t)})}},[]),F=(0,m.default)((0,l.default)(s.default.mark(function e(){var t,n,r,o,i,a,c,f,d,h,v,m,g,b,_,w,E;return s.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(t=q.system){e.next=4;break}return console.error("debResolveSubtrees: don't have a system to operate on, aborting."),e.abrupt("return");case 4:if(n=t.errActions,r=t.errSelectors,o=t.fn,i=o.resolveSubtree,a=o.AST,c=void 0===a?{}:a,f=t.specSelectors,d=t.specActions,i){e.next=8;break}return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."),e.abrupt("return");case 8:return h=c.getLineNumberForPath?c.getLineNumberForPath:function(){},v=f.specStr(),m=t.getConfigs(),g=m.modelPropertyMacro,b=m.parameterMacro,_=m.requestInterceptor,w=m.responseInterceptor,e.prev=11,e.next=14,q.reduce(function(){var e=(0,l.default)(s.default.mark(function e(t,o){var a,u,l,c,p,d,m;return s.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t;case 2:return a=e.sent,u=a.resultMap,l=a.specWithCurrentSubtrees,e.next=7,i(l,o,{baseDoc:f.url(),modelPropertyMacro:g,parameterMacro:b,requestInterceptor:_,responseInterceptor:w});case 7:return c=e.sent,p=c.errors,d=c.spec,r.allErrors().size&&n.clear({type:"thrown"}),Array.isArray(p)&&p.length>0&&(m=p.map(function(e){return e.line=e.fullPath?h(v,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",Object.defineProperty(e,"message",{enumerable:!0,value:e.message}),e}),n.newThrownErrBatch(m)),(0,y.default)(u,o,d),(0,y.default)(l,o,d),e.abrupt("return",{resultMap:u,specWithCurrentSubtrees:l});case 15:case"end":return e.stop()}},e,void 0)}));return function(t,n){return e.apply(this,arguments)}}(),u.default.resolve({resultMap:(f.specResolvedSubtree([])||(0,p.Map)()).toJS(),specWithCurrentSubtrees:f.specJson().toJS()}));case 14:E=e.sent,delete q.system,q=[],e.next=22;break;case 19:e.prev=19,e.t0=e.catch(11),console.error(e.t0);case 22:d.updateResolvedSubtree([],E.resultMap);case 23:case"end":return e.stop()}},e,void 0,[[11,19]])})),35);t.requestResolvedSubtree=function(e){return function(t){q.push(e),q.system=t,F()}};t.updateResolvedSubtree=function(e,t){return{type:R,payload:{path:e,value:t}}},t.invalidateResolvedSubtreeCache=function(){return{type:R,payload:{path:[],value:(0,p.Map)()}}},t.validateParams=function(e,t){return{type:C,payload:{pathMethod:e,isOAS3:t}}},t.updateEmptyParamInclusion=function(e,t,n,r){return{type:S,payload:{pathMethod:e,paramName:t,paramIn:n,includeEmptyValue:r}}};t.setResponse=function(e,t,n){return{payload:{path:e,method:t,res:n},type:k}},t.setRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:A}},t.setMutatedRequest=function(e,t,n){return{payload:{path:e,method:t,req:n},type:O}},t.logRequest=function(e){return{payload:e,type:P}},t.executeRequest=function(e){return function(t){var n=t.fn,r=t.specActions,o=t.specSelectors,u=t.getConfigs,s=t.oas3Selectors,l=e.pathName,c=e.method,f=e.operation,p=u(),v=p.requestInterceptor,m=p.responseInterceptor,y=f.toJS();if(y&&y.parameters&&y.parameters.length&&y.parameters.filter(function(e){return e&&!0===e.allowEmptyValue}).forEach(function(t){if(o.parameterInclusionSettingFor([l,c],t.name,t.in)){e.parameters=e.parameters||{};var n=e.parameters[t.name];(!n||n&&0===n.size)&&(e.parameters[t.name]="")}}),e.contextUrl=(0,d.default)(o.url()).toString(),y&&y.operationId?e.operationId=y.operationId:y&&l&&c&&(e.operationId=n.opId(y,l,c)),o.isOAS3()){var b=l+":"+c;e.server=s.selectedServer(b)||s.selectedServer();var _=s.serverVariables({server:e.server,namespace:b}).toJS(),w=s.serverVariables({server:e.server}).toJS();e.serverVariables=(0,a.default)(_).length?_:w,e.requestContentType=s.requestContentType(l,c),e.responseContentType=s.responseContentType(l,c)||"*/*";var E=s.requestBodyValue(l,c);(0,g.isJSONObject)(E)?e.requestBody=JSON.parse(E):E&&E.toJS?e.requestBody=E.toJS():e.requestBody=E}var x=(0,i.default)({},e);x=n.buildRequest(x),r.setRequest(e.pathName,e.method,x);e.requestInterceptor=function(t){var n=v.apply(this,[t]),o=(0,i.default)({},n);return r.setMutatedRequest(e.pathName,e.method,o),n},e.responseInterceptor=m;var S=Date.now();return n.execute(e).then(function(t){t.duration=Date.now()-S,r.setResponse(e.pathName,e.method,t)}).catch(function(t){return r.setResponse(e.pathName,e.method,{error:!0,err:(0,h.default)(t)})})}};t.execute=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,i=(0,o.default)(e,["path","method"]);return function(e){var o=e.fn.fetch,a=e.specSelectors,u=e.specActions,s=a.specJsonWithResolvedSubtrees().toJS(),l=a.operationScheme(t,n),c=a.contentTypeValues([t,n]).toJS(),f=c.requestContentType,p=c.responseContentType,d=/xml/i.test(f),h=a.parameterValues([t,n],d).toJS();return u.executeRequest((0,r.default)({},i,{fetch:o,spec:s,pathName:t,method:n,parameters:h,requestContentType:f,scheme:l,responseContentType:p}))}}},function(e,t,n){e.exports={default:n(733),__esModule:!0}},function(e,t){e.exports=function(e,t,n,r){if(!(e instanceof t)||void 0!==r&&r in e)throw TypeError(n+": incorrect invocation!");return e}},function(e,t,n){"use strict";var r=n(94);e.exports.f=function(e){return new function(e){var t,n;this.promise=new e(function(e,r){if(void 0!==t||void 0!==n)throw TypeError("Bad Promise constructor");t=e,n=r}),this.resolve=r(t),this.reject=r(n)}(e)}},function(e,t,n){var r=n(50);e.exports=function(e,t,n){for(var o in t)n&&e[o]?e[o]=t[o]:r(e,o,t[o]);return e}},function(e,t,n){"use strict";var r=n(742);e.exports=r},function(e,t,n){"use strict";var r=n(86);e.exports=new r({explicit:[n(745),n(746),n(747)]})},function(e,t,n){"use strict";(function(t){var r=n(762),o=n(763),i=/^([a-z][a-z0-9.+-]*:)?(\/\/)?([\S\s]*)/i,a=/^[A-Za-z][A-Za-z0-9+-.]*:\/\//,u=[["#","hash"],["?","query"],["/","pathname"],["@","auth",1],[NaN,"host",void 0,1,1],[/:(\d+)$/,"port",void 0,1],[NaN,"hostname",void 0,1,1]],s={hash:1,query:1};function l(e){var n,r={},o=typeof(e=e||t.location||{});if("blob:"===e.protocol)r=new f(unescape(e.pathname),{});else if("string"===o)for(n in r=new f(e,{}),s)delete r[n];else if("object"===o){for(n in e)n in s||(r[n]=e[n]);void 0===r.slashes&&(r.slashes=a.test(e.href))}return r}function c(e){var t=i.exec(e);return{protocol:t[1]?t[1].toLowerCase():"",slashes:!!t[2],rest:t[3]}}function f(e,t,n){if(!(this instanceof f))return new f(e,t,n);var i,a,s,p,d,h,v=u.slice(),m=typeof t,y=this,g=0;for("object"!==m&&"string"!==m&&(n=t,t=null),n&&"function"!=typeof n&&(n=o.parse),t=l(t),i=!(a=c(e||"")).protocol&&!a.slashes,y.slashes=a.slashes||i&&t.slashes,y.protocol=a.protocol||t.protocol||"",e=a.rest,a.slashes||(v[2]=[/(.*)/,"pathname"]);g-1||r("96",e),!l.plugins[n]){t.extractEvents||r("97",e),l.plugins[n]=t;var a=t.eventTypes;for(var s in a)u(a[s],t,s)||r("98",s,e)}}}function u(e,t,n){l.eventNameDispatchConfigs.hasOwnProperty(n)&&r("99",n),l.eventNameDispatchConfigs[n]=e;var o=e.phasedRegistrationNames;if(o){for(var i in o){if(o.hasOwnProperty(i))s(o[i],t,n)}return!0}return!!e.registrationName&&(s(e.registrationName,t,n),!0)}function s(e,t,n){l.registrationNameModules[e]&&r("100",e),l.registrationNameModules[e]=t,l.registrationNameDependencies[e]=t.eventTypes[n].dependencies}var l={plugins:[],eventNameDispatchConfigs:{},registrationNameModules:{},registrationNameDependencies:{},possibleRegistrationNames:null,injectEventPluginOrder:function(e){o&&r("101"),o=Array.prototype.slice.call(e),a()},injectEventPluginsByName:function(e){var t=!1;for(var n in e)if(e.hasOwnProperty(n)){var o=e[n];i.hasOwnProperty(n)&&i[n]===o||(i[n]&&r("102",n),i[n]=o,t=!0)}t&&a()},getPluginModuleForEvent:function(e){var t=e.dispatchConfig;if(t.registrationName)return l.registrationNameModules[t.registrationName]||null;if(void 0!==t.phasedRegistrationNames){var n=t.phasedRegistrationNames;for(var r in n)if(n.hasOwnProperty(r)){var o=l.registrationNameModules[n[r]];if(o)return o}}return null},_resetEventPlugins:function(){for(var e in o=null,i)i.hasOwnProperty(e)&&delete i[e];l.plugins.length=0;var t=l.eventNameDispatchConfigs;for(var n in t)t.hasOwnProperty(n)&&delete t[n];var r=l.registrationNameModules;for(var a in r)r.hasOwnProperty(a)&&delete r[a]}};e.exports=l},function(e,t,n){"use strict";var r,o,i=n(11),a=n(212);n(8),n(10);function u(e,t,n,r){var o=e.type||"unknown-event";e.currentTarget=s.getNodeFromInstance(r),t?a.invokeGuardedCallbackWithCatch(o,n,e):a.invokeGuardedCallback(o,n,e),e.currentTarget=null}var s={isEndish:function(e){return"topMouseUp"===e||"topTouchEnd"===e||"topTouchCancel"===e},isMoveish:function(e){return"topMouseMove"===e||"topTouchMove"===e},isStartish:function(e){return"topMouseDown"===e||"topTouchStart"===e},executeDirectDispatch:function(e){var t=e._dispatchListeners,n=e._dispatchInstances;Array.isArray(t)&&i("103"),e.currentTarget=t?s.getNodeFromInstance(n):null;var r=t?t(e):null;return e.currentTarget=null,e._dispatchListeners=null,e._dispatchInstances=null,r},executeDispatchesInOrder:function(e,t){var n=e._dispatchListeners,r=e._dispatchInstances;if(Array.isArray(n))for(var o=0;o0&&r.length<20?n+" (keys: "+r.join(", ")+")":n}function s(e,t){var n=o.get(e);return n||null}var l={isMounted:function(e){var t=o.get(e);return!!t&&!!t._renderedComponent},enqueueCallback:function(e,t,n){l.validateCallback(t,n);var r=s(e);if(!r)return null;r._pendingCallbacks?r._pendingCallbacks.push(t):r._pendingCallbacks=[t],a(r)},enqueueCallbackInternal:function(e,t){e._pendingCallbacks?e._pendingCallbacks.push(t):e._pendingCallbacks=[t],a(e)},enqueueForceUpdate:function(e){var t=s(e);t&&(t._pendingForceUpdate=!0,a(t))},enqueueReplaceState:function(e,t,n){var r=s(e);r&&(r._pendingStateQueue=[t],r._pendingReplaceState=!0,void 0!==n&&null!==n&&(l.validateCallback(n,"replaceState"),r._pendingCallbacks?r._pendingCallbacks.push(n):r._pendingCallbacks=[n]),a(r))},enqueueSetState:function(e,t){var n=s(e);n&&((n._pendingStateQueue||(n._pendingStateQueue=[])).push(t),a(n))},enqueueElementInternal:function(e,t,n){e._pendingElement=t,e._context=n,a(e)},validateCallback:function(e,t){e&&"function"!=typeof e&&r("122",t,u(e))}};e.exports=l},function(e,t,n){"use strict";n(13);var r=n(34),o=(n(10),r);e.exports=o},function(e,t,n){"use strict";e.exports=function(e){var t,n=e.keyCode;return"charCode"in e?0===(t=e.charCode)&&13===n&&(t=13):t=n,t>=32||13===t?t:0}},function(e,t,n){var r=n(62),o=n(228),i=n(47),a="[object Object]",u=Function.prototype,s=Object.prototype,l=u.toString,c=s.hasOwnProperty,f=l.call(Object);e.exports=function(e){if(!i(e)||r(e)!=a)return!1;var t=o(e);if(null===t)return!0;var n=c.call(t,"constructor")&&t.constructor;return"function"==typeof n&&n instanceof n&&l.call(n)==f}},function(e,t,n){var r=n(298)(Object.getPrototypeOf,Object);e.exports=r},function(e,t,n){var r=n(292);e.exports=function(e){var t=new e.constructor(e.byteLength);return new r(t).set(new r(e)),t}},function(e,t){var n=this&&this.__extends||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);function r(){this.constructor=e}e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)},r=Object.prototype.hasOwnProperty; -/*! - * https://github.com/Starcounter-Jack/JSON-Patch - * (c) 2017 Joachim Wester - * MIT license - */function o(e,t){return r.call(e,t)}function i(e){if(Array.isArray(e)){for(var t=new Array(e.length),n=0;n=48&&t<=57))return!1;n++}return!0},t.escapePathComponent=a,t.unescapePathComponent=function(e){return e.replace(/~1/g,"/").replace(/~0/g,"~")},t._getPathRecursive=u,t.getPath=function(e,t){if(e===t)return"/";var n=u(e,t);if(""===n)throw new Error("Object not found in root");return"/"+n},t.hasUndefined=function e(t){if(void 0===t)return!0;if(t)if(Array.isArray(t)){for(var n=0,r=t.length;nw;w++)if((p||w in g)&&(m=b(v=g[w],w,y),e))if(n)E[w]=m;else if(m)switch(e){case 3:return!0;case 5:return v;case 6:return w;case 2:E.push(v)}else if(c)return!1;return f?-1:l||c?c:E}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.authorizeRequest=t.authorizeAccessCodeWithBasicAuthentication=t.authorizeAccessCodeWithFormParams=t.authorizeApplication=t.authorizePassword=t.preAuthorizeImplicit=t.CONFIGURE_AUTH=t.VALIDATE=t.AUTHORIZE_OAUTH2=t.PRE_AUTHORIZE_OAUTH2=t.LOGOUT=t.AUTHORIZE=t.SHOW_AUTH_POPUP=void 0;var r=l(n(45)),o=l(n(23)),i=l(n(41));t.showDefinitions=function(e){return{type:c,payload:e}},t.authorize=function(e){return{type:f,payload:e}},t.logout=function(e){return{type:p,payload:e}},t.authorizeOauth2=function(e){return{type:d,payload:e}},t.configureAuth=function(e){return{type:h,payload:e}};var a=l(n(209)),u=l(n(32)),s=n(9);function l(e){return e&&e.__esModule?e:{default:e}}var c=t.SHOW_AUTH_POPUP="show_popup",f=t.AUTHORIZE="authorize",p=t.LOGOUT="logout",d=(t.PRE_AUTHORIZE_OAUTH2="pre_authorize_oauth2",t.AUTHORIZE_OAUTH2="authorize_oauth2"),h=(t.VALIDATE="validate",t.CONFIGURE_AUTH="configure_auth");t.preAuthorizeImplicit=function(e){return function(t){var n=t.authActions,r=t.errActions,o=e.auth,a=e.token,s=e.isValid,l=o.schema,c=o.name,f=l.get("flow");delete u.default.swaggerUIRedirectOauth2,"accessCode"===f||s||r.newAuthErr({authId:c,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),a.error?r.newAuthErr({authId:c,source:"auth",level:"error",message:(0,i.default)(a)}):n.authorizeOauth2({auth:o,token:a})}};t.authorizePassword=function(e){return function(t){var n=t.authActions,r=e.schema,i=e.name,a=e.username,u=e.password,l=e.passwordType,c=e.clientId,f=e.clientSecret,p={grant_type:"password",scope:e.scopes.join(" ")},d={},h={};if("basic"===l)h.Authorization="Basic "+(0,s.btoa)(a+":"+u);else switch((0,o.default)(p,{username:a},{password:u}),l){case"query":v(d,c,f);break;case"request-body":v(p,c,f);break;default:h.Authorization="Basic "+(0,s.btoa)(c+":"+f)}return n.authorizeRequest({body:(0,s.buildFormData)(p),url:r.get("tokenUrl"),name:i,headers:h,query:d,auth:e})}};function v(e,t,n){t&&(0,o.default)(e,{client_id:t}),n&&(0,o.default)(e,{client_secret:n})}t.authorizeApplication=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.scopes,i=e.name,a=e.clientId,u=e.clientSecret,l={Authorization:"Basic "+(0,s.btoa)(a+":"+u)},c={grant_type:"client_credentials",scope:o.join(" ")};return n.authorizeRequest({body:(0,s.buildFormData)(c),name:i,url:r.get("tokenUrl"),auth:e,headers:l})}},t.authorizeAccessCodeWithFormParams=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,i=t.name,a=t.clientId,u=t.clientSecret,l={grant_type:"authorization_code",code:t.code,client_id:a,client_secret:u,redirect_uri:n};return r.authorizeRequest({body:(0,s.buildFormData)(l),name:i,url:o.get("tokenUrl"),auth:t})}},t.authorizeAccessCodeWithBasicAuthentication=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,i=t.name,a=t.clientId,u=t.clientSecret,l={Authorization:"Basic "+(0,s.btoa)(a+":"+u)},c={grant_type:"authorization_code",code:t.code,client_id:a,redirect_uri:n};return r.authorizeRequest({body:(0,s.buildFormData)(c),name:i,url:o.get("tokenUrl"),auth:t,headers:l})}},t.authorizeRequest=function(e){return function(t){var n=t.fn,u=t.getConfigs,s=t.authActions,l=t.errActions,c=t.oas3Selectors,f=t.specSelectors,p=t.authSelectors,d=e.body,h=e.query,v=void 0===h?{}:h,m=e.headers,y=void 0===m?{}:m,g=e.name,b=e.url,_=e.auth,w=(p.getConfigs()||{}).additionalQueryStringParams,E=void 0;E=f.isOAS3()?(0,a.default)(b,c.selectedServer(),!0):(0,a.default)(b,f.url(),!0),"object"===(void 0===w?"undefined":(0,r.default)(w))&&(E.query=(0,o.default)({},E.query,w));var x=E.toString(),S=(0,o.default)({Accept:"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded"},y);n.fetch({url:x,method:"post",headers:S,query:v,body:d,requestInterceptor:u().requestInterceptor,responseInterceptor:u().responseInterceptor}).then(function(e){var t=JSON.parse(e.data),n=t&&(t.error||""),r=t&&(t.parseError||"");e.ok?n||r?l.newAuthErr({authId:g,level:"error",source:"auth",message:(0,i.default)(t)}):s.authorizeOauth2({auth:_,token:t}):l.newAuthErr({authId:g,level:"error",source:"auth",message:e.statusText})}).catch(function(e){var t=new Error(e).message;if(e.response&&e.response.data){var n=e.response.data;try{var r="string"==typeof n?JSON.parse(n):n;r.error&&(t+=", error: "+r.error),r.error_description&&(t+=", description: "+r.error_description)}catch(e){}}l.newAuthErr({authId:g,level:"error",source:"auth",message:t})})}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.parseYamlConfig=void 0;var r,o=n(207),i=(r=o)&&r.__esModule?r:{default:r};t.parseYamlConfig=function(e,t){try{return i.default.safeLoad(e)}catch(e){return t&&t.errActions.newThrownErr(new Error(e)),{}}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.loaded=t.TOGGLE_CONFIGS=t.UPDATE_CONFIGS=void 0;var r,o=n(22),i=(r=o)&&r.__esModule?r:{default:r};t.update=function(e,t){return{type:a,payload:(0,i.default)({},e,t)}},t.toggle=function(e){return{type:u,payload:e}};var a=t.UPDATE_CONFIGS="configs_update",u=t.TOGGLE_CONFIGS="configs_toggle";t.loaded=function(){return function(){}}},function(e,t,n){"use strict";function r(e,t,n,r,o){this.src=e,this.env=r,this.options=n,this.parser=t,this.tokens=o,this.pos=0,this.posMax=this.src.length,this.level=0,this.pending="",this.pendingLevel=0,this.cache=[],this.isInLabel=!1,this.linkLevel=0,this.linkContent="",this.labelUnmatchedScopes=0}r.prototype.pushPending=function(){this.tokens.push({type:"text",content:this.pending,level:this.pendingLevel}),this.pending=""},r.prototype.push=function(e){this.pending&&this.pushPending(),this.tokens.push(e),this.pendingLevel=this.level},r.prototype.cacheSet=function(e,t){for(var n=this.cache.length;n<=e;n++)this.cache.push(0);this.cache[e]=t},r.prototype.cacheGet=function(e){return es;)r(u,n=t[s++])&&(~i(l,n)||l.push(n));return l}},function(e,t,n){var r=n(21).document;e.exports=r&&r.documentElement},function(e,t,n){var r=n(52),o=n(72),i=n(161)("IE_PROTO"),a=Object.prototype;e.exports=Object.getPrototypeOf||function(e){return e=o(e),r(e,i)?e[i]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?a:null}},function(e,t,n){var r=n(33),o=r["__core-js_shared__"]||(r["__core-js_shared__"]={});e.exports=function(e){return o[e]||(o[e]={})}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t,n){"use strict";var r=n(245)(!0);n(246)(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,n=this._i;return n>=t.length?{value:void 0,done:!0}:(e=r(t,n),this._i+=e.length,{value:e,done:!1})})},function(e,t,n){var r=n(119),o=n(53);e.exports=function(e){return function(t,n){var i,a,u=String(o(t)),s=r(n),l=u.length;return s<0||s>=l?e?"":void 0:(i=u.charCodeAt(s))<55296||i>56319||s+1===l||(a=u.charCodeAt(s+1))<56320||a>57343?e?u.charAt(s):i:e?u.slice(s,s+2):a-56320+(i-55296<<10)+65536}}},function(e,t,n){"use strict";var r=n(247),o=n(29),i=n(73),a=n(58),u=n(102),s=n(462),l=n(170),c=n(468),f=n(17)("iterator"),p=!([].keys&&"next"in[].keys()),d=function(){return this};e.exports=function(e,t,n,h,v,m,y){s(n,t,h);var g,b,_,w=function(e){if(!p&&e in C)return C[e];switch(e){case"keys":case"values":return function(){return new n(this,e)}}return function(){return new n(this,e)}},E=t+" Iterator",x="values"==v,S=!1,C=e.prototype,k=C[f]||C["@@iterator"]||v&&C[v],A=k||w(v),O=v?x?w("entries"):A:void 0,P="Array"==t&&C.entries||k;if(P&&(_=c(P.call(new e)))!==Object.prototype&&_.next&&(l(_,E,!0),r||"function"==typeof _[f]||a(_,f,d)),x&&k&&"values"!==k.name&&(S=!0,A=function(){return k.call(this)}),r&&!y||!p&&!S&&C[f]||a(C,f,A),u[t]=A,u[E]=d,v)if(g={values:x?A:w("values"),keys:m?A:w("keys"),entries:O},y)for(b in g)b in C||i(C,b,g[b]);else o(o.P+o.F*(p||S),t,g);return g}},function(e,t){e.exports=!1},function(e,t,n){var r=n(465),o=n(250);e.exports=Object.keys||function(e){return r(e,o)}},function(e,t,n){var r=n(119),o=Math.max,i=Math.min;e.exports=function(e,t){return(e=r(e))<0?o(e+t,0):i(e,t)}},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t,n){var r=n(33).document;e.exports=r&&r.documentElement},function(e,t,n){var r=n(59),o=n(121),i=n(17)("species");e.exports=function(e,t){var n,a=r(e).constructor;return void 0===a||void 0==(n=r(a)[i])?t:o(n)}},function(e,t,n){var r,o,i,a=n(120),u=n(480),s=n(251),l=n(168),c=n(33),f=c.process,p=c.setImmediate,d=c.clearImmediate,h=c.MessageChannel,v=c.Dispatch,m=0,y={},g=function(){var e=+this;if(y.hasOwnProperty(e)){var t=y[e];delete y[e],t()}},b=function(e){g.call(e.data)};p&&d||(p=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return y[++m]=function(){u("function"==typeof e?e:Function(e),t)},r(m),m},d=function(e){delete y[e]},"process"==n(99)(f)?r=function(e){f.nextTick(a(g,e,1))}:v&&v.now?r=function(e){v.now(a(g,e,1))}:h?(i=(o=new h).port2,o.port1.onmessage=b,r=a(i.postMessage,i,1)):c.addEventListener&&"function"==typeof postMessage&&!c.importScripts?(r=function(e){c.postMessage(e+"","*")},c.addEventListener("message",b,!1)):r="onreadystatechange"in l("script")?function(e){s.appendChild(l("script")).onreadystatechange=function(){s.removeChild(this),g.call(e)}}:function(e){setTimeout(a(g,e,1),0)}),e.exports={set:p,clear:d}},function(e,t){e.exports=function(e){try{return{e:!1,v:e()}}catch(e){return{e:!0,v:e}}}},function(e,t,n){var r=n(59),o=n(74),i=n(171);e.exports=function(e,t){if(r(e),o(t)&&t.constructor===e)return t;var n=i.f(e);return(0,n.resolve)(t),n.promise}},function(e,t,n){var r=n(74),o=n(99),i=n(17)("match");e.exports=function(e){var t;return r(e)&&(void 0!==(t=e[i])?!!t:"RegExp"==o(e))}},function(e,t,n){var r=n(20),o=n(15),i=n(51);e.exports=function(e,t){var n=(o.Object||{})[e]||Object[e],a={};a[e]=t(n),r(r.S+r.F*i(function(){n(1)}),"Object",a)}},function(e,t,n){var r=n(93);e.exports=Array.isArray||function(e){return"Array"==r(e)}},function(e,t,n){var r=n(239),o=n(163).concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return r(e,o)}},function(e,t,n){var r=n(125),o=n(95),i=n(71),a=n(157),u=n(52),s=n(238),l=Object.getOwnPropertyDescriptor;t.f=n(44)?l:function(e,t){if(e=i(e),t=a(t,!0),s)try{return l(e,t)}catch(e){}if(u(e,t))return o(!r.f.call(e,t),e[t])}},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t,n){e.exports={default:n(532),__esModule:!0}},function(e,t,n){"use strict";var r=n(96),o=n(176),i=n(125),a=n(72),u=n(154),s=Object.assign;e.exports=!s||n(51)(function(){var e={},t={},n=Symbol(),r="abcdefghijklmnopqrst";return e[n]=7,r.split("").forEach(function(e){t[e]=e}),7!=s({},e)[n]||Object.keys(s({},t)).join("")!=r})?function(e,t){for(var n=a(e),s=arguments.length,l=1,c=o.f,f=i.f;s>l;)for(var p,d=u(arguments[l++]),h=c?r(d).concat(c(d)):r(d),v=h.length,m=0;v>m;)f.call(d,p=h[m++])&&(n[p]=d[p]);return n}:s},function(e,t,n){"use strict";var r=n(104),o=n(13),i=n(265),a=(n(266),n(126));n(8),n(536);function u(e,t,n){this.props=e,this.context=t,this.refs=a,this.updater=n||i}function s(e,t,n){this.props=e,this.context=t,this.refs=a,this.updater=n||i}function l(){}u.prototype.isReactComponent={},u.prototype.setState=function(e,t){"object"!=typeof e&&"function"!=typeof e&&null!=e&&r("85"),this.updater.enqueueSetState(this,e),t&&this.updater.enqueueCallback(this,t,"setState")},u.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this),e&&this.updater.enqueueCallback(this,e,"forceUpdate")},l.prototype=u.prototype,s.prototype=new l,s.prototype.constructor=s,o(s.prototype,u.prototype),s.prototype.isPureReactComponent=!0,e.exports={Component:u,PureComponent:s}},function(e,t,n){"use strict";n(10);var r={isMounted:function(e){return!1},enqueueCallback:function(e,t){},enqueueForceUpdate:function(e){},enqueueReplaceState:function(e,t){},enqueueSetState:function(e,t){}};e.exports=r},function(e,t,n){"use strict";var r=!1;e.exports=r},function(e,t,n){"use strict";var r="function"==typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103;e.exports=r},function(e,t,n){"use strict";var r=n(544);e.exports=function(e){return r(e,!1)}},function(e,t,n){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(271),o=n(561),i=n(562),a=n(563),u=n(275);n(274);n.d(t,"createStore",function(){return r.b}),n.d(t,"combineReducers",function(){return o.a}),n.d(t,"bindActionCreators",function(){return i.a}),n.d(t,"applyMiddleware",function(){return a.a}),n.d(t,"compose",function(){return u.a})},function(e,t,n){"use strict";n.d(t,"a",function(){return i}),t.b=function e(t,n,a){var u;"function"==typeof n&&void 0===a&&(a=n,n=void 0);if(void 0!==a){if("function"!=typeof a)throw new Error("Expected the enhancer to be a function.");return a(e)(t,n)}if("function"!=typeof t)throw new Error("Expected the reducer to be a function.");var s=t;var l=n;var c=[];var f=c;var p=!1;function d(){f===c&&(f=c.slice())}function h(){return l}function v(e){if("function"!=typeof e)throw new Error("Expected listener to be a function.");var t=!0;return d(),f.push(e),function(){if(t){t=!1,d();var n=f.indexOf(e);f.splice(n,1)}}}function m(e){if(!r.a(e))throw new Error("Actions must be plain objects. Use custom middleware for async actions.");if(void 0===e.type)throw new Error('Actions may not have an undefined "type" property. Have you misspelled a constant?');if(p)throw new Error("Reducers may not dispatch actions.");try{p=!0,l=s(l,e)}finally{p=!1}for(var t=c=f,n=0;n1&&void 0!==arguments[1]?arguments[1]:[],n={arrayBehaviour:(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).arrayBehaviour||"replace"},r=t.map(function(e){return e||{}}),i=e||{},l=0;l1?t-1:0),r=1;ro?0:o+t),(n=n>o?o:n)<0&&(n+=o),o=t>n?0:n-t>>>0,t>>>=0;for(var i=Array(o);++rp))return!1;var h=c.get(e);if(h&&c.get(t))return h==t;var v=-1,m=!0,y=n&u?new r:void 0;for(c.set(e,t),c.set(t,e);++v0?("string"==typeof t||a.objectMode||Object.getPrototypeOf(t)===l.prototype||(t=function(e){return l.from(e)}(t)),r?a.endEmitted?e.emit("error",new Error("stream.unshift() after end event")):w(e,a,t,!0):a.ended?e.emit("error",new Error("stream.push() after EOF")):(a.reading=!1,a.decoder&&!n?(t=a.decoder.write(t),a.objectMode||0!==t.length?w(e,a,t,!1):k(e,a)):w(e,a,t,!1))):r||(a.reading=!1));return function(e){return!e.ended&&(e.needReadable||e.lengtht.highWaterMark&&(t.highWaterMark=function(e){return e>=E?e=E:(e--,e|=e>>>1,e|=e>>>2,e|=e>>>4,e|=e>>>8,e|=e>>>16,e++),e}(e)),e<=t.length?e:t.ended?t.length:(t.needReadable=!0,0))}function S(e){var t=e._readableState;t.needReadable=!1,t.emittedReadable||(d("emitReadable",t.flowing),t.emittedReadable=!0,t.sync?o.nextTick(C,e):C(e))}function C(e){d("emit readable"),e.emit("readable"),T(e)}function k(e,t){t.readingMore||(t.readingMore=!0,o.nextTick(A,e,t))}function A(e,t){for(var n=t.length;!t.reading&&!t.flowing&&!t.ended&&t.length=t.length?(n=t.decoder?t.buffer.join(""):1===t.buffer.length?t.buffer.head.data:t.buffer.concat(t.length),t.buffer.clear()):n=function(e,t,n){var r;ei.length?i.length:e;if(a===i.length?o+=i:o+=i.slice(0,e),0===(e-=a)){a===i.length?(++r,n.next?t.head=n.next:t.head=t.tail=null):(t.head=n,n.data=i.slice(a));break}++r}return t.length-=r,o}(e,t):function(e,t){var n=l.allocUnsafe(e),r=t.head,o=1;r.data.copy(n),e-=r.data.length;for(;r=r.next;){var i=r.data,a=e>i.length?i.length:e;if(i.copy(n,n.length-e,0,a),0===(e-=a)){a===i.length?(++o,r.next?t.head=r.next:t.head=t.tail=null):(t.head=r,r.data=i.slice(a));break}++o}return t.length-=o,n}(e,t);return r}(e,t.buffer,t.decoder),n);var n}function I(e){var t=e._readableState;if(t.length>0)throw new Error('"endReadable()" called on non-empty stream');t.endEmitted||(t.ended=!0,o.nextTick(j,t,e))}function j(e,t){e.endEmitted||0!==e.length||(e.endEmitted=!0,t.readable=!1,t.emit("end"))}function N(e,t){for(var n=0,r=e.length;n=t.highWaterMark||t.ended))return d("read: emitReadable",t.length,t.ended),0===t.length&&t.ended?I(this):S(this),null;if(0===(e=x(e,t))&&t.ended)return 0===t.length&&I(this),null;var r,o=t.needReadable;return d("need readable",o),(0===t.length||t.length-e0?M(e,t):null)?(t.needReadable=!0,e=0):t.length-=e,0===t.length&&(t.ended||(t.needReadable=!0),n!==e&&t.ended&&I(this)),null!==r&&this.emit("data",r),r},b.prototype._read=function(e){this.emit("error",new Error("_read() is not implemented"))},b.prototype.pipe=function(e,t){var n=this,i=this._readableState;switch(i.pipesCount){case 0:i.pipes=e;break;case 1:i.pipes=[i.pipes,e];break;default:i.pipes.push(e)}i.pipesCount+=1,d("pipe count=%d opts=%j",i.pipesCount,t);var s=(!t||!1!==t.end)&&e!==r.stdout&&e!==r.stderr?c:b;function l(t,r){d("onunpipe"),t===n&&r&&!1===r.hasUnpiped&&(r.hasUnpiped=!0,d("cleanup"),e.removeListener("close",y),e.removeListener("finish",g),e.removeListener("drain",f),e.removeListener("error",m),e.removeListener("unpipe",l),n.removeListener("end",c),n.removeListener("end",b),n.removeListener("data",v),p=!0,!i.awaitDrain||e._writableState&&!e._writableState.needDrain||f())}function c(){d("onend"),e.end()}i.endEmitted?o.nextTick(s):n.once("end",s),e.on("unpipe",l);var f=function(e){return function(){var t=e._readableState;d("pipeOnDrain",t.awaitDrain),t.awaitDrain&&t.awaitDrain--,0===t.awaitDrain&&u(e,"data")&&(t.flowing=!0,T(e))}}(n);e.on("drain",f);var p=!1;var h=!1;function v(t){d("ondata"),h=!1,!1!==e.write(t)||h||((1===i.pipesCount&&i.pipes===e||i.pipesCount>1&&-1!==N(i.pipes,e))&&!p&&(d("false write response, pause",n._readableState.awaitDrain),n._readableState.awaitDrain++,h=!0),n.pause())}function m(t){d("onerror",t),b(),e.removeListener("error",m),0===u(e,"error")&&e.emit("error",t)}function y(){e.removeListener("finish",g),b()}function g(){d("onfinish"),e.removeListener("close",y),b()}function b(){d("unpipe"),n.unpipe(e)}return n.on("data",v),function(e,t,n){if("function"==typeof e.prependListener)return e.prependListener(t,n);e._events&&e._events[t]?a(e._events[t])?e._events[t].unshift(n):e._events[t]=[n,e._events[t]]:e.on(t,n)}(e,"error",m),e.once("close",y),e.once("finish",g),e.emit("pipe",n),i.flowing||(d("pipe resume"),n.resume()),e},b.prototype.unpipe=function(e){var t=this._readableState,n={hasUnpiped:!1};if(0===t.pipesCount)return this;if(1===t.pipesCount)return e&&e!==t.pipes?this:(e||(e=t.pipes),t.pipes=null,t.pipesCount=0,t.flowing=!1,e&&e.emit("unpipe",this,n),this);if(!e){var r=t.pipes,o=t.pipesCount;t.pipes=null,t.pipesCount=0,t.flowing=!1;for(var i=0;i=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n(663),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(t,n(31))},function(e,t,n){"use strict";var r=n(141).Buffer,o=r.isEncoding||function(e){switch((e=""+e)&&e.toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":case"raw":return!0;default:return!1}};function i(e){var t;switch(this.encoding=function(e){var t=function(e){if(!e)return"utf8";for(var t;;)switch(e){case"utf8":case"utf-8":return"utf8";case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return"utf16le";case"latin1":case"binary":return"latin1";case"base64":case"ascii":case"hex":return e;default:if(t)return;e=(""+e).toLowerCase(),t=!0}}(e);if("string"!=typeof t&&(r.isEncoding===o||!o(e)))throw new Error("Unknown encoding: "+e);return t||e}(e),this.encoding){case"utf16le":this.text=s,this.end=l,t=4;break;case"utf8":this.fillLast=u,t=4;break;case"base64":this.text=c,this.end=f,t=3;break;default:return this.write=p,void(this.end=d)}this.lastNeed=0,this.lastTotal=0,this.lastChar=r.allocUnsafe(t)}function a(e){return e<=127?0:e>>5==6?2:e>>4==14?3:e>>3==30?4:e>>6==2?-1:-2}function u(e){var t=this.lastTotal-this.lastNeed,n=function(e,t,n){if(128!=(192&t[0]))return e.lastNeed=0,"�";if(e.lastNeed>1&&t.length>1){if(128!=(192&t[1]))return e.lastNeed=1,"�";if(e.lastNeed>2&&t.length>2&&128!=(192&t[2]))return e.lastNeed=2,"�"}}(this,e);return void 0!==n?n:this.lastNeed<=e.length?(e.copy(this.lastChar,t,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal)):(e.copy(this.lastChar,t,0,e.length),void(this.lastNeed-=e.length))}function s(e,t){if((e.length-t)%2==0){var n=e.toString("utf16le",t);if(n){var r=n.charCodeAt(n.length-1);if(r>=55296&&r<=56319)return this.lastNeed=2,this.lastTotal=4,this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1],n.slice(0,-1)}return n}return this.lastNeed=1,this.lastTotal=2,this.lastChar[0]=e[e.length-1],e.toString("utf16le",t,e.length-1)}function l(e){var t=e&&e.length?this.write(e):"";if(this.lastNeed){var n=this.lastTotal-this.lastNeed;return t+this.lastChar.toString("utf16le",0,n)}return t}function c(e,t){var n=(e.length-t)%3;return 0===n?e.toString("base64",t):(this.lastNeed=3-n,this.lastTotal=3,1===n?this.lastChar[0]=e[e.length-1]:(this.lastChar[0]=e[e.length-2],this.lastChar[1]=e[e.length-1]),e.toString("base64",t,e.length-n))}function f(e){var t=e&&e.length?this.write(e):"";return this.lastNeed?t+this.lastChar.toString("base64",0,3-this.lastNeed):t}function p(e){return e.toString(this.encoding)}function d(e){return e&&e.length?this.write(e):""}t.StringDecoder=i,i.prototype.write=function(e){if(0===e.length)return"";var t,n;if(this.lastNeed){if(void 0===(t=this.fillLast(e)))return"";n=this.lastNeed,this.lastNeed=0}else n=0;return n=0)return o>0&&(e.lastNeed=o-1),o;if(--r=0)return o>0&&(e.lastNeed=o-2),o;if(--r=0)return o>0&&(2===o?o=0:e.lastNeed=o-3),o;return 0}(this,e,t);if(!this.lastNeed)return e.toString("utf8",t);this.lastTotal=n;var r=e.length-(n-this.lastNeed);return e.copy(this.lastChar,0,r),e.toString("utf8",t,r)},i.prototype.fillLast=function(e){if(this.lastNeed<=e.length)return e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,this.lastNeed),this.lastChar.toString(this.encoding,0,this.lastTotal);e.copy(this.lastChar,this.lastTotal-this.lastNeed,0,e.length),this.lastNeed-=e.length}},function(e,t,n){"use strict";e.exports=i;var r=n(65),o=n(106);function i(e){if(!(this instanceof i))return new i(e);r.call(this,e),this._transformState={afterTransform:function(e,t){var n=this._transformState;n.transforming=!1;var r=n.writecb;if(!r)return this.emit("error",new Error("write callback called multiple times"));n.writechunk=null,n.writecb=null,null!=t&&this.push(t),r(e);var o=this._readableState;o.reading=!1,(o.needReadable||o.length=0?n&&o?o-1:o:1:!1!==e&&r(e)}},function(e,t,n){"use strict";e.exports=n(679)()?Object.assign:n(680)},function(e,t,n){"use strict";var r,o,i,a,u,s=n(67),l=function(e,t){return t};try{Object.defineProperty(l,"length",{configurable:!0,writable:!1,enumerable:!1,value:1})}catch(e){}1===l.length?(r={configurable:!0,writable:!1,enumerable:!1},o=Object.defineProperty,e.exports=function(e,t){return t=s(t),e.length===t?e:(r.value=t,o(e,"length",r))}):(a=n(317),u=[],i=function(e){var t,n=0;if(u[e])return u[e];for(t=[];e--;)t.push("a"+(++n).toString(36));return new Function("fn","return function ("+t.join(", ")+") { return fn.apply(this, arguments); };")},e.exports=function(e,t){var n;if(t=s(t),e.length===t)return e;n=i(t)(e);try{a(n,e)}catch(e){}return n})},function(e,t,n){"use strict";var r=n(82),o=Object.defineProperty,i=Object.getOwnPropertyDescriptor,a=Object.getOwnPropertyNames,u=Object.getOwnPropertySymbols;e.exports=function(e,t){var n,s=Object(r(t));if(e=Object(r(e)),a(s).forEach(function(r){try{o(e,r,i(t,r))}catch(e){n=e}}),"function"==typeof u&&u(s).forEach(function(r){try{o(e,r,i(t,r))}catch(e){n=e}}),void 0!==n)throw n;return e}},function(e,t,n){"use strict";var r=n(56),o=n(142),i=Function.prototype.call;e.exports=function(e,t){var n={},a=arguments[2];return r(t),o(e,function(e,r,o,u){n[r]=i.call(t,a,e,r,o,u)}),n}},function(e,t){e.exports=function(e){return!!e&&("object"==typeof e||"function"==typeof e)&&"function"==typeof e.then}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return{statePlugins:{err:{reducers:(0,i.default)(e),actions:a,selectors:u}}}};var r,o=n(321),i=(r=o)&&r.__esModule?r:{default:r},a=s(n(127)),u=s(n(326));function s(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=s(n(22)),o=s(n(23));t.default=function(e){var t;return t={},(0,r.default)(t,i.NEW_THROWN_ERR,function(t,n){var r=n.payload,i=(0,o.default)(l,r,{type:"thrown"});return t.update("errors",function(e){return(e||(0,a.List)()).push((0,a.fromJS)(i))}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.NEW_THROWN_ERR_BATCH,function(t,n){var r=n.payload;return r=r.map(function(e){return(0,a.fromJS)((0,o.default)(l,e,{type:"thrown"}))}),t.update("errors",function(e){return(e||(0,a.List)()).concat((0,a.fromJS)(r))}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.NEW_SPEC_ERR,function(t,n){var r=n.payload,o=(0,a.fromJS)(r);return o=o.set("type","spec"),t.update("errors",function(e){return(e||(0,a.List)()).push((0,a.fromJS)(o)).sortBy(function(e){return e.get("line")})}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.NEW_SPEC_ERR_BATCH,function(t,n){var r=n.payload;return r=r.map(function(e){return(0,a.fromJS)((0,o.default)(l,e,{type:"spec"}))}),t.update("errors",function(e){return(e||(0,a.List)()).concat((0,a.fromJS)(r))}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.NEW_AUTH_ERR,function(t,n){var r=n.payload,i=(0,a.fromJS)((0,o.default)({},r));return i=i.set("type","auth"),t.update("errors",function(e){return(e||(0,a.List)()).push((0,a.fromJS)(i))}).update("errors",function(t){return(0,u.default)(t,e.getSystem())})}),(0,r.default)(t,i.CLEAR,function(e,t){var n=t.payload;if(!n||!e.get("errors"))return e;var r=e.get("errors").filter(function(e){return e.keySeq().every(function(t){var r=e.get(t),o=n[t];return!o||r!==o})});return e.merge({errors:r})}),(0,r.default)(t,i.CLEAR_BY,function(e,t){var n=t.payload;if(!n||"function"!=typeof n)return e;var r=e.get("errors").filter(function(e){return n(e)});return e.merge({errors:r})}),t};var i=n(127),a=n(7),u=s(n(322));function s(e){return e&&e.__esModule?e:{default:e}}var l={line:0,level:"error",message:"Unknown error"}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){var n={jsSpec:t.specSelectors.specJson().toJS()};return(0,i.default)(u,function(e,t){try{var r=t.transform(e,n);return r.filter(function(e){return!!e})}catch(t){return console.error("Transformer error:",t),e}},e).filter(function(e){return!!e}).map(function(e){return!e.get("line")&&e.get("path"),e})};var r,o=n(727),i=(r=o)&&r.__esModule?r:{default:r};function a(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}var u=[a(n(323)),a(n(324)),a(n(325))]},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transform=function(e){return e.map(function(e){var t=e.get("message").indexOf("is not of a type(s)");if(t>-1){var n=e.get("message").slice(t+"is not of a type(s)".length).split(",");return e.set("message",e.get("message").slice(0,t)+function(e){return e.reduce(function(e,t,n,r){return n===r.length-1&&r.length>1?e+"or "+t:r[n+1]&&r.length>2?e+t+", ":r[n+1]?e+t+" ":e+t},"should be a")}(n))}return e})}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transform=function(e,t){t.jsSpec;return e};var r,o=n(138);(r=o)&&r.__esModule,n(7)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.transform=function(e){return e.map(function(e){return e.set("message",(t=e.get("message"),n="instance.",t.replace(new RegExp(n,"g"),"")));var t,n})}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.lastError=t.allErrors=void 0;var r=n(7),o=n(57),i=t.allErrors=(0,o.createSelector)(function(e){return e},function(e){return e.get("errors",(0,r.List)())});t.lastError=(0,o.createSelector)(i,function(e){return e.last()})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return{statePlugins:{layout:{reducers:i.default,actions:a,selectors:u}}}};var r,o=n(328),i=(r=o)&&r.__esModule?r:{default:r},a=s(n(200)),u=s(n(329));function s(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r,o,i=n(22),a=(r=i)&&r.__esModule?r:{default:r},u=n(7),s=n(200);t.default=(o={},(0,a.default)(o,s.UPDATE_LAYOUT,function(e,t){return e.set("layout",t.payload)}),(0,a.default)(o,s.UPDATE_FILTER,function(e,t){return e.set("filter",t.payload)}),(0,a.default)(o,s.SHOW,function(e,t){var n=t.payload.shown,r=(0,u.fromJS)(t.payload.thing);return e.update("shown",(0,u.fromJS)({}),function(e){return e.set(r,n)})}),(0,a.default)(o,s.UPDATE_MODE,function(e,t){var n=t.payload.thing,r=t.payload.mode;return e.setIn(["modes"].concat(n),(r||"")+"")}),o)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.showSummary=t.whatMode=t.isShown=t.currentFilter=t.current=void 0;var r,o=n(83),i=(r=o)&&r.__esModule?r:{default:r},a=n(57),u=n(9),s=n(7);t.current=function(e){return e.get("layout")},t.currentFilter=function(e){return e.get("filter")};var l=t.isShown=function(e,t,n){return t=(0,u.normalizeArray)(t),e.get("shown",(0,s.fromJS)({})).get((0,s.fromJS)(t),n)};t.whatMode=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";return t=(0,u.normalizeArray)(t),e.getIn(["modes"].concat((0,i.default)(t)),n)},t.showSummary=(0,a.createSelector)(function(e){return e},function(e){return!l(e,"editor")})},function(e,t,n){var r=n(36);e.exports=function(e,t,n,o){try{return o?t(r(n)[0],n[1]):t(n)}catch(t){var i=e.return;throw void 0!==i&&r(i.call(e)),t}}},function(e,t,n){var r=n(70),o=n(19)("iterator"),i=Array.prototype;e.exports=function(e){return void 0!==e&&(r.Array===e||i[o]===e)}},function(e,t,n){var r=n(19)("iterator"),o=!1;try{var i=[7][r]();i.return=function(){o=!0},Array.from(i,function(){throw 2})}catch(e){}e.exports=function(e,t){if(!t&&!o)return!1;var n=!1;try{var i=[7],a=i[r]();a.next=function(){return{done:n=!0}},i[r]=function(){return a},e(i)}catch(e){}return n}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return{statePlugins:{spec:{wrapActions:s,reducers:i.default,actions:a,selectors:u}}}};var r,o=n(334),i=(r=o)&&r.__esModule?r:{default:r},a=l(n(202)),u=l(n(201)),s=l(n(347));function l(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r,o=p(n(22)),i=p(n(23)),a=p(n(83)),u=n(7),s=n(9),l=p(n(32)),c=n(201),f=n(202);function p(e){return e&&e.__esModule?e:{default:e}}t.default=(r={},(0,o.default)(r,f.UPDATE_SPEC,function(e,t){return"string"==typeof t.payload?e.set("spec",t.payload):e}),(0,o.default)(r,f.UPDATE_URL,function(e,t){return e.set("url",t.payload+"")}),(0,o.default)(r,f.UPDATE_JSON,function(e,t){return e.set("json",(0,s.fromJSOrdered)(t.payload))}),(0,o.default)(r,f.UPDATE_RESOLVED,function(e,t){return e.setIn(["resolved"],(0,s.fromJSOrdered)(t.payload))}),(0,o.default)(r,f.UPDATE_RESOLVED_SUBTREE,function(e,t){var n=t.payload,r=n.value,o=n.path;return e.setIn(["resolvedSubtrees"].concat((0,a.default)(o)),(0,s.fromJSOrdered)(r))}),(0,o.default)(r,f.UPDATE_PARAM,function(e,t){var n=t.payload,r=n.path,o=n.paramName,i=n.paramIn,u=n.param,s=n.value,l=n.isXml,c=void 0;c=u&&u.hashCode&&!i&&!o?u.get("name")+"."+u.get("in")+".hash-"+u.hashCode():o+"."+i;var f=l?"value_xml":"value";return e.setIn(["meta","paths"].concat((0,a.default)(r),["parameters",c,f]),s)}),(0,o.default)(r,f.UPDATE_EMPTY_PARAM_INCLUSION,function(e,t){var n=t.payload,r=n.pathMethod,o=n.paramName,i=n.paramIn,u=n.includeEmptyValue;if(!o||!i)return console.warn("Warning: UPDATE_EMPTY_PARAM_INCLUSION could not generate a paramKey."),e;var s=o+"."+i;return e.setIn(["meta","paths"].concat((0,a.default)(r),["parameter_inclusions",s]),u)}),(0,o.default)(r,f.VALIDATE_PARAMS,function(e,t){var n=t.payload,r=n.pathMethod,o=n.isOAS3,i=e.getIn(["meta","paths"].concat((0,a.default)(r)),(0,u.fromJS)({})),l=/xml/i.test(i.get("consumes_value")),f=c.operationWithMeta.apply(void 0,[e].concat((0,a.default)(r)));return e.updateIn(["meta","paths"].concat((0,a.default)(r),["parameters"]),(0,u.fromJS)({}),function(e){return f.get("parameters",(0,u.List)()).reduce(function(e,t){var n=(0,s.validateParam)(t,l,o);return e.setIn([t.get("name")+"."+t.get("in"),"errors"],(0,u.fromJS)(n))},e)})}),(0,o.default)(r,f.CLEAR_VALIDATE_PARAMS,function(e,t){var n=t.payload.pathMethod;return e.updateIn(["meta","paths"].concat((0,a.default)(n),["parameters"]),(0,u.fromJS)([]),function(e){return e.map(function(e){return e.set("errors",(0,u.fromJS)([]))})})}),(0,o.default)(r,f.SET_RESPONSE,function(e,t){var n=t.payload,r=n.res,o=n.path,a=n.method,u=void 0;(u=r.error?(0,i.default)({error:!0,name:r.err.name,message:r.err.message,statusCode:r.err.statusCode},r.err.response):r).headers=u.headers||{};var c=e.setIn(["responses",o,a],(0,s.fromJSOrdered)(u));return l.default.Blob&&r.data instanceof l.default.Blob&&(c=c.setIn(["responses",o,a,"text"],r.data)),c}),(0,o.default)(r,f.SET_REQUEST,function(e,t){var n=t.payload,r=n.req,o=n.path,i=n.method;return e.setIn(["requests",o,i],(0,s.fromJSOrdered)(r))}),(0,o.default)(r,f.SET_MUTATED_REQUEST,function(e,t){var n=t.payload,r=n.req,o=n.path,i=n.method;return e.setIn(["mutatedRequests",o,i],(0,s.fromJSOrdered)(r))}),(0,o.default)(r,f.UPDATE_OPERATION_META_VALUE,function(e,t){var n=t.payload,r=n.path,o=n.value,i=n.key,s=["paths"].concat((0,a.default)(r)),l=["meta","paths"].concat((0,a.default)(r));return e.getIn(["json"].concat((0,a.default)(s)))||e.getIn(["resolved"].concat((0,a.default)(s)))||e.getIn(["resolvedSubtrees"].concat((0,a.default)(s)))?e.setIn([].concat((0,a.default)(l),[i]),(0,u.fromJS)(o)):e}),(0,o.default)(r,f.CLEAR_RESPONSE,function(e,t){var n=t.payload,r=n.path,o=n.method;return e.deleteIn(["responses",r,o])}),(0,o.default)(r,f.CLEAR_REQUEST,function(e,t){var n=t.payload,r=n.path,o=n.method;return e.deleteIn(["requests",r,o])}),(0,o.default)(r,f.SET_SCHEME,function(e,t){var n=t.payload,r=n.scheme,o=n.path,i=n.method;return o&&i?e.setIn(["scheme",o,i],r):o||i?void 0:e.setIn(["scheme","_defaultScheme"],r)}),r)},function(e,t,n){var r=n(36),o=n(94),i=n(19)("species");e.exports=function(e,t){var n,a=r(e).constructor;return void 0===a||void 0==(n=r(a)[i])?t:o(n)}},function(e,t,n){var r,o,i,a=n(49),u=n(735),s=n(240),l=n(156),c=n(21),f=c.process,p=c.setImmediate,d=c.clearImmediate,h=c.MessageChannel,v=c.Dispatch,m=0,y={},g=function(){var e=+this;if(y.hasOwnProperty(e)){var t=y[e];delete y[e],t()}},b=function(e){g.call(e.data)};p&&d||(p=function(e){for(var t=[],n=1;arguments.length>n;)t.push(arguments[n++]);return y[++m]=function(){u("function"==typeof e?e:Function(e),t)},r(m),m},d=function(e){delete y[e]},"process"==n(93)(f)?r=function(e){f.nextTick(a(g,e,1))}:v&&v.now?r=function(e){v.now(a(g,e,1))}:h?(i=(o=new h).port2,o.port1.onmessage=b,r=a(i.postMessage,i,1)):c.addEventListener&&"function"==typeof postMessage&&!c.importScripts?(r=function(e){c.postMessage(e+"","*")},c.addEventListener("message",b,!1)):r="onreadystatechange"in l("script")?function(e){s.appendChild(l("script")).onreadystatechange=function(){s.removeChild(this),g.call(e)}}:function(e){setTimeout(a(g,e,1),0)}),e.exports={set:p,clear:d}},function(e,t){e.exports=function(e){try{return{e:!1,v:e()}}catch(e){return{e:!0,v:e}}}},function(e,t,n){var r=n(36),o=n(28),i=n(205);e.exports=function(e,t){if(r(e),o(t)&&t.constructor===e)return t;var n=i.f(e);return(0,n.resolve)(t),n.promise}},function(e,t,n){e.exports=n(740)},function(e,t,n){"use strict";t.__esModule=!0;var r,o=n(203),i=(r=o)&&r.__esModule?r:{default:r};t.default=function(e){return function(){var t=e.apply(this,arguments);return new i.default(function(e,n){return function r(o,a){try{var u=t[o](a),s=u.value}catch(e){return void n(e)}if(!u.done)return i.default.resolve(s).then(function(e){r("next",e)},function(e){r("throw",e)});e(s)}("next")})}}},function(e,t,n){"use strict";var r=n(86);e.exports=new r({include:[n(342)]})},function(e,t,n){"use strict";var r=n(86);e.exports=new r({include:[n(208)],implicit:[n(748),n(749),n(750),n(751)]})},function(e,t,n){var r=n(62),o=n(24),i=n(47),a="[object String]";e.exports=function(e){return"string"==typeof e||!o(e)&&i(e)&&r(e)==a}},function(e,t,n){var r=n(146),o=n(79),i=n(135),a=n(38),u=n(80);e.exports=function(e,t,n,s){if(!a(e))return e;for(var l=-1,c=(t=o(t,e)).length,f=c-1,p=e;null!=p&&++l.":"function"==typeof t?" Instead of passing a class like Foo, pass React.createElement(Foo) or .":null!=t&&void 0!==t.props?" This may be caused by unintentionally loading two independent copies of React.":"");var i,u=a.createElement(D,{child:t});if(e){var s=p.get(e);i=s._processChildContext(s._context)}else i=y;var l=N(n);if(l){var c=l._currentElement.props.child;if(_(c,t)){var f=l._renderedComponent.getPublicInstance(),d=o&&function(){o.call(f)};return L._updateRootComponent(l,u,i,n,d),f}L.unmountComponentAtNode(n)}var h=A(n),m=h&&!!O(h),g=I(n),b=m&&!l&&!g,w=L._renderNewRootComponent(u,n,b,i)._renderedComponent.getPublicInstance();return o&&o.call(w),w},render:function(e,t,n){return L._renderSubtreeIntoContainer(null,e,t,n)},unmountComponentAtNode:function(e){j(e)||r("40");var t=N(e);if(!t){I(e),1===e.nodeType&&e.hasAttribute(E);return!1}return delete k[t._instance.rootID],m.batchedUpdates(M,t,e,!1),!0},_mountImageIntoNode:function(e,t,n,i,a){if(j(t)||r("41"),i){var u=A(t);if(d.canReuseMarkup(e,u))return void s.precacheNode(n,u);var l=u.getAttribute(d.CHECKSUM_ATTR_NAME);u.removeAttribute(d.CHECKSUM_ATTR_NAME);var c=u.outerHTML;u.setAttribute(d.CHECKSUM_ATTR_NAME,l);var f=e,p=function(e,t){for(var n=Math.min(e.length,t.length),r=0;r1?r-1:0),a=1;a=o&&(t=console)[e].apply(t,i)}return i.warn=i.bind(null,"warn"),i.error=i.bind(null,"error"),i.info=i.bind(null,"info"),i.debug=i.bind(null,"debug"),{rootInjects:{log:i}}}},function(e,t,n){"use strict";var r,o=n(388),i=(r=o)&&r.__esModule?r:{default:r};e.exports=function(e){var t=e.configs;return{fn:{fetch:i.default.makeHttp(t.preFetch,t.postFetch),buildRequest:i.default.buildRequest,execute:i.default.execute,resolve:i.default.resolve,resolveSubtree:i.default.resolveSubtree,serializeRes:i.default.serializeRes,opId:i.default.helpers.opId}}}},function(e,t,n){e.exports=function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=23)}([function(e,t){e.exports=n(42)},function(e,t){e.exports=n(45)},function(e,t){e.exports=n(23)},function(e,t){e.exports=n(25)},function(e,t){e.exports=n(339)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=(arguments.length>3&&void 0!==arguments[3]?arguments[3]:{}).v2OperationIdCompatibilityMode;return e&&"object"===(void 0===e?"undefined":(0,c.default)(e))?(e.operationId||"").replace(/\s/g,"").length?h(e.operationId):i(t,n,{v2OperationIdCompatibilityMode:r}):null}function i(e,t){if((arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).v2OperationIdCompatibilityMode){var n=(t.toLowerCase()+"_"+e).replace(/[\s!@#$%^&*()_+=[{\]};:<>|.\/?,\\'""-]/g,"_");return(n=n||e.substring(1)+"_"+t).replace(/((_){2,})/g,"_").replace(/^(_)*/g,"").replace(/([_])*$/g,"")}return""+d(t)+h(e)}function a(e,t){return d(t)+"-"+e}function u(e,t){return s(e,t,!0)||null}function s(e,t,n){if(!e||"object"!==(void 0===e?"undefined":(0,c.default)(e))||!e.paths||"object"!==(0,c.default)(e.paths))return null;var r=e.paths;for(var o in r)for(var i in r[o])if("PARAMETERS"!==i.toUpperCase()){var a=r[o][i];if(a&&"object"===(void 0===a?"undefined":(0,c.default)(a))){var u={spec:e,pathName:o,method:i.toUpperCase(),operation:a},s=t(u);if(n&&s)return u}}}Object.defineProperty(t,"__esModule",{value:!0});var l=r(n(18)),c=r(n(1));t.isOAS3=function(e){var t=e.openapi;return!!t&&(0,p.default)(t,"3")},t.isSwagger2=function(e){var t=e.swagger;return!!t&&(0,p.default)(t,"2")},t.opId=o,t.idFromPathMethod=i,t.legacyIdFromPathMethod=a,t.getOperationRaw=function(e,t){return e&&e.paths?u(e,function(e){var n=e.pathName,r=e.method,i=e.operation;if(!i||"object"!==(void 0===i?"undefined":(0,c.default)(i)))return!1;var u=i.operationId;return[o(i,n,r),a(n,r),u].some(function(e){return e&&e===t})}):null},t.findOperation=u,t.eachOperation=s,t.normalizeSwagger=function(e){var t=e.spec,n=t.paths,r={};if(!n||t.$$normalized)return e;for(var i in n){var a=n[i];if((0,f.default)(a)){var u=a.parameters;for(var s in a)!function(e){var n=a[e];if(!(0,f.default)(n))return"continue";var s=o(n,i,e);if(s){r[s]?r[s].push(n):r[s]=[n];var c=r[s];if(c.length>1)c.forEach(function(e,t){e.__originalOperationId=e.__originalOperationId||e.operationId,e.operationId=""+s+(t+1)});else if(void 0!==n.operationId){var p=c[0];p.__originalOperationId=p.__originalOperationId||n.operationId,p.operationId=s}}if("parameters"!==e){var d=[],h={};for(var v in t)"produces"!==v&&"consumes"!==v&&"security"!==v||(h[v]=t[v],d.push(h));if(u&&(h.parameters=u,d.push(h)),d.length){var m=!0,y=!1,g=void 0;try{for(var b,_=(0,l.default)(d);!(m=(b=_.next()).done);m=!0){var w=b.value;for(var E in w)if(n[E]){if("parameters"===E){var x=!0,S=!1,C=void 0;try{for(var k,A=(0,l.default)(w[E]);!(x=(k=A.next()).done);x=!0)!function(){var e=k.value;n[E].some(function(t){return t.name&&t.name===e.name||t.$ref&&t.$ref===e.$ref||t.$$ref&&t.$$ref===e.$$ref||t===e})||n[E].push(e)}()}catch(e){S=!0,C=e}finally{try{!x&&A.return&&A.return()}finally{if(S)throw C}}}}else n[E]=w[E]}}catch(e){y=!0,g=e}finally{try{!m&&_.return&&_.return()}finally{if(y)throw g}}}}}(s)}}return t.$$normalized=!0,e};var f=r(n(47)),p=r(n(14)),d=function(e){return String.prototype.toLowerCase.call(e)},h=function(e){return e.replace(/[^\w]/gi,"_")}},function(e,t){e.exports=n(893)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).loadSpec,r=void 0!==n&&n,o={ok:e.ok,url:e.url||t,status:e.status,statusText:e.statusText,headers:i(e.headers)},a=o.headers["content-type"],u=r||_(a);return(u?e.text:e.blob||e.buffer).call(e).then(function(e){if(o.text=e,o.data=e,u)try{var t=function(e,t){return"application/json"===t?JSON.parse(e):y.default.safeLoad(e)}(e,a);o.body=t,o.obj=t}catch(e){o.parseError=e}return o})}function i(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t={};return"function"==typeof e.forEach?(e.forEach(function(e,n){void 0!==t[n]?(t[n]=Array.isArray(t[n])?t[n]:[t[n]],t[n].push(e)):t[n]=e}),t):t}function a(e,t){return t||"undefined"==typeof navigator||(t=navigator),t&&"ReactNative"===t.product?!(!e||"object"!==(void 0===e?"undefined":(0,h.default)(e))||"string"!=typeof e.uri):"undefined"!=typeof File?e instanceof File:null!==e&&"object"===(void 0===e?"undefined":(0,h.default)(e))&&"function"==typeof e.pipe}function u(e,t){var n=e.collectionFormat,r=e.allowEmptyValue,o="object"===(void 0===e?"undefined":(0,h.default)(e))?e.value:e;if(void 0===o&&r)return"";if(a(o)||"boolean"==typeof o)return o;var i=encodeURIComponent;return t&&(i=(0,g.default)(o)?function(e){return e}:function(e){return(0,p.default)(e)}),"object"!==(void 0===o?"undefined":(0,h.default)(o))||Array.isArray(o)?Array.isArray(o)?Array.isArray(o)&&!n?o.map(i).join(","):"multi"===n?o.map(i):o.map(i).join({csv:",",ssv:"%20",tsv:"%09",pipes:"|"}[n]):i(o):""}function s(e){var t=(0,f.default)(e).reduce(function(t,n){var r=e[n],o=!!r.skipEncoding,i=o?n:encodeURIComponent(n),a=function(e){return e&&"object"===(void 0===e?"undefined":(0,h.default)(e))}(r)&&!Array.isArray(r);return t[i]=u(a?r:{value:r},o),t},{});return m.default.stringify(t,{encode:!1,indices:!1})||""}function l(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.url,r=void 0===t?"":t,o=e.query,i=e.form;if(i){var l=(0,f.default)(i).some(function(e){return a(i[e].value)}),p=e.headers["content-type"]||e.headers["Content-Type"];if(l||/multipart\/form-data/i.test(p)){var d=n(30);e.body=new d,(0,f.default)(i).forEach(function(t){e.body.append(t,u(i[t],!0))})}else e.body=s(i);delete e.form}if(o){var h=r.split("?"),v=(0,c.default)(h,2),y=v[0],g=v[1],b="";if(g){var _=m.default.parse(g);(0,f.default)(o).forEach(function(e){return delete _[e]}),b=m.default.stringify(_,{encode:!0})}var w=function(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:{};return d.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if("object"===(void 0===t?"undefined":(0,h.default)(t))&&(t=(a=t).url),a.headers=a.headers||{},b.mergeInQueryOrForm(a),!a.requestInterceptor){e.next=10;break}return e.next=6,a.requestInterceptor(a);case 6:if(e.t0=e.sent,e.t0){e.next=9;break}e.t0=a;case 9:a=e.t0;case 10:return n=a.headers["content-type"]||a.headers["Content-Type"],/multipart\/form-data/i.test(n)&&(delete a.headers["content-type"],delete a.headers["Content-Type"]),r=void 0,e.prev=13,e.next=16,(a.userFetch||fetch)(a.url,a);case 16:return r=e.sent,e.next=19,b.serializeRes(r,t,a);case 19:if(r=e.sent,!a.responseInterceptor){e.next=27;break}return e.next=23,a.responseInterceptor(r);case 23:if(e.t1=e.sent,e.t1){e.next=26;break}e.t1=r;case 26:r=e.t1;case 27:e.next=37;break;case 29:if(e.prev=29,e.t2=e.catch(13),r){e.next=33;break}throw e.t2;case 33:throw(o=new Error(r.statusText)).statusCode=o.status=r.status,o.responseError=e.t2,o;case 37:if(r.ok){e.next=42;break}throw(i=new Error(r.statusText)).statusCode=i.status=r.status,i.response=r,i;case 42:return e.abrupt("return",r);case 43:case"end":return e.stop()}},e,this,[[13,29]])}));return function(t){return e.apply(this,arguments)}}();var _=t.shouldDownloadAsText=function(){return/(json|xml|yaml|text)\b/.test(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"")}},function(e,t){e.exports=n(41)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){return Array.isArray(e)?e.length<1?"":"/"+e.map(function(e){return(e+"").replace(/~/g,"~0").replace(/\//g,"~1")}).join("/"):e}function i(e,t,n){return{op:"replace",path:e,value:t,meta:n}}function a(e,t,n){return f(c(e.filter(m).map(function(e){return t(e.value,n,e.path)})||[]))}function u(e,t,n){return n=n||[],Array.isArray(e)?e.map(function(e,r){return u(e,t,n.concat(r))}):p(e)?(0,w.default)(e).map(function(r){return u(e[r],t,n.concat(r))}):t(e,n[n.length-1],n)}function s(e,t,n){var r=[];if((n=n||[]).length>0){var o=t(e,n[n.length-1],n);o&&(r=r.concat(o))}if(Array.isArray(e)){var i=e.map(function(e,r){return s(e,t,n.concat(r))});i&&(r=r.concat(i))}else if(p(e)){var a=(0,w.default)(e).map(function(r){return s(e[r],t,n.concat(r))});a&&(r=r.concat(a))}return c(r)}function l(e){return Array.isArray(e)?e:[e]}function c(e){var t;return(t=[]).concat.apply(t,(0,_.default)(e.map(function(e){return Array.isArray(e)?c(e):e})))}function f(e){return e.filter(function(e){return void 0!==e})}function p(e){return e&&"object"===(void 0===e?"undefined":(0,b.default)(e))}function d(e){return e&&"function"==typeof e}function h(e){if(y(e)){var t=e.op;return"add"===t||"remove"===t||"replace"===t}return!1}function v(e){return h(e)||y(e)&&"mutation"===e.type}function m(e){return v(e)&&("add"===e.op||"replace"===e.op||"merge"===e.op||"mergeDeep"===e.op)}function y(e){return e&&"object"===(void 0===e?"undefined":(0,b.default)(e))}function g(e,t){try{return S.default.getValueByPointer(e,t)}catch(e){return console.error(e),{}}}Object.defineProperty(t,"__esModule",{value:!0});var b=r(n(1)),_=r(n(34)),w=r(n(0)),E=r(n(35)),x=r(n(2)),S=r(n(36)),C=r(n(4)),k=r(n(37)),A=r(n(38));t.default={add:function(e,t){return{op:"add",path:e,value:t}},replace:i,remove:function(e,t){return{op:"remove",path:e}},merge:function(e,t){return{type:"mutation",op:"merge",path:e,value:t}},mergeDeep:function(e,t){return{type:"mutation",op:"mergeDeep",path:e,value:t}},context:function(e,t){return{type:"context",path:e,value:t}},getIn:function(e,t){return t.reduce(function(e,t){return void 0!==t&&e?e[t]:e},e)},applyPatch:function(e,t,n){if(n=n||{},"merge"===(t=(0,x.default)({},t,{path:t.path&&o(t.path)})).op){var r=g(e,t.path);(0,x.default)(r,t.value),S.default.applyPatch(e,[i(t.path,r)])}else if("mergeDeep"===t.op){var a=g(e,t.path);for(var u in t.value){var s=t.value[u],l=Array.isArray(s);if(l){var c=a[u]||[];a[u]=c.concat(s)}else if(p(s)&&!l){var f=(0,x.default)({},a[u]);for(var d in s){if(Object.prototype.hasOwnProperty.call(f,d)){f=(0,k.default)((0,A.default)({},f),s);break}(0,x.default)(f,(0,E.default)({},d,s[d]))}a[u]=f}else a[u]=s}}else if("add"===t.op&&""===t.path&&p(t.value)){var h=(0,w.default)(t.value).reduce(function(e,n){return e.push({op:"add",path:"/"+o(n),value:t.value[n]}),e},[]);S.default.applyPatch(e,h)}else if("replace"===t.op&&""===t.path){var v=t.value;n.allowMetaPatches&&t.meta&&m(t)&&(Array.isArray(t.value)||p(t.value))&&(v=(0,x.default)({},v,t.meta)),e=v}else if(S.default.applyPatch(e,[t]),n.allowMetaPatches&&t.meta&&m(t)&&(Array.isArray(t.value)||p(t.value))){var y=g(e,t.path),b=(0,x.default)({},y,t.meta);S.default.applyPatch(e,[i(t.path,b)])}return e},parentPathMatch:function(e,t){if(!Array.isArray(t))return!1;for(var n=0,r=t.length;n1&&void 0!==arguments[1]?arguments[1]:{},n=t.requestInterceptor,r=t.responseInterceptor,o=e.withCredentials?"include":"same-origin";return function(t){return e({url:t,loadSpec:!0,requestInterceptor:n,responseInterceptor:r,headers:{Accept:"application/json"},credentials:o}).then(function(e){return e.body})}}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(4)),a=r(n(11));t.makeFetchJSON=o,t.clearCache=function(){s.plugins.refs.clearCache()},t.default=function(e){function t(e){var t=this;E&&(s.plugins.refs.docCache[E]=e),s.plugins.refs.fetchJSON=o(w,{requestInterceptor:g,responseInterceptor:b});var n=[s.plugins.refs];return"function"==typeof y&&n.push(s.plugins.parameters),"function"==typeof m&&n.push(s.plugins.properties),"strict"!==p&&n.push(s.plugins.allOf),(0,l.default)({spec:e,context:{baseDoc:E},plugins:n,allowMetaPatches:h,pathDiscriminator:v,parameterMacro:y,modelPropertyMacro:m}).then(_?function(){var e=(0,a.default)(i.default.mark(function e(n){return i.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return e.abrupt("return",n);case 1:case"end":return e.stop()}},e,t)}));return function(t){return e.apply(this,arguments)}}():c.normalizeSwagger)}var n=e.fetch,r=e.spec,f=e.url,p=e.mode,d=e.allowMetaPatches,h=void 0===d||d,v=e.pathDiscriminator,m=e.modelPropertyMacro,y=e.parameterMacro,g=e.requestInterceptor,b=e.responseInterceptor,_=e.skipNormalization,w=e.http,E=e.baseDoc;return E=E||f,w=n||w||u.default,r?t(r):o(w,{requestInterceptor:g,responseInterceptor:b})(E).then(t)};var u=r(n(7)),s=n(31),l=r(s),c=n(5)},function(e,t){e.exports=n(203)},function(e,t){e.exports=n(91)},function(e,t){e.exports=n(2)},function(e,t){e.exports=n(3)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){function n(){Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):this.stack=(new Error).stack;for(var e=arguments.length,n=Array(e),r=0;r-1&&-1===o.indexOf(n)||i.indexOf(u)>-1||a.some(function(e){return u.indexOf(e)>-1})};var r=["properties"],o=["properties"],i=["definitions","parameters","responses","securityDefinitions","components/schemas","components/responses","components/parameters","components/securitySchemes"],a=["schema/example"]},function(e,t,n){e.exports=n(24)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if("string"==typeof e?n.url=e:n=e,!(this instanceof o))return new o(n);(0,a.default)(this,n);var r=this.resolve().then(function(){return t.disableInterfaces||(0,a.default)(t,o.makeApisTagOperation(t)),t});return r.client=this,r}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(3)),a=r((r(n(25)),n(6))),u=r(n(14)),s=r(n(10)),l=n(7),c=r(l),f=n(16),p=r(f),d=r(n(48)),h=n(49),v=n(51),m=n(5);o.http=c.default,o.makeHttp=l.makeHttp.bind(null,o.http),o.resolve=p.default,o.resolveSubtree=d.default,o.execute=v.execute,o.serializeRes=l.serializeRes,o.serializeHeaders=l.serializeHeaders,o.clearCache=f.clearCache,o.parameterBuilders=v.PARAMETER_BUILDERS,o.makeApisTagOperation=h.makeApisTagOperation,o.buildRequest=v.buildRequest,o.helpers={opId:m.opId},o.prototype={http:c.default,execute:function(e){return this.applyDefaults(),o.execute((0,i.default)({spec:this.spec,http:this.http,securities:{authorized:this.authorizations},contextUrl:"string"==typeof this.url?this.url:void 0},e))},resolve:function(){var e=this;return o.resolve({spec:this.spec,url:this.url,allowMetaPatches:this.allowMetaPatches,requestInterceptor:this.requestInterceptor||null,responseInterceptor:this.responseInterceptor||null}).then(function(t){return e.originalSpec=e.spec,e.spec=t.spec,e.errors=t.errors,e})}},o.prototype.applyDefaults=function(){var e=this.spec,t=this.url;if(t&&(0,u.default)(t,"http")){var n=s.default.parse(t);e.host||(e.host=n.host),e.schemes||(e.schemes=[n.protocol.replace(":","")]),e.basePath||(e.basePath="/")}},t.default=o,e.exports=t.default},function(e,t){e.exports=n(905)},function(e,t){e.exports=n(18)},function(e,t){e.exports=n(906)},function(e,t){e.exports=n(907)},function(e,t){e.exports=n(343)},function(e,t){e.exports=n(910)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0}),t.plugins=t.SpecMap=void 0;var o=r(n(8)),i=r(n(1)),a=r(n(17)),u=r(n(4)),s=r(n(0)),l=r(n(18)),c=r(n(32)),f=r(n(2)),p=r(n(19)),d=r(n(20));t.default=function(e){return new w(e).dispatch()};var h=r(n(33)),v=r(n(9)),m=r(n(39)),y=r(n(43)),g=r(n(44)),b=r(n(45)),_=r(n(46)),w=function(){function e(t){(0,p.default)(this,e),(0,f.default)(this,{spec:"",debugLevel:"info",plugins:[],pluginHistory:{},errors:[],mutations:[],promisedPatches:[],state:{},patches:[],context:{},contextTree:new _.default,showDebug:!1,allPatches:[],pluginProp:"specMap",libMethods:(0,f.default)((0,c.default)(this),v.default),allowMetaPatches:!1},t),this.get=this._get.bind(this),this.getContext=this._getContext.bind(this),this.hasRun=this._hasRun.bind(this),this.wrappedPlugins=this.plugins.map(this.wrapPlugin.bind(this)).filter(v.default.isFunction),this.patches.push(v.default.add([],this.spec)),this.patches.push(v.default.context([],this.context)),this.updatePatches(this.patches)}return(0,d.default)(e,[{key:"debug",value:function(e){if(this.debugLevel===e){for(var t,n=arguments.length,r=Array(n>1?n-1:0),o=1;o1?n-1:0),o=1;o0})}},{key:"nextPromisedPatch",value:function(){if(this.promisedPatches.length>0)return a.default.race(this.promisedPatches.map(function(e){return e.value}))}},{key:"getPluginHistory",value:function(e){var t=this.getPluginName(e);return this.pluginHistory[t]||[]}},{key:"getPluginRunCount",value:function(e){return this.getPluginHistory(e).length}},{key:"getPluginHistoryTip",value:function(e){var t=this.getPluginHistory(e);return t&&t[t.length-1]||{}}},{key:"getPluginMutationIndex",value:function(e){var t=this.getPluginHistoryTip(e).mutationIndex;return"number"!=typeof t?-1:t}},{key:"getPluginName",value:function(e){return e.pluginName}},{key:"updatePluginHistory",value:function(e,t){var n=this.getPluginName(e);(this.pluginHistory[n]=this.pluginHistory[n]||[]).push(t)}},{key:"updatePatches",value:function(e,t){var n=this;v.default.normalizeArray(e).forEach(function(e){if(e instanceof Error)n.errors.push(e);else try{if(!v.default.isObject(e))return void n.debug("updatePatches","Got a non-object patch",e);if(n.showDebug&&n.allPatches.push(e),v.default.isPromise(e.value))return n.promisedPatches.push(e),void n.promisedPatchThen(e);if(v.default.isContextPatch(e))return void n.setContext(e.path,e.value);if(v.default.isMutation(e))return void n.updateMutations(e)}catch(e){console.error(e),n.errors.push(e)}})}},{key:"updateMutations",value:function(e){"object"===(0,i.default)(e.value)&&!Array.isArray(e.value)&&this.allowMetaPatches&&(e.value=(0,f.default)({},e.value));var t=v.default.applyPatch(this.state,e,{allowMetaPatches:this.allowMetaPatches});t&&(this.mutations.push(e),this.state=t)}},{key:"removePromisedPatch",value:function(e){var t=this.promisedPatches.indexOf(e);t<0?this.debug("Tried to remove a promisedPatch that isn't there!"):this.promisedPatches.splice(t,1)}},{key:"promisedPatchThen",value:function(e){var t=this;return e.value=e.value.then(function(n){var r=(0,f.default)({},e,{value:n});t.removePromisedPatch(e),t.updatePatches(r)}).catch(function(n){t.removePromisedPatch(e),t.updatePatches(n)})}},{key:"getMutations",value:function(e,t){return e=e||0,"number"!=typeof t&&(t=this.mutations.length),this.mutations.slice(e,t)}},{key:"getCurrentMutations",value:function(){return this.getMutationsForPlugin(this.getCurrentPlugin())}},{key:"getMutationsForPlugin",value:function(e){var t=this.getPluginMutationIndex(e);return this.getMutations(t+1)}},{key:"getCurrentPlugin",value:function(){return this.currentPlugin}},{key:"getPatchesOfType",value:function(e,t){return e.filter(t)}},{key:"getLib",value:function(){return this.libMethods}},{key:"_get",value:function(e){return v.default.getIn(this.state,e)}},{key:"_getContext",value:function(e){return this.contextTree.get(e)}},{key:"setContext",value:function(e,t){return this.contextTree.set(e,t)}},{key:"_hasRun",value:function(e){return this.getPluginRunCount(this.getCurrentPlugin())>(e||0)}},{key:"_clone",value:function(e){return JSON.parse((0,o.default)(e))}},{key:"dispatch",value:function(){function e(e){e&&(e=v.default.fullyNormalizeArray(e),n.updatePatches(e,r))}var t=this,n=this,r=this.nextPlugin();if(!r){var o=this.nextPromisedPatch();if(o)return o.then(function(){return t.dispatch()}).catch(function(){return t.dispatch()});var i={spec:this.state,errors:this.errors};return this.showDebug&&(i.patches=this.allPatches),a.default.resolve(i)}if(n.pluginCount=n.pluginCount||{},n.pluginCount[r]=(n.pluginCount[r]||0)+1,n.pluginCount[r]>100)return a.default.resolve({spec:n.state,errors:n.errors.concat(new Error("We've reached a hard limit of 100 plugin runs"))});if(r!==this.currentPlugin&&this.promisedPatches.length){var u=this.promisedPatches.map(function(e){return e.value});return a.default.all(u.map(function(e){return e.then(Function,Function)})).then(function(){return t.dispatch()})}return function(){n.currentPlugin=r;var t=n.getCurrentMutations(),o=n.mutations.length-1;try{if(r.isGenerator){var i=!0,a=!1,u=void 0;try{for(var s,p=(0,l.default)(r(t,n.getLib()));!(i=(s=p.next()).done);i=!0)e(s.value)}catch(e){a=!0,u=e}finally{try{!i&&p.return&&p.return()}finally{if(a)throw u}}}else e(r(t,n.getLib()))}catch(t){console.error(t),e([(0,f.default)((0,c.default)(t),{plugin:r})])}finally{n.updatePluginHistory(r,{mutationIndex:o})}return n.dispatch()}()}}]),e}(),E={refs:m.default,allOf:y.default,parameters:g.default,properties:b.default};t.SpecMap=w,t.plugins=E},function(e,t){e.exports=n(350)},function(e,t){e.exports=n(288)},function(e,t){e.exports=n(83)},function(e,t){e.exports=n(22)},function(e,t){e.exports=n(911)},function(e,t){e.exports=n(178)},function(e,t){e.exports=n(277)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){if(!A.test(e)){if(!t)throw new O("Tried to resolve a relative URL, without having a basePath. path: '"+e+"' basePath: '"+t+"'");return x.default.resolve(t,e)}return e}function i(e,t){return new O("Could not resolve reference because of: "+e.message,t,e)}function a(e){return(e+"").split("#")}function u(e,t){var n=P[e];if(n&&!S.default.isPromise(n))try{var r=l(t,n);return(0,b.default)(y.default.resolve(r),{__value:r})}catch(e){return y.default.reject(e)}return s(e).then(function(e){return l(t,e)})}function s(e){var t=P[e];return t?S.default.isPromise(t)?t:y.default.resolve(t):(P[e]=I.fetchJSON(e).then(function(t){return P[e]=t,t}),P[e])}function l(e,t){var n=c(e);if(n.length<1)return t;var r=S.default.getIn(t,n);if(void 0===r)throw new O("Could not resolve pointer: "+e+" does not exist in document",{pointer:e});return r}function c(e){if("string"!=typeof e)throw new TypeError("Expected a string, got a "+(void 0===e?"undefined":(0,v.default)(e)));return"/"===e[0]&&(e=e.substr(1)),""===e?[]:e.split("/").map(f)}function f(e){return"string"!=typeof e?e:E.default.unescape(e.replace(/~1/g,"/").replace(/~0/g,"~"))}function p(e){return E.default.escape(e.replace(/~/g,"~0").replace(/\//g,"~1"))}function d(e,t){if(j(t))return!0;var n=e.charAt(t.length),r=t.slice(-1);return 0===e.indexOf(t)&&(!n||"/"===n||"#"===n)&&"#"!==r}function h(e,t,n,r){var o=T.get(r);o||(o={},T.set(r,o));var i=function(e){return 0===e.length?"":"/"+e.map(p).join("/")}(n),a=(t||"")+"#"+e;if(t==r.contextTree.get([]).baseDoc&&d(i,e))return!0;var u="";if(n.some(function(e){return u=u+"/"+p(e),o[u]&&o[u].some(function(e){return d(e,a)||d(a,e)})}))return!0;o[i]=(o[i]||[]).concat(a)}Object.defineProperty(t,"__esModule",{value:!0});var v=r(n(1)),m=r(n(0)),y=r(n(17)),g=r(n(40)),b=r(n(2)),_=n(41),w=r(n(15)),E=r(n(42)),x=r(n(10)),S=r(n(9)),C=r(n(21)),k=n(22),A=new RegExp("^([a-z]+://|//)","i"),O=(0,C.default)("JSONRefError",function(e,t,n){this.originalError=n,(0,b.default)(this,t||{})}),P={},T=new g.default,M={key:"$ref",plugin:function(e,t,n,r){var s=n.slice(0,-1);if(!(0,k.isFreelyNamed)(s)){var l=r.getContext(n).baseDoc;if("string"!=typeof e)return new O("$ref: must be a string (JSON-Ref)",{$ref:e,baseDoc:l,fullPath:n});var f=a(e),p=f[0],d=f[1]||"",v=void 0;try{v=l||p?o(p,l):null}catch(t){return i(t,{pointer:d,$ref:e,basePath:v,fullPath:n})}var y=void 0,g=void 0;if(!h(d,v,s,r)){if(null==v?(g=c(d),void 0===(y=r.get(g))&&(y=new O("Could not resolve reference: "+e,{pointer:d,$ref:e,baseDoc:l,fullPath:n}))):y=null!=(y=u(v,d)).__value?y.__value:y.catch(function(t){throw i(t,{pointer:d,$ref:e,baseDoc:l,fullPath:n})}),y instanceof Error)return[S.default.remove(n),y];var b=S.default.replace(s,y,{$$ref:e});if(v&&v!==l)return[b,S.default.context(s,{baseDoc:v})];try{if(!function(e,t){var n=[e];return t.path.reduce(function(e,t){return n.push(e[t]),e[t]},e),function e(t){return S.default.isObject(t)&&(n.indexOf(t)>=0||(0,m.default)(t).some(function(n){return e(t[n])}))}(t.value)}(r.state,b))return b}catch(e){return null}}}}},I=(0,b.default)(M,{docCache:P,absoluteify:o,clearCache:function(e){void 0!==e?delete P[e]:(0,m.default)(P).forEach(function(e){delete P[e]})},JSONRefError:O,wrapError:i,getDoc:s,split:a,extractFromDoc:u,fetchJSON:function(e){return(0,_.fetch)(e,{headers:{Accept:"application/json, application/yaml"},loadSpec:!0}).then(function(e){return e.text()}).then(function(e){return w.default.safeLoad(e)})},extract:l,jsonPointerToArray:c,unescapeJsonPointerToken:f});t.default=I;var j=function(e){return!e||"/"===e||"#"===e};e.exports=t.default},function(e,t){e.exports=n(914)},function(e,t){e.exports=n(925)},function(e,t){e.exports=n(926)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=function(e){return e&&e.__esModule?e:{default:e}}(n(2)),o=n(22);t.default={key:"allOf",plugin:function(e,t,n,i,a){if(!a.meta||!a.meta.$$ref){var u=n.slice(0,-1);if(!(0,o.isFreelyNamed)(u)){if(!Array.isArray(e)){var s=new TypeError("allOf must be an array");return s.fullPath=n,s}var l=!1,c=a.value;u.forEach(function(e){c&&(c=c[e])}),delete(c=(0,r.default)({},c)).allOf;var f=[i.replace(u,{})].concat(e.map(function(e,t){if(!i.isObject(e)){if(l)return null;l=!0;var r=new TypeError("Elements in allOf must be objects");return r.fullPath=n,r}return i.mergeDeep(u,e)}));return f.push(i.mergeDeep(u,c)),c.$$ref||f.push(i.remove([].concat(u,"$$ref"))),f}}}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(2)),i=r(n(9));t.default={key:"parameters",plugin:function(e,t,n,r,a){if(Array.isArray(e)&&e.length){var u=(0,o.default)([],e),s=n.slice(0,-1),l=(0,o.default)({},i.default.getIn(r.spec,s));return e.forEach(function(e,t){try{u[t].default=r.parameterMacro(l,e)}catch(e){var o=new Error(e);return o.fullPath=n,o}}),i.default.replace(n,u)}return i.default.replace(n,e)}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(2)),i=r(n(9));t.default={key:"properties",plugin:function(e,t,n,r){var a=(0,o.default)({},e);for(var u in e)try{a[u].default=r.modelPropertyMacro(a[u])}catch(e){var s=new Error(e);return s.fullPath=n,s}return i.default.replace(n,a)}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e,t){return i({children:{}},e,t)}function i(e,t,n){return e.value=t||{},e.protoValue=n?(0,u.default)({},n.protoValue,e.value):e.value,(0,a.default)(e.children).forEach(function(t){var n=e.children[t];e.children[t]=i(n,n.value,e)}),e}Object.defineProperty(t,"__esModule",{value:!0});var a=r(n(0)),u=r(n(3)),s=r(n(19)),l=r(n(20)),c=function(){function e(t){(0,s.default)(this,e),this.root=o(t||{})}return(0,l.default)(e,[{key:"set",value:function(e,t){var n=this.getParent(e,!0);if(n){var r=e[e.length-1],a=n.children;a[r]?i(a[r],t,n):a[r]=o(t,n)}else i(this.root,t,null)}},{key:"get",value:function(e){if((e=e||[]).length<1)return this.root.value;for(var t=this.root,n=void 0,r=void 0,o=0;o2&&void 0!==arguments[2]?arguments[2]:{};return o.default.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:return r=g.returnEntireTree,a=g.baseDoc,c=g.requestInterceptor,f=g.responseInterceptor,p=g.parameterMacro,d=g.modelPropertyMacro,h={pathDiscriminator:n,baseDoc:a,requestInterceptor:c,responseInterceptor:f,parameterMacro:p,modelPropertyMacro:d},v=(0,l.normalizeSwagger)({spec:t}),m=v.spec,e.next=5,(0,s.default)((0,i.default)({},h,{spec:m,allowMetaPatches:!0,skipNormalization:!0}));case 5:return y=e.sent,!r&&Array.isArray(n)&&n.length&&(y.spec=(0,u.default)(y.spec,n)||null),e.abrupt("return",y);case 8:case"end":return e.stop()}},e,this)}));return function(t,n){return e.apply(this,arguments)}}(),e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return function(t){var n=t.pathName,r=t.method,o=t.operationId;return function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.execute((0,a.default)({spec:e.spec},(0,u.default)(e,"requestInterceptor","responseInterceptor","userFetch"),{pathName:n,method:r,parameters:t,operationId:o},i))}}}function i(e){var t=e.spec,n=e.cb,r=void 0===n?l:n,o=e.defaultTag,i=void 0===o?"default":o,a=e.v2OperationIdCompatibilityMode,u={},f={};return(0,s.eachOperation)(t,function(e){var n=e.pathName,o=e.method,l=e.operation;(l.tags?c(l.tags):[i]).forEach(function(e){if("string"==typeof e){var i=f[e]=f[e]||{},c=(0,s.opId)(l,n,o,{v2OperationIdCompatibilityMode:a}),p=r({spec:t,pathName:n,method:o,operation:l,operationId:c});if(u[c])u[c]++,i[""+c+u[c]]=p;else if(void 0!==i[c]){var d=u[c]||1;u[c]=d+1,i[""+c+u[c]]=p;var h=i[c];delete i[c],i[""+c+d]=h}else i[c]=p}})}),f}Object.defineProperty(t,"__esModule",{value:!0}),t.self=void 0;var a=r(n(3));t.makeExecute=o,t.makeApisTagOperationsOperationExecute=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=f.makeExecute(e),n=f.mapTagOperations({v2OperationIdCompatibilityMode:e.v2OperationIdCompatibilityMode,spec:e.spec,cb:t}),r={};for(var o in n)for(var i in r[o]={operations:{}},n[o])r[o].operations[i]={execute:n[o][i]};return{apis:r}},t.makeApisTagOperation=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=f.makeExecute(e);return{apis:f.mapTagOperations({v2OperationIdCompatibilityMode:e.v2OperationIdCompatibilityMode,spec:e.spec,cb:t})}},t.mapTagOperations=i;var u=r(n(50)),s=n(5),l=function(){return null},c=function(e){return Array.isArray(e)?e:[e]},f=t.self={mapTagOperations:i,makeExecute:o}},function(e,t){e.exports=n(927)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=e.spec,n=e.operationId,r=(e.securities,e.requestContentType,e.responseContentType),o=e.scheme,a=e.requestInterceptor,s=e.responseInterceptor,c=e.contextUrl,f=e.userFetch,p=(e.requestBody,e.server),d=e.serverVariables,h=e.http,y=e.parameters,g=e.parameterBuilders,O=(0,x.isOAS3)(t);g||(g=O?_.default:b.default);var P={url:"",credentials:h&&h.withCredentials?"include":"same-origin",headers:{},cookies:{}};a&&(P.requestInterceptor=a),s&&(P.responseInterceptor=s),f&&(P.userFetch=f);var T=(0,x.getOperationRaw)(t,n);if(!T)throw new C("Operation "+n+" not found");var M=T.operation,I=void 0===M?{}:M,j=T.method,N=T.pathName;if(P.url+=i({spec:t,scheme:o,contextUrl:c,server:p,serverVariables:d,pathName:N,method:j}),!n)return delete P.cookies,P;P.url+=N,P.method=(""+j).toUpperCase(),y=y||{};var R=t.paths[N]||{};r&&(P.headers.accept=r);var D=A([].concat(S(I.parameters)).concat(S(R.parameters)));D.forEach(function(e){var n=g[e.in],r=void 0;if("body"===e.in&&e.schema&&e.schema.properties&&(r=y),void 0===(r=e&&e.name&&y[e.name])?r=e&&e.name&&y[e.in+"."+e.name]:k(e.name,D).length>1&&console.warn("Parameter '"+e.name+"' is ambiguous because the defined spec has more than one parameter with the name: '"+e.name+"' and the passed-in parameter values did not define an 'in' value."),null!==r){if(void 0!==e.default&&void 0===r&&(r=e.default),void 0===r&&e.required&&!e.allowEmptyValue)throw new Error("Required parameter "+e.name+" is not provided");if(O&&e.schema&&"object"===e.schema.type&&"string"==typeof r)try{r=JSON.parse(r)}catch(e){throw new Error("Could not parse object parameter value string as JSON")}n&&n({req:P,parameter:e,value:r,operation:I,spec:t})}});var L=(0,u.default)({},e,{operation:I});if((P=O?(0,w.default)(L,P):(0,E.default)(L,P)).cookies&&(0,l.default)(P.cookies).length){var U=(0,l.default)(P.cookies).reduce(function(e,t){var n=P.cookies[t];return e+(e?"&":"")+v.default.serialize(t,n)},"");P.headers.Cookie=U}return P.cookies&&delete P.cookies,(0,m.mergeInQueryOrForm)(P),P}function i(e){return(0,x.isOAS3)(e.spec)?function(e){var t=e.spec,n=e.pathName,r=e.method,o=e.server,i=e.contextUrl,a=e.serverVariables,u=void 0===a?{}:a,s=(0,f.default)(t,["paths",n,(r||"").toLowerCase(),"servers"])||(0,f.default)(t,["paths",n,"servers"])||(0,f.default)(t,["servers"]),l="",c=null;if(o&&s&&s.length){var p=s.map(function(e){return e.url});p.indexOf(o)>-1&&(l=o,c=s[p.indexOf(o)])}!l&&s&&s.length&&(l=s[0].url,c=s[0]),l.indexOf("{")>-1&&function(e){for(var t=[],n=/{([^}]+)}/g,r=void 0;r=n.exec(e);)t.push(r[1]);return t}(l).forEach(function(e){if(c.variables&&c.variables[e]){var t=c.variables[e],n=u[e]||t.default,r=new RegExp("{"+e+"}","g");l=l.replace(r,n)}});return function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=h.default.parse(e),r=h.default.parse(t),o=P(n.protocol)||P(r.protocol)||"",i=n.host||r.host,a=n.pathname||"",u=void 0;return"/"===(u=o&&i?o+"://"+(i+a):a)[u.length-1]?u.slice(0,-1):u}(l,i)}(e):function(e){var t=e.spec,n=e.scheme,r=e.contextUrl,o=void 0===r?"":r,i=h.default.parse(o),a=Array.isArray(t.schemes)?t.schemes[0]:null,u=n||a||P(i.protocol)||"http",s=t.host||i.host||"",l=t.basePath||"",c=void 0;return"/"===(c=u&&s?u+"://"+(s+l):l)[c.length-1]?c.slice(0,-1):c}(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.self=void 0;var a=r(n(8)),u=r(n(3)),s=r(n(52)),l=r(n(0)),c=r(n(2));t.execute=function(e){var t=e.http,n=e.fetch,r=e.spec,o=e.operationId,i=e.pathName,l=e.method,c=e.parameters,f=e.securities,h=(0,s.default)(e,["http","fetch","spec","operationId","pathName","method","parameters","securities"]),v=t||n||y.default;i&&l&&!o&&(o=(0,x.legacyIdFromPathMethod)(i,l));var m=O.buildRequest((0,u.default)({spec:r,operationId:o,parameters:c,securities:f,http:v},h));return m.body&&((0,p.default)(m.body)||(0,d.default)(m.body))&&(m.body=(0,a.default)(m.body)),v(m)},t.buildRequest=o,t.baseUrl=i;var f=r((r(n(6)),n(12))),p=r(n(53)),d=r(n(54)),h=r((r(n(13)),n(10))),v=r(n(55)),m=n(7),y=r(m),g=r(n(21)),b=r(n(56)),_=r(n(57)),w=r(n(62)),E=r(n(64)),x=n(5),S=function(e){return Array.isArray(e)?e:[]},C=(0,g.default)("OperationNotFoundError",function(e,t,n){this.originalError=n,(0,c.default)(this,t||{})}),k=function(e,t){return t.filter(function(t){return t.name===e})},A=function(e){var t={};e.forEach(function(e){t[e.in]||(t[e.in]={}),t[e.in][e.name]=e});var n=[];return(0,l.default)(t).forEach(function(e){(0,l.default)(t[e]).forEach(function(r){n.push(t[e][r])})}),n},O=t.self={buildRequest:o},P=function(e){return e?e.replace(/\W/g,""):null}},function(e,t){e.exports=n(84)},function(e,t){e.exports=n(227)},function(e,t){e.exports=n(24)},function(e,t){e.exports=n(930)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={body:function(e){var t=e.req,n=e.value;t.body=n},header:function(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{},void 0!==r&&(t.headers[n.name]=r)},query:function(e){var t=e.req,n=e.value,r=e.parameter;if(t.query=t.query||{},!1===n&&"boolean"===r.type&&(n="false"),0===n&&["number","integer"].indexOf(r.type)>-1&&(n="0"),n)t.query[r.name]={collectionFormat:r.collectionFormat,value:n};else if(r.allowEmptyValue&&void 0!==n){var o=r.name;t.query[o]=t.query[o]||{},t.query[o].allowEmptyValue=!0}},path:function(e){var t=e.req,n=e.value,r=e.parameter;t.url=t.url.replace("{"+r.name+"}",encodeURIComponent(n))},formData:function(e){var t=e.req,n=e.value,r=e.parameter;(n||r.allowEmptyValue)&&(t.form=t.form||{},t.form[r.name]={value:n,allowEmptyValue:r.allowEmptyValue,collectionFormat:r.collectionFormat})}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(0)),i=r(n(1)),a=r(n(58));t.default={path:function(e){var t=e.req,n=e.value,r=e.parameter,o=r.name,i=r.style,u=r.explode,s=(0,a.default)({key:r.name,value:n,style:i||"simple",explode:u||!1,escape:!0});t.url=t.url.replace("{"+o+"}",s)},query:function(e){var t=e.req,n=e.value,r=e.parameter;if(t.query=t.query||{},!1===n&&(n="false"),0===n&&(n="0"),n){var u=void 0===n?"undefined":(0,i.default)(n);"deepObject"===r.style?(0,o.default)(n).forEach(function(e){var o=n[e];t.query[r.name+"["+e+"]"]={value:(0,a.default)({key:e,value:o,style:"deepObject",escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}}):"object"!==u||Array.isArray(n)||"form"!==r.style&&r.style||!r.explode&&void 0!==r.explode?t.query[r.name]={value:(0,a.default)({key:r.name,value:n,style:r.style||"form",explode:void 0===r.explode||r.explode,escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}:(0,o.default)(n).forEach(function(e){var o=n[e];t.query[e]={value:(0,a.default)({key:e,value:o,style:r.style||"form",escape:r.allowReserved?"unsafe":"reserved"}),skipEncoding:!0}})}else if(r.allowEmptyValue&&void 0!==n){var s=r.name;t.query[s]=t.query[s]||{},t.query[s].allowEmptyValue=!0}},header:function(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{},u.indexOf(n.name.toLowerCase())>-1||void 0!==r&&(t.headers[n.name]=(0,a.default)({key:n.name,value:r,style:n.style||"simple",explode:void 0!==n.explode&&n.explode,escape:!1}))},cookie:function(e){var t=e.req,n=e.parameter,r=e.value;t.headers=t.headers||{};var o=void 0===r?"undefined":(0,i.default)(r);if("undefined"!==o){var u="object"===o&&!Array.isArray(r)&&n.explode?"":n.name+"=";t.headers.Cookie=u+(0,a.default)({key:n.name,value:r,escape:!1,style:n.style||"form",explode:void 0!==n.explode&&n.explode})}}};var u=["accept","authorization","content-type"];e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=(arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}).escape,n=arguments[2];return"number"==typeof e&&(e=e.toString()),"string"==typeof e&&e.length&&t?n?JSON.parse(e):(0,s.stringToCharArray)(e).map(function(e){return c(e)?e:l(e)&&"unsafe"===t?e:((0,u.default)(e)||[]).map(function(e){return("0"+e.toString(16).toUpperCase()).slice(-2)}).map(function(e){return"%"+e}).join("")}).join(""):e}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(0)),a=r(n(1));t.encodeDisallowedCharacters=o,t.default=function(e){var t=e.value;return Array.isArray(t)?function(e){var t=e.key,n=e.value,r=e.style,i=e.explode,a=e.escape,u=function(e){return o(e,{escape:a})};if("simple"===r)return n.map(function(e){return u(e)}).join(",");if("label"===r)return"."+n.map(function(e){return u(e)}).join(".");if("matrix"===r)return n.map(function(e){return u(e)}).reduce(function(e,n){return!e||i?(e||"")+";"+t+"="+n:e+","+n},"");if("form"===r){var s=i?"&"+t+"=":",";return n.map(function(e){return u(e)}).join(s)}if("spaceDelimited"===r){var l=i?t+"=":"";return n.map(function(e){return u(e)}).join(" "+l)}if("pipeDelimited"===r){var c=i?t+"=":"";return n.map(function(e){return u(e)}).join("|"+c)}}(e):"object"===(void 0===t?"undefined":(0,a.default)(t))?function(e){var t=e.key,n=e.value,r=e.style,a=e.explode,u=e.escape,s=function(e){return o(e,{escape:u})},l=(0,i.default)(n);return"simple"===r?l.reduce(function(e,t){var r=s(n[t]);return(e?e+",":"")+t+(a?"=":",")+r},""):"label"===r?l.reduce(function(e,t){var r=s(n[t]);return(e?e+".":".")+t+(a?"=":".")+r},""):"matrix"===r&&a?l.reduce(function(e,t){var r=s(n[t]);return(e?e+";":";")+t+"="+r},""):"matrix"===r?l.reduce(function(e,r){var o=s(n[r]);return(e?e+",":";"+t+"=")+r+","+o},""):"form"===r?l.reduce(function(e,t){var r=s(n[t]);return(e?e+(a?"&":","):"")+t+(a?"=":",")+r},""):void 0}(e):function(e){var t=e.key,n=e.value,r=e.style,i=e.escape,a=function(e){return o(e,{escape:i})};return"simple"===r?a(n):"label"===r?"."+a(n):"matrix"===r?";"+t+"="+a(n):"form"===r?a(n):"deepObject"===r?a(n):void 0}(e)};var u=r((r(n(59)),n(60))),s=n(61),l=function(e){return":/?#[]@!$&'()*+,;=".indexOf(e)>-1},c=function(e){return/^[a-z0-9\-._~]+$/i.test(e)}},function(e,t){e.exports=n(931)},function(e,t){e.exports=n(932)},function(e,t){e.exports=n(933)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=e.request,n=e.securities,r=void 0===n?{}:n,o=e.operation,i=void 0===o?{}:o,a=e.spec,f=(0,s.default)({},t),p=r.authorized,d=void 0===p?{}:p,h=i.security||a.security||[],v=d&&!!(0,u.default)(d).length,m=(0,l.default)(a,["components","securitySchemes"])||{};return f.headers=f.headers||{},f.query=f.query||{},(0,u.default)(r).length&&v&&h&&(!Array.isArray(i.security)||i.security.length)?(h.forEach(function(e,t){for(var n in e){var r=d[n],o=m[n];if(r){var i=r.value||r,a=o.type;if(r)if("apiKey"===a)"query"===o.in&&(f.query[o.name]=i),"header"===o.in&&(f.headers[o.name]=i),"cookie"===o.in&&(f.cookies[o.name]=i);else if("http"===a){if("basic"===o.scheme){var u=i.username,s=i.password,l=(0,c.default)(u+":"+s);f.headers.Authorization="Basic "+l}"bearer"===o.scheme&&(f.headers.Authorization="Bearer "+i)}else if("oauth2"===a){var p=r.token||{},h=p.access_token,v=p.token_type;v&&"bearer"!==v.toLowerCase()||(v="Bearer"),f.headers.Authorization=v+" "+h}}}}),f):t}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(8)),a=r(n(1)),u=r(n(0));t.default=function(e,t){var n=e.operation,r=e.requestBody,s=e.securities,l=e.spec,c=e.attachContentTypeForEmptyPayload,p=e.requestContentType;t=o({request:t,securities:s,operation:n,spec:l});var d=n.requestBody||{},h=(0,u.default)(d.content||{}),v=p&&h.indexOf(p)>-1;if(r||c){if(p&&v)t.headers["Content-Type"]=p;else if(!p){var m=h[0];m&&(t.headers["Content-Type"]=m,p=m)}}else p&&v&&(t.headers["Content-Type"]=p);return r&&(p?h.indexOf(p)>-1&&("application/x-www-form-urlencoded"===p||0===p.indexOf("multipart/")?"object"===(void 0===r?"undefined":(0,a.default)(r))?(t.form={},(0,u.default)(r).forEach(function(e){var n,o=r[e],u=void 0;"undefined"!=typeof File&&(u=o instanceof File),"undefined"!=typeof Blob&&(u=u||o instanceof Blob),void 0!==f.Buffer&&(u=u||f.Buffer.isBuffer(o)),n="object"!==(void 0===o?"undefined":(0,a.default)(o))||u?o:Array.isArray(o)?o.toString():(0,i.default)(o),t.form[e]={value:n}})):t.form=r:t.body=r):t.body=r),t},t.applySecurities=o;var s=r(n(6)),l=r(n(12)),c=r(n(13)),f=n(63)},function(e,t){e.exports=n(54)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=e.request,n=e.securities,r=void 0===n?{}:n,o=e.operation,s=void 0===o?{}:o,l=e.spec,c=(0,u.default)({},t),f=r.authorized,p=void 0===f?{}:f,d=r.specSecurity,h=void 0===d?[]:d,v=s.security||h,m=p&&!!(0,i.default)(p).length,y=l.securityDefinitions;return c.headers=c.headers||{},c.query=c.query||{},(0,i.default)(r).length&&m&&v&&(!Array.isArray(s.security)||s.security.length)?(v.forEach(function(e,t){for(var n in e){var r=p[n];if(r){var o=r.token,i=r.value||r,u=y[n],s=u.type,l=u["x-tokenName"]||"access_token",f=o&&o[l],d=o&&o.token_type;if(r)if("apiKey"===s){var h="query"===u.in?"query":"headers";c[h]=c[h]||{},c[h][u.name]=i}else"basic"===s?i.header?c.headers.authorization=i.header:(i.base64=(0,a.default)(i.username+":"+i.password),c.headers.authorization="Basic "+i.base64):"oauth2"===s&&f&&(d=d&&"bearer"!==d.toLowerCase()?d:"Bearer",c.headers.authorization=d+" "+f)}}}),c):t}Object.defineProperty(t,"__esModule",{value:!0});var i=r(n(0));t.default=function(e,t){var n=e.spec,r=e.operation,i=e.securities,a=e.requestContentType,u=e.attachContentTypeForEmptyPayload;if((t=o({request:t,securities:i,operation:r,spec:n})).body||t.form||u)a?t.headers["Content-Type"]=a:Array.isArray(r.consumes)?t.headers["Content-Type"]=r.consumes[0]:Array.isArray(n.consumes)?t.headers["Content-Type"]=n.consumes[0]:r.parameters&&r.parameters.filter(function(e){return"file"===e.type}).length?t.headers["Content-Type"]="multipart/form-data":r.parameters&&r.parameters.filter(function(e){return"formData"===e.in}).length&&(t.headers["Content-Type"]="application/x-www-form-urlencoded");else if(a){var s=r.parameters&&r.parameters.filter(function(e){return"body"===e.in}).length>0,l=r.parameters&&r.parameters.filter(function(e){return"formData"===e.in}).length>0;(s||l)&&(t.headers["Content-Type"]=a)}return t},t.applySecurities=o;var a=r(n(13)),u=r(n(6));r(n(7))}])},function(e,t,n){"use strict";var r=Object.prototype.hasOwnProperty,o=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}();t.arrayToObject=function(e,t){for(var n=t&&t.plainObjects?Object.create(null):{},r=0;r=48&&i<=57||i>=65&&i<=90||i>=97&&i<=122?n+=t.charAt(r):i<128?n+=o[i]:i<2048?n+=o[192|i>>6]+o[128|63&i]:i<55296||i>=57344?n+=o[224|i>>12]+o[128|i>>6&63]+o[128|63&i]:(r+=1,i=65536+((1023&i)<<10|1023&t.charCodeAt(r)),n+=o[240|i>>18]+o[128|i>>12&63]+o[128|i>>6&63]+o[128|63&i])}return n},t.compact=function(e){for(var t=[{obj:{o:e},prop:"o"}],n=[],r=0;r=0;l--)if(f[l]!=p[l])return!1;for(l=f.length-1;l>=0;l--)if(c=f[l],!a(e[c],t[c],n))return!1;return typeof e==typeof t}(e,t,n))};function u(e){return null===e||void 0===e}function s(e){return!(!e||"object"!=typeof e||"number"!=typeof e.length)&&("function"==typeof e.copy&&"function"==typeof e.slice&&!(e.length>0&&"number"!=typeof e[0]))}},function(e,t,n){var r={strict:!0},o=n(391),i=function(e,t){return o(e,t,r)},a=n(230);t.JsonPatchError=a.PatchError,t.deepClone=a._deepClone;var u={add:function(e,t,n){return e[t]=this.value,{newDocument:n}},remove:function(e,t,n){var r=e[t];return delete e[t],{newDocument:n,removed:r}},replace:function(e,t,n){var r=e[t];return e[t]=this.value,{newDocument:n,removed:r}},move:function(e,t,n){var r=l(n,this.path);r&&(r=a._deepClone(r));var o=c(n,{op:"remove",path:this.from}).removed;return c(n,{op:"add",path:this.path,value:o}),{newDocument:n,removed:r}},copy:function(e,t,n){var r=l(n,this.from);return c(n,{op:"add",path:this.path,value:a._deepClone(r)}),{newDocument:n}},test:function(e,t,n){return{newDocument:n,test:i(e[t],this.value)}},_get:function(e,t,n){return this.value=e[t],{newDocument:n}}},s={add:function(e,t,n){return a.isInteger(t)?e.splice(t,0,this.value):e[t]=this.value,{newDocument:n,index:t}},remove:function(e,t,n){return{newDocument:n,removed:e.splice(t,1)[0]}},replace:function(e,t,n){var r=e[t];return e[t]=this.value,{newDocument:n,removed:r}},move:u.move,copy:u.copy,test:u.test,_get:u._get};function l(e,t){if(""==t)return e;var n={op:"_get",path:t};return c(e,n),n.value}function c(e,n,r,o){if(void 0===r&&(r=!1),void 0===o&&(o=!0),r&&("function"==typeof r?r(n,0,e,n.path):p(n,0)),""===n.path){var c={newDocument:e};if("add"===n.op)return c.newDocument=n.value,c;if("replace"===n.op)return c.newDocument=n.value,c.removed=e,c;if("move"===n.op||"copy"===n.op)return c.newDocument=l(e,n.from),"move"===n.op&&(c.removed=e),c;if("test"===n.op){if(c.test=i(e,n.value),!1===c.test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",0,n,e);return c.newDocument=e,c}if("remove"===n.op)return c.removed=e,c.newDocument=null,c;if("_get"===n.op)return n.value=e,c;if(r)throw new t.JsonPatchError("Operation `op` property is not one of operations defined in RFC-6902","OPERATION_OP_INVALID",0,n,e);return c}o||(e=a._deepClone(e));var f=(n.path||"").split("/"),d=e,h=1,v=f.length,m=void 0,y=void 0,g=void 0;for(g="function"==typeof r?r:p;;){if(y=f[h],r&&void 0===m&&(void 0===d[y]?m=f.slice(0,h).join("/"):h==v-1&&(m=n.path),void 0!==m&&g(n,0,e,m)),h++,Array.isArray(d)){if("-"===y)y=d.length;else{if(r&&!a.isInteger(y))throw new t.JsonPatchError("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index","OPERATION_PATH_ILLEGAL_ARRAY_INDEX",0,n.path,n);a.isInteger(y)&&(y=~~y)}if(h>=v){if(r&&"add"===n.op&&y>d.length)throw new t.JsonPatchError("The specified index MUST NOT be greater than the number of elements in the array","OPERATION_VALUE_OUT_OF_BOUNDS",0,n.path,n);if(!1===(c=s[n.op].call(n,d,y,e)).test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",0,n,e);return c}}else if(y&&-1!=y.indexOf("~")&&(y=a.unescapePathComponent(y)),h>=v){if(!1===(c=u[n.op].call(n,d,y,e)).test)throw new t.JsonPatchError("Test operation failed","TEST_OPERATION_FAILED",0,n,e);return c}d=d[y]}}function f(e,n,r,o){if(void 0===o&&(o=!0),r&&!Array.isArray(n))throw new t.JsonPatchError("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");o||(e=a._deepClone(e));for(var i=new Array(n.length),u=0,s=n.length;u0)throw new t.JsonPatchError('Operation `path` property must start with "/"',"OPERATION_PATH_INVALID",n,e,r);if(("move"===e.op||"copy"===e.op)&&"string"!=typeof e.from)throw new t.JsonPatchError("Operation `from` property is not present (applicable in `move` and `copy` operations)","OPERATION_FROM_REQUIRED",n,e,r);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&void 0===e.value)throw new t.JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_REQUIRED",n,e,r);if(("add"===e.op||"replace"===e.op||"test"===e.op)&&a.hasUndefined(e.value))throw new t.JsonPatchError("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED",n,e,r);if(r)if("add"==e.op){var i=e.path.split("/").length,s=o.split("/").length;if(i!==s+1&&i!==s)throw new t.JsonPatchError("Cannot perform an `add` operation at the desired path","OPERATION_PATH_CANNOT_ADD",n,e,r)}else if("replace"===e.op||"remove"===e.op||"_get"===e.op){if(e.path!==o)throw new t.JsonPatchError("Cannot perform the operation at a path that does not exist","OPERATION_PATH_UNRESOLVABLE",n,e,r)}else if("move"===e.op||"copy"===e.op){var l=d([{op:"_get",path:e.from,value:void 0}],r);if(l&&"OPERATION_PATH_UNRESOLVABLE"===l.name)throw new t.JsonPatchError("Cannot perform the operation from a path that does not exist","OPERATION_FROM_UNRESOLVABLE",n,e,r)}}function d(e,n,r){try{if(!Array.isArray(e))throw new t.JsonPatchError("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");if(n)f(a._deepClone(n),a._deepClone(e),r||!0);else{r=r||p;for(var o=0;o1&&void 0!==arguments[1]?arguments[1]:(0,a.List)();return function(e){return(e.authSelectors.definitionsToAuthorize()||(0,a.List)()).filter(function(e){return t.some(function(t){return t.get(e.keySeq().first())})})}},t.authorized=(0,i.createSelector)(s,function(e){return e.get("authorized")||(0,a.Map)()}),t.isAuthorized=function(e,t){return function(e){var n=e.authSelectors.authorized();return a.List.isList(t)?!!t.toJS().filter(function(e){return-1===(0,r.default)(e).map(function(e){return!!n.get(e)}).indexOf(!1)}).length:null}},t.getConfigs=(0,i.createSelector)(s,function(e){return e.get("configs")})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.execute=void 0;var r,o=n(25),i=(r=o)&&r.__esModule?r:{default:r};t.execute=function(e,t){var n=t.authSelectors,r=t.specSelectors;return function(t){var o=t.path,a=t.method,u=t.operation,s=t.extras,l={authorized:n.authorized()&&n.authorized().toJS(),definitions:r.securityDefinitions()&&r.securityDefinitions().toJS(),specSecurity:r.security()&&r.security().toJS()};return e((0,i.default)({path:o,method:a,operation:u,securities:l},s))}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return{fn:{shallowEqualKeys:r.shallowEqualKeys}}};var r=n(9)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=s(n(41)),o=s(n(23));t.default=function(e){var t=e.fn,n={download:function(e){return function(n){var r=n.errActions,i=n.specSelectors,a=n.specActions,s=n.getConfigs,l=t.fetch,c=s();function f(t){if(t instanceof Error||t.status>=400)return a.updateLoadingStatus("failed"),r.newThrownErr((0,o.default)(new Error((t.message||t.statusText)+" "+e),{source:"fetch"})),void(!t.status&&t instanceof Error&&function(){try{var t=void 0;if("URL"in u.default?t=new URL(e):(t=document.createElement("a")).href=e,"https:"!==t.protocol&&"https:"===u.default.location.protocol){var n=(0,o.default)(new Error("Possible mixed-content issue? The page was loaded over https:// but a "+t.protocol+"// URL was specified. Check that you are not attempting to load mixed content."),{source:"fetch"});return void r.newThrownErr(n)}if(t.origin!==u.default.location.origin){var i=(0,o.default)(new Error("Possible cross-origin (CORS) issue? The URL origin ("+t.origin+") does not match the page ("+u.default.location.origin+"). Check the server returns the correct 'Access-Control-Allow-*' headers."),{source:"fetch"});r.newThrownErr(i)}}catch(e){return}}());a.updateLoadingStatus("success"),a.updateSpec(t.text),i.url()!==e&&a.updateUrl(e)}e=e||i.url(),a.updateLoadingStatus("loading"),r.clear({source:"fetch"}),l({url:e,loadSpec:!0,requestInterceptor:c.requestInterceptor||function(e){return e},responseInterceptor:c.responseInterceptor||function(e){return e},credentials:"same-origin",headers:{Accept:"application/json,*/*"}}).then(f,f)}},updateLoadingStatus:function(e){var t=[null,"loading","failed","success","failedConfig"];return-1===t.indexOf(e)&&console.error("Error: "+e+" is not one of "+(0,r.default)(t)),{type:"spec_update_loading_status",payload:e}}},s={loadingStatus:(0,i.createSelector)(function(e){return e||(0,a.Map)()},function(e){return e.get("loadingStatus")||null})};return{statePlugins:{spec:{actions:n,reducers:{spec_update_loading_status:function(e,t){return"string"==typeof t.payload?e.set("loadingStatus",t.payload):e}},selectors:s}}}};var i=n(57),a=n(7),u=s(n(32));function s(e){return e&&e.__esModule?e:{default:e}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return{statePlugins:{spec:{actions:a,selectors:f},configs:{reducers:s.default,actions:i,selectors:u}}}};var r=c(n(934)),o=n(233),i=l(n(234)),a=l(n(401)),u=l(n(402)),s=c(n(403));function l(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}function c(e){return e&&e.__esModule?e:{default:e}}var f={getLocalConfig:function(){return(0,o.parseYamlConfig)(r.default)}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getConfigByUrl=t.downloadConfig=void 0;var r=n(233);t.downloadConfig=function(e){return function(t){return(0,t.fn.fetch)(e)}},t.getConfigByUrl=function(e,t){return function(n){var o=n.specActions;if(e)return o.downloadConfig(e).then(i,i);function i(n){n instanceof Error||n.status>=400?(o.updateLoadingStatus("failedConfig"),o.updateLoadingStatus("failedConfig"),o.updateUrl(""),console.error(n.statusText+" "+e.url),t(null)):t((0,r.parseYamlConfig)(n.text))}}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});t.get=function(e,t){return e.getIn(Array.isArray(t)?t:[t])}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r,o,i=n(22),a=(r=i)&&r.__esModule?r:{default:r},u=n(7),s=n(234);t.default=(o={},(0,a.default)(o,s.UPDATE_CONFIGS,function(e,t){return e.merge((0,u.fromJS)(t.payload))}),(0,a.default)(o,s.TOGGLE_CONFIGS,function(e,t){var n=t.payload,r=e.get(n);return e.set(n,!r)}),o)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){return[r.default,{statePlugins:{configs:{wrapActions:{loaded:function(e,t){return function(){e.apply(void 0,arguments);var n=window.location.hash;t.layoutActions.parseDeepLinkHash(n)}}}}},wrapComponents:{operation:o.default,OperationTag:i.default}}]};var r=a(n(405)),o=a(n(407)),i=a(n(408));function a(e){return e&&e.__esModule?e:{default:e}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.clearScrollTo=t.scrollToElement=t.readyToScroll=t.parseDeepLinkHash=t.scrollTo=t.show=void 0;var r,o=f(n(22)),i=f(n(18)),a=n(406),u=f(n(935)),s=n(9),l=n(7),c=f(l);function f(e){return e&&e.__esModule?e:{default:e}}var p=t.show=function(e,t){var n=t.getConfigs,r=t.layoutSelectors;return function(){for(var t=arguments.length,o=Array(t),u=0;u",Gt:"≫",gt:">",gtcc:"⪧",gtcir:"⩺",gtdot:"⋗",gtlPar:"⦕",gtquest:"⩼",gtrapprox:"⪆",gtrarr:"⥸",gtrdot:"⋗",gtreqless:"⋛",gtreqqless:"⪌",gtrless:"≷",gtrsim:"≳",gvertneqq:"≩︀",gvnE:"≩︀",Hacek:"ˇ",hairsp:" ",half:"½",hamilt:"ℋ",HARDcy:"Ъ",hardcy:"ъ",hArr:"⇔",harr:"↔",harrcir:"⥈",harrw:"↭",Hat:"^",hbar:"ℏ",Hcirc:"Ĥ",hcirc:"ĥ",hearts:"♥",heartsuit:"♥",hellip:"…",hercon:"⊹",Hfr:"ℌ",hfr:"𝔥",HilbertSpace:"ℋ",hksearow:"⤥",hkswarow:"⤦",hoarr:"⇿",homtht:"∻",hookleftarrow:"↩",hookrightarrow:"↪",Hopf:"ℍ",hopf:"𝕙",horbar:"―",HorizontalLine:"─",Hscr:"ℋ",hscr:"𝒽",hslash:"ℏ",Hstrok:"Ħ",hstrok:"ħ",HumpDownHump:"≎",HumpEqual:"≏",hybull:"⁃",hyphen:"‐",Iacute:"Í",iacute:"í",ic:"⁣",Icirc:"Î",icirc:"î",Icy:"И",icy:"и",Idot:"İ",IEcy:"Е",iecy:"е",iexcl:"¡",iff:"⇔",Ifr:"ℑ",ifr:"𝔦",Igrave:"Ì",igrave:"ì",ii:"ⅈ",iiiint:"⨌",iiint:"∭",iinfin:"⧜",iiota:"℩",IJlig:"IJ",ijlig:"ij",Im:"ℑ",Imacr:"Ī",imacr:"ī",image:"ℑ",ImaginaryI:"ⅈ",imagline:"ℐ",imagpart:"ℑ",imath:"ı",imof:"⊷",imped:"Ƶ",Implies:"⇒",in:"∈",incare:"℅",infin:"∞",infintie:"⧝",inodot:"ı",Int:"∬",int:"∫",intcal:"⊺",integers:"ℤ",Integral:"∫",intercal:"⊺",Intersection:"⋂",intlarhk:"⨗",intprod:"⨼",InvisibleComma:"⁣",InvisibleTimes:"⁢",IOcy:"Ё",iocy:"ё",Iogon:"Į",iogon:"į",Iopf:"𝕀",iopf:"𝕚",Iota:"Ι",iota:"ι",iprod:"⨼",iquest:"¿",Iscr:"ℐ",iscr:"𝒾",isin:"∈",isindot:"⋵",isinE:"⋹",isins:"⋴",isinsv:"⋳",isinv:"∈",it:"⁢",Itilde:"Ĩ",itilde:"ĩ",Iukcy:"І",iukcy:"і",Iuml:"Ï",iuml:"ï",Jcirc:"Ĵ",jcirc:"ĵ",Jcy:"Й",jcy:"й",Jfr:"𝔍",jfr:"𝔧",jmath:"ȷ",Jopf:"𝕁",jopf:"𝕛",Jscr:"𝒥",jscr:"𝒿",Jsercy:"Ј",jsercy:"ј",Jukcy:"Є",jukcy:"є",Kappa:"Κ",kappa:"κ",kappav:"ϰ",Kcedil:"Ķ",kcedil:"ķ",Kcy:"К",kcy:"к",Kfr:"𝔎",kfr:"𝔨",kgreen:"ĸ",KHcy:"Х",khcy:"х",KJcy:"Ќ",kjcy:"ќ",Kopf:"𝕂",kopf:"𝕜",Kscr:"𝒦",kscr:"𝓀",lAarr:"⇚",Lacute:"Ĺ",lacute:"ĺ",laemptyv:"⦴",lagran:"ℒ",Lambda:"Λ",lambda:"λ",Lang:"⟪",lang:"⟨",langd:"⦑",langle:"⟨",lap:"⪅",Laplacetrf:"ℒ",laquo:"«",Larr:"↞",lArr:"⇐",larr:"←",larrb:"⇤",larrbfs:"⤟",larrfs:"⤝",larrhk:"↩",larrlp:"↫",larrpl:"⤹",larrsim:"⥳",larrtl:"↢",lat:"⪫",lAtail:"⤛",latail:"⤙",late:"⪭",lates:"⪭︀",lBarr:"⤎",lbarr:"⤌",lbbrk:"❲",lbrace:"{",lbrack:"[",lbrke:"⦋",lbrksld:"⦏",lbrkslu:"⦍",Lcaron:"Ľ",lcaron:"ľ",Lcedil:"Ļ",lcedil:"ļ",lceil:"⌈",lcub:"{",Lcy:"Л",lcy:"л",ldca:"⤶",ldquo:"“",ldquor:"„",ldrdhar:"⥧",ldrushar:"⥋",ldsh:"↲",lE:"≦",le:"≤",LeftAngleBracket:"⟨",LeftArrow:"←",Leftarrow:"⇐",leftarrow:"←",LeftArrowBar:"⇤",LeftArrowRightArrow:"⇆",leftarrowtail:"↢",LeftCeiling:"⌈",LeftDoubleBracket:"⟦",LeftDownTeeVector:"⥡",LeftDownVector:"⇃",LeftDownVectorBar:"⥙",LeftFloor:"⌊",leftharpoondown:"↽",leftharpoonup:"↼",leftleftarrows:"⇇",LeftRightArrow:"↔",Leftrightarrow:"⇔",leftrightarrow:"↔",leftrightarrows:"⇆",leftrightharpoons:"⇋",leftrightsquigarrow:"↭",LeftRightVector:"⥎",LeftTee:"⊣",LeftTeeArrow:"↤",LeftTeeVector:"⥚",leftthreetimes:"⋋",LeftTriangle:"⊲",LeftTriangleBar:"⧏",LeftTriangleEqual:"⊴",LeftUpDownVector:"⥑",LeftUpTeeVector:"⥠",LeftUpVector:"↿",LeftUpVectorBar:"⥘",LeftVector:"↼",LeftVectorBar:"⥒",lEg:"⪋",leg:"⋚",leq:"≤",leqq:"≦",leqslant:"⩽",les:"⩽",lescc:"⪨",lesdot:"⩿",lesdoto:"⪁",lesdotor:"⪃",lesg:"⋚︀",lesges:"⪓",lessapprox:"⪅",lessdot:"⋖",lesseqgtr:"⋚",lesseqqgtr:"⪋",LessEqualGreater:"⋚",LessFullEqual:"≦",LessGreater:"≶",lessgtr:"≶",LessLess:"⪡",lesssim:"≲",LessSlantEqual:"⩽",LessTilde:"≲",lfisht:"⥼",lfloor:"⌊",Lfr:"𝔏",lfr:"𝔩",lg:"≶",lgE:"⪑",lHar:"⥢",lhard:"↽",lharu:"↼",lharul:"⥪",lhblk:"▄",LJcy:"Љ",ljcy:"љ",Ll:"⋘",ll:"≪",llarr:"⇇",llcorner:"⌞",Lleftarrow:"⇚",llhard:"⥫",lltri:"◺",Lmidot:"Ŀ",lmidot:"ŀ",lmoust:"⎰",lmoustache:"⎰",lnap:"⪉",lnapprox:"⪉",lnE:"≨",lne:"⪇",lneq:"⪇",lneqq:"≨",lnsim:"⋦",loang:"⟬",loarr:"⇽",lobrk:"⟦",LongLeftArrow:"⟵",Longleftarrow:"⟸",longleftarrow:"⟵",LongLeftRightArrow:"⟷",Longleftrightarrow:"⟺",longleftrightarrow:"⟷",longmapsto:"⟼",LongRightArrow:"⟶",Longrightarrow:"⟹",longrightarrow:"⟶",looparrowleft:"↫",looparrowright:"↬",lopar:"⦅",Lopf:"𝕃",lopf:"𝕝",loplus:"⨭",lotimes:"⨴",lowast:"∗",lowbar:"_",LowerLeftArrow:"↙",LowerRightArrow:"↘",loz:"◊",lozenge:"◊",lozf:"⧫",lpar:"(",lparlt:"⦓",lrarr:"⇆",lrcorner:"⌟",lrhar:"⇋",lrhard:"⥭",lrm:"‎",lrtri:"⊿",lsaquo:"‹",Lscr:"ℒ",lscr:"𝓁",Lsh:"↰",lsh:"↰",lsim:"≲",lsime:"⪍",lsimg:"⪏",lsqb:"[",lsquo:"‘",lsquor:"‚",Lstrok:"Ł",lstrok:"ł",LT:"<",Lt:"≪",lt:"<",ltcc:"⪦",ltcir:"⩹",ltdot:"⋖",lthree:"⋋",ltimes:"⋉",ltlarr:"⥶",ltquest:"⩻",ltri:"◃",ltrie:"⊴",ltrif:"◂",ltrPar:"⦖",lurdshar:"⥊",luruhar:"⥦",lvertneqq:"≨︀",lvnE:"≨︀",macr:"¯",male:"♂",malt:"✠",maltese:"✠",Map:"⤅",map:"↦",mapsto:"↦",mapstodown:"↧",mapstoleft:"↤",mapstoup:"↥",marker:"▮",mcomma:"⨩",Mcy:"М",mcy:"м",mdash:"—",mDDot:"∺",measuredangle:"∡",MediumSpace:" ",Mellintrf:"ℳ",Mfr:"𝔐",mfr:"𝔪",mho:"℧",micro:"µ",mid:"∣",midast:"*",midcir:"⫰",middot:"·",minus:"−",minusb:"⊟",minusd:"∸",minusdu:"⨪",MinusPlus:"∓",mlcp:"⫛",mldr:"…",mnplus:"∓",models:"⊧",Mopf:"𝕄",mopf:"𝕞",mp:"∓",Mscr:"ℳ",mscr:"𝓂",mstpos:"∾",Mu:"Μ",mu:"μ",multimap:"⊸",mumap:"⊸",nabla:"∇",Nacute:"Ń",nacute:"ń",nang:"∠⃒",nap:"≉",napE:"⩰̸",napid:"≋̸",napos:"ʼn",napprox:"≉",natur:"♮",natural:"♮",naturals:"ℕ",nbsp:" ",nbump:"≎̸",nbumpe:"≏̸",ncap:"⩃",Ncaron:"Ň",ncaron:"ň",Ncedil:"Ņ",ncedil:"ņ",ncong:"≇",ncongdot:"⩭̸",ncup:"⩂",Ncy:"Н",ncy:"н",ndash:"–",ne:"≠",nearhk:"⤤",neArr:"⇗",nearr:"↗",nearrow:"↗",nedot:"≐̸",NegativeMediumSpace:"​",NegativeThickSpace:"​",NegativeThinSpace:"​",NegativeVeryThinSpace:"​",nequiv:"≢",nesear:"⤨",nesim:"≂̸",NestedGreaterGreater:"≫",NestedLessLess:"≪",NewLine:"\n",nexist:"∄",nexists:"∄",Nfr:"𝔑",nfr:"𝔫",ngE:"≧̸",nge:"≱",ngeq:"≱",ngeqq:"≧̸",ngeqslant:"⩾̸",nges:"⩾̸",nGg:"⋙̸",ngsim:"≵",nGt:"≫⃒",ngt:"≯",ngtr:"≯",nGtv:"≫̸",nhArr:"⇎",nharr:"↮",nhpar:"⫲",ni:"∋",nis:"⋼",nisd:"⋺",niv:"∋",NJcy:"Њ",njcy:"њ",nlArr:"⇍",nlarr:"↚",nldr:"‥",nlE:"≦̸",nle:"≰",nLeftarrow:"⇍",nleftarrow:"↚",nLeftrightarrow:"⇎",nleftrightarrow:"↮",nleq:"≰",nleqq:"≦̸",nleqslant:"⩽̸",nles:"⩽̸",nless:"≮",nLl:"⋘̸",nlsim:"≴",nLt:"≪⃒",nlt:"≮",nltri:"⋪",nltrie:"⋬",nLtv:"≪̸",nmid:"∤",NoBreak:"⁠",NonBreakingSpace:" ",Nopf:"ℕ",nopf:"𝕟",Not:"⫬",not:"¬",NotCongruent:"≢",NotCupCap:"≭",NotDoubleVerticalBar:"∦",NotElement:"∉",NotEqual:"≠",NotEqualTilde:"≂̸",NotExists:"∄",NotGreater:"≯",NotGreaterEqual:"≱",NotGreaterFullEqual:"≧̸",NotGreaterGreater:"≫̸",NotGreaterLess:"≹",NotGreaterSlantEqual:"⩾̸",NotGreaterTilde:"≵",NotHumpDownHump:"≎̸",NotHumpEqual:"≏̸",notin:"∉",notindot:"⋵̸",notinE:"⋹̸",notinva:"∉",notinvb:"⋷",notinvc:"⋶",NotLeftTriangle:"⋪",NotLeftTriangleBar:"⧏̸",NotLeftTriangleEqual:"⋬",NotLess:"≮",NotLessEqual:"≰",NotLessGreater:"≸",NotLessLess:"≪̸",NotLessSlantEqual:"⩽̸",NotLessTilde:"≴",NotNestedGreaterGreater:"⪢̸",NotNestedLessLess:"⪡̸",notni:"∌",notniva:"∌",notnivb:"⋾",notnivc:"⋽",NotPrecedes:"⊀",NotPrecedesEqual:"⪯̸",NotPrecedesSlantEqual:"⋠",NotReverseElement:"∌",NotRightTriangle:"⋫",NotRightTriangleBar:"⧐̸",NotRightTriangleEqual:"⋭",NotSquareSubset:"⊏̸",NotSquareSubsetEqual:"⋢",NotSquareSuperset:"⊐̸",NotSquareSupersetEqual:"⋣",NotSubset:"⊂⃒",NotSubsetEqual:"⊈",NotSucceeds:"⊁",NotSucceedsEqual:"⪰̸",NotSucceedsSlantEqual:"⋡",NotSucceedsTilde:"≿̸",NotSuperset:"⊃⃒",NotSupersetEqual:"⊉",NotTilde:"≁",NotTildeEqual:"≄",NotTildeFullEqual:"≇",NotTildeTilde:"≉",NotVerticalBar:"∤",npar:"∦",nparallel:"∦",nparsl:"⫽⃥",npart:"∂̸",npolint:"⨔",npr:"⊀",nprcue:"⋠",npre:"⪯̸",nprec:"⊀",npreceq:"⪯̸",nrArr:"⇏",nrarr:"↛",nrarrc:"⤳̸",nrarrw:"↝̸",nRightarrow:"⇏",nrightarrow:"↛",nrtri:"⋫",nrtrie:"⋭",nsc:"⊁",nsccue:"⋡",nsce:"⪰̸",Nscr:"𝒩",nscr:"𝓃",nshortmid:"∤",nshortparallel:"∦",nsim:"≁",nsime:"≄",nsimeq:"≄",nsmid:"∤",nspar:"∦",nsqsube:"⋢",nsqsupe:"⋣",nsub:"⊄",nsubE:"⫅̸",nsube:"⊈",nsubset:"⊂⃒",nsubseteq:"⊈",nsubseteqq:"⫅̸",nsucc:"⊁",nsucceq:"⪰̸",nsup:"⊅",nsupE:"⫆̸",nsupe:"⊉",nsupset:"⊃⃒",nsupseteq:"⊉",nsupseteqq:"⫆̸",ntgl:"≹",Ntilde:"Ñ",ntilde:"ñ",ntlg:"≸",ntriangleleft:"⋪",ntrianglelefteq:"⋬",ntriangleright:"⋫",ntrianglerighteq:"⋭",Nu:"Ν",nu:"ν",num:"#",numero:"№",numsp:" ",nvap:"≍⃒",nVDash:"⊯",nVdash:"⊮",nvDash:"⊭",nvdash:"⊬",nvge:"≥⃒",nvgt:">⃒",nvHarr:"⤄",nvinfin:"⧞",nvlArr:"⤂",nvle:"≤⃒",nvlt:"<⃒",nvltrie:"⊴⃒",nvrArr:"⤃",nvrtrie:"⊵⃒",nvsim:"∼⃒",nwarhk:"⤣",nwArr:"⇖",nwarr:"↖",nwarrow:"↖",nwnear:"⤧",Oacute:"Ó",oacute:"ó",oast:"⊛",ocir:"⊚",Ocirc:"Ô",ocirc:"ô",Ocy:"О",ocy:"о",odash:"⊝",Odblac:"Ő",odblac:"ő",odiv:"⨸",odot:"⊙",odsold:"⦼",OElig:"Œ",oelig:"œ",ofcir:"⦿",Ofr:"𝔒",ofr:"𝔬",ogon:"˛",Ograve:"Ò",ograve:"ò",ogt:"⧁",ohbar:"⦵",ohm:"Ω",oint:"∮",olarr:"↺",olcir:"⦾",olcross:"⦻",oline:"‾",olt:"⧀",Omacr:"Ō",omacr:"ō",Omega:"Ω",omega:"ω",Omicron:"Ο",omicron:"ο",omid:"⦶",ominus:"⊖",Oopf:"𝕆",oopf:"𝕠",opar:"⦷",OpenCurlyDoubleQuote:"“",OpenCurlyQuote:"‘",operp:"⦹",oplus:"⊕",Or:"⩔",or:"∨",orarr:"↻",ord:"⩝",order:"ℴ",orderof:"ℴ",ordf:"ª",ordm:"º",origof:"⊶",oror:"⩖",orslope:"⩗",orv:"⩛",oS:"Ⓢ",Oscr:"𝒪",oscr:"ℴ",Oslash:"Ø",oslash:"ø",osol:"⊘",Otilde:"Õ",otilde:"õ",Otimes:"⨷",otimes:"⊗",otimesas:"⨶",Ouml:"Ö",ouml:"ö",ovbar:"⌽",OverBar:"‾",OverBrace:"⏞",OverBracket:"⎴",OverParenthesis:"⏜",par:"∥",para:"¶",parallel:"∥",parsim:"⫳",parsl:"⫽",part:"∂",PartialD:"∂",Pcy:"П",pcy:"п",percnt:"%",period:".",permil:"‰",perp:"⊥",pertenk:"‱",Pfr:"𝔓",pfr:"𝔭",Phi:"Φ",phi:"φ",phiv:"ϕ",phmmat:"ℳ",phone:"☎",Pi:"Π",pi:"π",pitchfork:"⋔",piv:"ϖ",planck:"ℏ",planckh:"ℎ",plankv:"ℏ",plus:"+",plusacir:"⨣",plusb:"⊞",pluscir:"⨢",plusdo:"∔",plusdu:"⨥",pluse:"⩲",PlusMinus:"±",plusmn:"±",plussim:"⨦",plustwo:"⨧",pm:"±",Poincareplane:"ℌ",pointint:"⨕",Popf:"ℙ",popf:"𝕡",pound:"£",Pr:"⪻",pr:"≺",prap:"⪷",prcue:"≼",prE:"⪳",pre:"⪯",prec:"≺",precapprox:"⪷",preccurlyeq:"≼",Precedes:"≺",PrecedesEqual:"⪯",PrecedesSlantEqual:"≼",PrecedesTilde:"≾",preceq:"⪯",precnapprox:"⪹",precneqq:"⪵",precnsim:"⋨",precsim:"≾",Prime:"″",prime:"′",primes:"ℙ",prnap:"⪹",prnE:"⪵",prnsim:"⋨",prod:"∏",Product:"∏",profalar:"⌮",profline:"⌒",profsurf:"⌓",prop:"∝",Proportion:"∷",Proportional:"∝",propto:"∝",prsim:"≾",prurel:"⊰",Pscr:"𝒫",pscr:"𝓅",Psi:"Ψ",psi:"ψ",puncsp:" ",Qfr:"𝔔",qfr:"𝔮",qint:"⨌",Qopf:"ℚ",qopf:"𝕢",qprime:"⁗",Qscr:"𝒬",qscr:"𝓆",quaternions:"ℍ",quatint:"⨖",quest:"?",questeq:"≟",QUOT:'"',quot:'"',rAarr:"⇛",race:"∽̱",Racute:"Ŕ",racute:"ŕ",radic:"√",raemptyv:"⦳",Rang:"⟫",rang:"⟩",rangd:"⦒",range:"⦥",rangle:"⟩",raquo:"»",Rarr:"↠",rArr:"⇒",rarr:"→",rarrap:"⥵",rarrb:"⇥",rarrbfs:"⤠",rarrc:"⤳",rarrfs:"⤞",rarrhk:"↪",rarrlp:"↬",rarrpl:"⥅",rarrsim:"⥴",Rarrtl:"⤖",rarrtl:"↣",rarrw:"↝",rAtail:"⤜",ratail:"⤚",ratio:"∶",rationals:"ℚ",RBarr:"⤐",rBarr:"⤏",rbarr:"⤍",rbbrk:"❳",rbrace:"}",rbrack:"]",rbrke:"⦌",rbrksld:"⦎",rbrkslu:"⦐",Rcaron:"Ř",rcaron:"ř",Rcedil:"Ŗ",rcedil:"ŗ",rceil:"⌉",rcub:"}",Rcy:"Р",rcy:"р",rdca:"⤷",rdldhar:"⥩",rdquo:"”",rdquor:"”",rdsh:"↳",Re:"ℜ",real:"ℜ",realine:"ℛ",realpart:"ℜ",reals:"ℝ",rect:"▭",REG:"®",reg:"®",ReverseElement:"∋",ReverseEquilibrium:"⇋",ReverseUpEquilibrium:"⥯",rfisht:"⥽",rfloor:"⌋",Rfr:"ℜ",rfr:"𝔯",rHar:"⥤",rhard:"⇁",rharu:"⇀",rharul:"⥬",Rho:"Ρ",rho:"ρ",rhov:"ϱ",RightAngleBracket:"⟩",RightArrow:"→",Rightarrow:"⇒",rightarrow:"→",RightArrowBar:"⇥",RightArrowLeftArrow:"⇄",rightarrowtail:"↣",RightCeiling:"⌉",RightDoubleBracket:"⟧",RightDownTeeVector:"⥝",RightDownVector:"⇂",RightDownVectorBar:"⥕",RightFloor:"⌋",rightharpoondown:"⇁",rightharpoonup:"⇀",rightleftarrows:"⇄",rightleftharpoons:"⇌",rightrightarrows:"⇉",rightsquigarrow:"↝",RightTee:"⊢",RightTeeArrow:"↦",RightTeeVector:"⥛",rightthreetimes:"⋌",RightTriangle:"⊳",RightTriangleBar:"⧐",RightTriangleEqual:"⊵",RightUpDownVector:"⥏",RightUpTeeVector:"⥜",RightUpVector:"↾",RightUpVectorBar:"⥔",RightVector:"⇀",RightVectorBar:"⥓",ring:"˚",risingdotseq:"≓",rlarr:"⇄",rlhar:"⇌",rlm:"‏",rmoust:"⎱",rmoustache:"⎱",rnmid:"⫮",roang:"⟭",roarr:"⇾",robrk:"⟧",ropar:"⦆",Ropf:"ℝ",ropf:"𝕣",roplus:"⨮",rotimes:"⨵",RoundImplies:"⥰",rpar:")",rpargt:"⦔",rppolint:"⨒",rrarr:"⇉",Rrightarrow:"⇛",rsaquo:"›",Rscr:"ℛ",rscr:"𝓇",Rsh:"↱",rsh:"↱",rsqb:"]",rsquo:"’",rsquor:"’",rthree:"⋌",rtimes:"⋊",rtri:"▹",rtrie:"⊵",rtrif:"▸",rtriltri:"⧎",RuleDelayed:"⧴",ruluhar:"⥨",rx:"℞",Sacute:"Ś",sacute:"ś",sbquo:"‚",Sc:"⪼",sc:"≻",scap:"⪸",Scaron:"Š",scaron:"š",sccue:"≽",scE:"⪴",sce:"⪰",Scedil:"Ş",scedil:"ş",Scirc:"Ŝ",scirc:"ŝ",scnap:"⪺",scnE:"⪶",scnsim:"⋩",scpolint:"⨓",scsim:"≿",Scy:"С",scy:"с",sdot:"⋅",sdotb:"⊡",sdote:"⩦",searhk:"⤥",seArr:"⇘",searr:"↘",searrow:"↘",sect:"§",semi:";",seswar:"⤩",setminus:"∖",setmn:"∖",sext:"✶",Sfr:"𝔖",sfr:"𝔰",sfrown:"⌢",sharp:"♯",SHCHcy:"Щ",shchcy:"щ",SHcy:"Ш",shcy:"ш",ShortDownArrow:"↓",ShortLeftArrow:"←",shortmid:"∣",shortparallel:"∥",ShortRightArrow:"→",ShortUpArrow:"↑",shy:"­",Sigma:"Σ",sigma:"σ",sigmaf:"ς",sigmav:"ς",sim:"∼",simdot:"⩪",sime:"≃",simeq:"≃",simg:"⪞",simgE:"⪠",siml:"⪝",simlE:"⪟",simne:"≆",simplus:"⨤",simrarr:"⥲",slarr:"←",SmallCircle:"∘",smallsetminus:"∖",smashp:"⨳",smeparsl:"⧤",smid:"∣",smile:"⌣",smt:"⪪",smte:"⪬",smtes:"⪬︀",SOFTcy:"Ь",softcy:"ь",sol:"/",solb:"⧄",solbar:"⌿",Sopf:"𝕊",sopf:"𝕤",spades:"♠",spadesuit:"♠",spar:"∥",sqcap:"⊓",sqcaps:"⊓︀",sqcup:"⊔",sqcups:"⊔︀",Sqrt:"√",sqsub:"⊏",sqsube:"⊑",sqsubset:"⊏",sqsubseteq:"⊑",sqsup:"⊐",sqsupe:"⊒",sqsupset:"⊐",sqsupseteq:"⊒",squ:"□",Square:"□",square:"□",SquareIntersection:"⊓",SquareSubset:"⊏",SquareSubsetEqual:"⊑",SquareSuperset:"⊐",SquareSupersetEqual:"⊒",SquareUnion:"⊔",squarf:"▪",squf:"▪",srarr:"→",Sscr:"𝒮",sscr:"𝓈",ssetmn:"∖",ssmile:"⌣",sstarf:"⋆",Star:"⋆",star:"☆",starf:"★",straightepsilon:"ϵ",straightphi:"ϕ",strns:"¯",Sub:"⋐",sub:"⊂",subdot:"⪽",subE:"⫅",sube:"⊆",subedot:"⫃",submult:"⫁",subnE:"⫋",subne:"⊊",subplus:"⪿",subrarr:"⥹",Subset:"⋐",subset:"⊂",subseteq:"⊆",subseteqq:"⫅",SubsetEqual:"⊆",subsetneq:"⊊",subsetneqq:"⫋",subsim:"⫇",subsub:"⫕",subsup:"⫓",succ:"≻",succapprox:"⪸",succcurlyeq:"≽",Succeeds:"≻",SucceedsEqual:"⪰",SucceedsSlantEqual:"≽",SucceedsTilde:"≿",succeq:"⪰",succnapprox:"⪺",succneqq:"⪶",succnsim:"⋩",succsim:"≿",SuchThat:"∋",Sum:"∑",sum:"∑",sung:"♪",Sup:"⋑",sup:"⊃",sup1:"¹",sup2:"²",sup3:"³",supdot:"⪾",supdsub:"⫘",supE:"⫆",supe:"⊇",supedot:"⫄",Superset:"⊃",SupersetEqual:"⊇",suphsol:"⟉",suphsub:"⫗",suplarr:"⥻",supmult:"⫂",supnE:"⫌",supne:"⊋",supplus:"⫀",Supset:"⋑",supset:"⊃",supseteq:"⊇",supseteqq:"⫆",supsetneq:"⊋",supsetneqq:"⫌",supsim:"⫈",supsub:"⫔",supsup:"⫖",swarhk:"⤦",swArr:"⇙",swarr:"↙",swarrow:"↙",swnwar:"⤪",szlig:"ß",Tab:"\t",target:"⌖",Tau:"Τ",tau:"τ",tbrk:"⎴",Tcaron:"Ť",tcaron:"ť",Tcedil:"Ţ",tcedil:"ţ",Tcy:"Т",tcy:"т",tdot:"⃛",telrec:"⌕",Tfr:"𝔗",tfr:"𝔱",there4:"∴",Therefore:"∴",therefore:"∴",Theta:"Θ",theta:"θ",thetasym:"ϑ",thetav:"ϑ",thickapprox:"≈",thicksim:"∼",ThickSpace:"  ",thinsp:" ",ThinSpace:" ",thkap:"≈",thksim:"∼",THORN:"Þ",thorn:"þ",Tilde:"∼",tilde:"˜",TildeEqual:"≃",TildeFullEqual:"≅",TildeTilde:"≈",times:"×",timesb:"⊠",timesbar:"⨱",timesd:"⨰",tint:"∭",toea:"⤨",top:"⊤",topbot:"⌶",topcir:"⫱",Topf:"𝕋",topf:"𝕥",topfork:"⫚",tosa:"⤩",tprime:"‴",TRADE:"™",trade:"™",triangle:"▵",triangledown:"▿",triangleleft:"◃",trianglelefteq:"⊴",triangleq:"≜",triangleright:"▹",trianglerighteq:"⊵",tridot:"◬",trie:"≜",triminus:"⨺",TripleDot:"⃛",triplus:"⨹",trisb:"⧍",tritime:"⨻",trpezium:"⏢",Tscr:"𝒯",tscr:"𝓉",TScy:"Ц",tscy:"ц",TSHcy:"Ћ",tshcy:"ћ",Tstrok:"Ŧ",tstrok:"ŧ",twixt:"≬",twoheadleftarrow:"↞",twoheadrightarrow:"↠",Uacute:"Ú",uacute:"ú",Uarr:"↟",uArr:"⇑",uarr:"↑",Uarrocir:"⥉",Ubrcy:"Ў",ubrcy:"ў",Ubreve:"Ŭ",ubreve:"ŭ",Ucirc:"Û",ucirc:"û",Ucy:"У",ucy:"у",udarr:"⇅",Udblac:"Ű",udblac:"ű",udhar:"⥮",ufisht:"⥾",Ufr:"𝔘",ufr:"𝔲",Ugrave:"Ù",ugrave:"ù",uHar:"⥣",uharl:"↿",uharr:"↾",uhblk:"▀",ulcorn:"⌜",ulcorner:"⌜",ulcrop:"⌏",ultri:"◸",Umacr:"Ū",umacr:"ū",uml:"¨",UnderBar:"_",UnderBrace:"⏟",UnderBracket:"⎵",UnderParenthesis:"⏝",Union:"⋃",UnionPlus:"⊎",Uogon:"Ų",uogon:"ų",Uopf:"𝕌",uopf:"𝕦",UpArrow:"↑",Uparrow:"⇑",uparrow:"↑",UpArrowBar:"⤒",UpArrowDownArrow:"⇅",UpDownArrow:"↕",Updownarrow:"⇕",updownarrow:"↕",UpEquilibrium:"⥮",upharpoonleft:"↿",upharpoonright:"↾",uplus:"⊎",UpperLeftArrow:"↖",UpperRightArrow:"↗",Upsi:"ϒ",upsi:"υ",upsih:"ϒ",Upsilon:"Υ",upsilon:"υ",UpTee:"⊥",UpTeeArrow:"↥",upuparrows:"⇈",urcorn:"⌝",urcorner:"⌝",urcrop:"⌎",Uring:"Ů",uring:"ů",urtri:"◹",Uscr:"𝒰",uscr:"𝓊",utdot:"⋰",Utilde:"Ũ",utilde:"ũ",utri:"▵",utrif:"▴",uuarr:"⇈",Uuml:"Ü",uuml:"ü",uwangle:"⦧",vangrt:"⦜",varepsilon:"ϵ",varkappa:"ϰ",varnothing:"∅",varphi:"ϕ",varpi:"ϖ",varpropto:"∝",vArr:"⇕",varr:"↕",varrho:"ϱ",varsigma:"ς",varsubsetneq:"⊊︀",varsubsetneqq:"⫋︀",varsupsetneq:"⊋︀",varsupsetneqq:"⫌︀",vartheta:"ϑ",vartriangleleft:"⊲",vartriangleright:"⊳",Vbar:"⫫",vBar:"⫨",vBarv:"⫩",Vcy:"В",vcy:"в",VDash:"⊫",Vdash:"⊩",vDash:"⊨",vdash:"⊢",Vdashl:"⫦",Vee:"⋁",vee:"∨",veebar:"⊻",veeeq:"≚",vellip:"⋮",Verbar:"‖",verbar:"|",Vert:"‖",vert:"|",VerticalBar:"∣",VerticalLine:"|",VerticalSeparator:"❘",VerticalTilde:"≀",VeryThinSpace:" ",Vfr:"𝔙",vfr:"𝔳",vltri:"⊲",vnsub:"⊂⃒",vnsup:"⊃⃒",Vopf:"𝕍",vopf:"𝕧",vprop:"∝",vrtri:"⊳",Vscr:"𝒱",vscr:"𝓋",vsubnE:"⫋︀",vsubne:"⊊︀",vsupnE:"⫌︀",vsupne:"⊋︀",Vvdash:"⊪",vzigzag:"⦚",Wcirc:"Ŵ",wcirc:"ŵ",wedbar:"⩟",Wedge:"⋀",wedge:"∧",wedgeq:"≙",weierp:"℘",Wfr:"𝔚",wfr:"𝔴",Wopf:"𝕎",wopf:"𝕨",wp:"℘",wr:"≀",wreath:"≀",Wscr:"𝒲",wscr:"𝓌",xcap:"⋂",xcirc:"◯",xcup:"⋃",xdtri:"▽",Xfr:"𝔛",xfr:"𝔵",xhArr:"⟺",xharr:"⟷",Xi:"Ξ",xi:"ξ",xlArr:"⟸",xlarr:"⟵",xmap:"⟼",xnis:"⋻",xodot:"⨀",Xopf:"𝕏",xopf:"𝕩",xoplus:"⨁",xotime:"⨂",xrArr:"⟹",xrarr:"⟶",Xscr:"𝒳",xscr:"𝓍",xsqcup:"⨆",xuplus:"⨄",xutri:"△",xvee:"⋁",xwedge:"⋀",Yacute:"Ý",yacute:"ý",YAcy:"Я",yacy:"я",Ycirc:"Ŷ",ycirc:"ŷ",Ycy:"Ы",ycy:"ы",yen:"¥",Yfr:"𝔜",yfr:"𝔶",YIcy:"Ї",yicy:"ї",Yopf:"𝕐",yopf:"𝕪",Yscr:"𝒴",yscr:"𝓎",YUcy:"Ю",yucy:"ю",Yuml:"Ÿ",yuml:"ÿ",Zacute:"Ź",zacute:"ź",Zcaron:"Ž",zcaron:"ž",Zcy:"З",zcy:"з",Zdot:"Ż",zdot:"ż",zeetrf:"ℨ",ZeroWidthSpace:"​",Zeta:"Ζ",zeta:"ζ",Zfr:"ℨ",zfr:"𝔷",ZHcy:"Ж",zhcy:"ж",zigrarr:"⇝",Zopf:"ℤ",zopf:"𝕫",Zscr:"𝒵",zscr:"𝓏",zwj:"‍",zwnj:"‌"}},function(e,t,n){"use strict";var r=n(419),o=n(27).unescapeMd;e.exports=function(e,t){var n,i,a,u=t,s=e.posMax;if(60===e.src.charCodeAt(t)){for(t++;t8&&n<14);)if(92===n&&t+11)break;if(41===n&&--i<0)break;t++}return u!==t&&(a=o(e.src.slice(u,t)),!!e.parser.validateLink(a)&&(e.linkContent=a,e.pos=t,!0))}},function(e,t,n){"use strict";var r=n(27).replaceEntities;e.exports=function(e){var t=r(e);try{t=decodeURI(t)}catch(e){}return encodeURI(t)}},function(e,t,n){"use strict";var r=n(27).unescapeMd;e.exports=function(e,t){var n,o=t,i=e.posMax,a=e.src.charCodeAt(t);if(34!==a&&39!==a&&40!==a)return!1;for(t++,40===a&&(a=41);t1?r-1:0),i=1;i1?t-1:0),r=1;r0?Array(e+1).join(" ")+t:t}).join("\n")}(0,(0,r.default)(a,null,2))||"{}",c.default.createElement("br",null)))}}]),t}(l.Component);t.default=p},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=c(n(4)),o=c(n(2)),i=c(n(3)),a=c(n(5)),u=c(n(6)),s=c(n(0)),l=n(7);c(n(1)),c(n(12));function c(e){return e&&e.__esModule?e:{default:e}}var f=function(e){function t(){var e,n,i,u;(0,o.default)(this,t);for(var s=arguments.length,l=Array(s),c=0;c=e.length?(this._t=void 0,o(1)):o(0,"keys"==t?n:"values"==t?e[n]:[n,e[n]])},"values"),i.Arguments=i.Array,r("keys"),r("values"),r("entries")},function(e,t){e.exports=function(){}},function(e,t){e.exports=function(e,t){return{value:t,done:!!e}}},function(e,t,n){"use strict";var r=n(159),o=n(95),i=n(97),a={};n(50)(a,n(19)("iterator"),function(){return this}),e.exports=function(e,t,n){e.prototype=r(a,{next:o(1,n)}),i(e,t+" Iterator")}},function(e,t,n){var r=n(40),o=n(36),i=n(96);e.exports=n(44)?Object.defineProperties:function(e,t){o(e);for(var n,a=i(t),u=a.length,s=0;u>s;)r.f(e,n=a[s++],t[n]);return e}},function(e,t,n){var r=n(71),o=n(115),i=n(455);e.exports=function(e){return function(t,n,a){var u,s=r(t),l=o(s.length),c=i(a,l);if(e&&n!=n){for(;l>c;)if((u=s[c++])!=u)return!0}else for(;l>c;c++)if((e||c in s)&&s[c]===n)return e||c||0;return!e&&-1}}},function(e,t,n){var r=n(160),o=Math.max,i=Math.min;e.exports=function(e,t){return(e=r(e))<0?o(e+t,0):i(e,t)}},function(e,t,n){var r=n(160),o=n(155);e.exports=function(e){return function(t,n){var i,a,u=String(o(t)),s=r(n),l=u.length;return s<0||s>=l?e?"":void 0:(i=u.charCodeAt(s))<55296||i>56319||s+1===l||(a=u.charCodeAt(s+1))<56320||a>57343?e?u.charAt(s):i:e?u.slice(s,s+2):a-56320+(i-55296<<10)+65536}}},function(e,t,n){var r=n(36),o=n(164);e.exports=n(15).getIterator=function(e){var t=o(e);if("function"!=typeof t)throw TypeError(e+" is not iterable!");return r(t.call(e))}},function(e,t,n){n(459),n(244),n(470),n(474),n(485),n(486),e.exports=n(60).Promise},function(e,t,n){"use strict";var r=n(166),o={};o[n(17)("toStringTag")]="z",o+""!="[object z]"&&n(73)(Object.prototype,"toString",function(){return"[object "+r(this)+"]"},!0)},function(e,t,n){e.exports=!n(100)&&!n(101)(function(){return 7!=Object.defineProperty(n(168)("div"),"a",{get:function(){return 7}}).a})},function(e,t,n){var r=n(74);e.exports=function(e,t){if(!r(e))return e;var n,o;if(t&&"function"==typeof(n=e.toString)&&!r(o=n.call(e)))return o;if("function"==typeof(n=e.valueOf)&&!r(o=n.call(e)))return o;if(!t&&"function"==typeof(n=e.toString)&&!r(o=n.call(e)))return o;throw TypeError("Can't convert object to primitive value")}},function(e,t,n){"use strict";var r=n(463),o=n(243),i=n(170),a={};n(58)(a,n(17)("iterator"),function(){return this}),e.exports=function(e,t,n){e.prototype=r(a,{next:o(1,n)}),i(e,t+" Iterator")}},function(e,t,n){var r=n(59),o=n(464),i=n(250),a=n(169)("IE_PROTO"),u=function(){},s=function(){var e,t=n(168)("iframe"),r=i.length;for(t.style.display="none",n(251).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write(" + diff --git a/examples/demo1/src/demo-frontend/src/js/demo-svc.js b/examples/demo1/src/demo-frontend/src/js/demo-svc.js new file mode 100755 index 0000000000000000000000000000000000000000..73968e7b1fa822f44b429e0f13f06a0d32d833fd --- /dev/null +++ b/examples/demo1/src/demo-frontend/src/js/demo-svc.js @@ -0,0 +1,380 @@ +// Import CSS +import 'material-design-icons/iconfont/material-icons.css'; +import 'ol/ol.css'; +import '../css/demo-svc.scss'; + +// Import module dependencies +import * as $ from 'jquery'; +import 'material-design-icons'; +import * as mdc from 'material-components-web'; + +import React from 'react'; +import ReactDOM from 'react-dom'; +import classNames from 'classnames'; +import Toolbar from '@material-ui/core/Toolbar'; + +// Import JS dependencies +import * as demoSvcRestApiClient from '../../../demo-client/js/src/index.js'; +import * as iperfTransitRestApiClient from '../../../iperf-proxy-client/js/src/index.js'; + +// Import images used in JS +import * as im1 from '../img/zone1-edge1-svc.jpg'; +import * as im2 from '../img/zone1-fog1-svc.jpg'; +import * as im3 from '../img/zone2-edge1-svc.jpg'; +import * as im4 from '../img/azone1-edge1-svc.jpg'; +import * as im5 from '../img/azone1-fog1-svc.jpg'; +import * as im6 from '../img/azone2-edge1-svc.jpg'; + +// Constants +const PAGE_STATUS = 'page-status-link'; +const PAGE_SETTINGS = 'page-settings-link'; + +const STATUS_OK = 'No Conflict'; +const STATUS_RA = 'Active Resolution Advisory'; + +const DEFAULT_REFRESH_INTERVAL_MS = 1000; + + +// Variables +var drawer; +var refreshIntervalTextfield; +var refreshInterval = DEFAULT_REFRESH_INTERVAL_MS; +var refreshIntervalTimer; +var mapLayerSelect; +var mapLayers = []; +var map; +var targetedUeNameDialogTextfield; +var iperfBwDialogTextfield; + + +// MEEP Controller REST API JS client +var basepath = 'http://' + location.host + location.pathname + 'v1/'; +console.log("basepath: " + basepath); + +demoSvcRestApiClient.ApiClient.instance.basePath = basepath.replace(/\/+$/, ''); +var ueStateApi = new demoSvcRestApiClient.UEStateApi(); +var edgeInfoApi = new demoSvcRestApiClient.EdgeAppInfoApi(); + +//iperfTransitRestApiClient.ApiClient.instance.basePath = "http://iperf-transit-iperf-transit-server/v1"; + +var iperfBasepath = basepath; +iperfBasepath = iperfBasepath.replace(/\/+$/, ''); +//find the path in the webbrowser to determine if its running in the cloud or edge +var subStr1 = iperfBasepath.split(":"); +var subStr2 = subStr1[2].split("/"); +var portApp = subStr2[0]; +iperfBasepath = iperfBasepath.replace(portApp, "30220"); +iperfTransitRestApiClient.ApiClient.instance.basePath = iperfBasepath; + +var iperfInfoApi = new iperfTransitRestApiClient.IperfAppInfoApi(); + +/** + * Callback function to receive the result of the edgeAppInfo operation. + * @callback module:api/EdgeInfoApi~getEdgeInfoCallback + * @param {String} error Error message, if any. + * @param {module:model/EdgeInfo} data The data returned by the service call. + * @param {String} response The complete HTTP response. + */ +function getEdgeInfoCb(error, data, response) { + console.log("Received getEdgeInfo response"); + + if (error != null) { + console.log(error); + } else { + console.log(data); + if (data != null) { + updateSvcInfo(data); + } + } +} + +function updateSvcInfo(data) { + $('#svc-info-name').text(data.svc); + $('#node-svc-info-name').text(data.name); + $('#node-svc-info-ip').text(data.ip); + var str = "img/" + data.name + ".jpg" + $('#demo-svc-app-pic').attr('src', str); +} + +function hideTrafficGenerator() { + $('#iperf-bw-tf-div').hide(); + $('#start-demo-iperf-button').hide(); + $('#stop-demo-iperf-button').hide(); +} + +function showTrafficGenerator() { + $('#iperf-bw-tf-div').show(); + $('#start-demo-iperf-button').show(); + $('#stop-demo-iperf-button').show(); +} + + +/** + * Callback function to receive the result of the getUeState operation. + * @callback module:api/UeStateApi~getUeStateCallback + * @param {String} error Error message, if any. + * @param {module:model/UeState} data The data returned by the service call. + * @param {String} response The complete HTTP response. + */ +function getUeStateCb(error, data, response) { + console.log("Received getUeState response"); + + if (error != null) { + console.log(error); + } else { + console.log(data); + if (data != null) { + updateGameStats(data); + } + } +} + +/** + * Callback function to receive the result of the createUeState operation. + * @callback module:api/UeStateApi~createUeStateCallback + * @param {String} error Error message, if any. + * @param {module:model/UeState} data The data returned by the service call. + * @param {String} response The complete HTTP response. + */ +function createUeStateCb(error, data, response) { + console.log("Received createUeState response"); + + if (error != null) { + console.log(error); + } else { + console.log("creation successful"); + } +} + +function genTrafficCb(error, data, response) { + console.log("Received genTraffic response"); + + if (error != null) { + console.log(error); + } else { + console.log("genTraffic successful"); + } +} + +function initTrafficBwCb(error, data, response) { + console.log("Received initTrafficBwInfo response"); + + if (error != null) { + console.log(error); + iperfBwDialogTextfield.value = ""; + } else { + console.log(data); + if (data != null) { + iperfBwDialogTextfield.value = data.trafficBw; + } else { + iperfBwDialogTextfield.value = ""; + } + } +} + +function demoIperfOnButtonCb(error, data, response) { + console.log("Received iperf ON response"); + + if (error != null) { + console.log(error); + } else { + console.log("response successful"); + } +} +function demoIperfOffButtonCb(error, data, response) { + console.log("Received iperf OFF response"); + + if (error != null) { + console.log(error); + } else { + console.log("response successful"); + } +} + +function updateGameStats(data) { + $('#demo-svc-info-duration').text(data.duration); + showTrafficGenerator(); +} + +// Retrieve current scenario status +function refreshGameInfo() { + console.log("Sending regular update request"); + edgeInfoApi.getEdgeInfo(getEdgeInfoCb); + ueStateApi.getUeState(targetedUeNameDialogTextfield.value, getUeStateCb); +} + +// Initialize UI +function initializeUI() { + + // Set service information + $('#svc-info-name').text("N/A"); + $('#node-svc-info-name').text("N/A"); + $('#node-svc-info-ip').text("N/A"); + $('#poa-info-name').text("N/A"); + $('#demo-svc-info-duration').text("N/A"); + + targetedUeNameDialogTextfield = new mdc.textField.MDCTextField(document.querySelector('#targeted-ue-name-tf-div')); + //setting a default value for now + targetedUeNameDialogTextfield.value = "ue2-ext"; + targetedUeNameDialogTextfield.valid = true; + $('#targeted-ue-name-tf-div').hide(); + iperfBwDialogTextfield = new mdc.textField.MDCTextField(document.querySelector('#iperf-bw-tf-div')); + iperfBwDialogTextfield.valid = true; + + ueStateApi.getUeState(targetedUeNameDialogTextfield.value, initTrafficBwCb); + hideTrafficGenerator(); + + // START COUNTER BUTTON + $("#start-demo-svc-button").on("click", function () { + console.log("start-demo-svc-button clicked"); + ueStateApi.createUeState(targetedUeNameDialogTextfield.value, createUeStateCb); + showTrafficGenerator + }); + + // START TRAFFIC BUTTON + $("#start-demo-iperf-button").on("click", function () { + console.log("start-demo-iperf-button clicked"); + + var ueState = new demoSvcRestApiClient.UeState(); + ueState['trafficBw'] = parseInt(iperfBwDialogTextfield.value); + //we don't care about reporting other values + ueStateApi.updateUeState(targetedUeNameDialogTextfield.value, ueState, genTrafficCb); + + var iperfInfo = new iperfTransitRestApiClient.IperfInfo(); + + iperfInfo['name'] = targetedUeNameDialogTextfield.value; + + if (portApp != "31111") { + iperfInfo.app = "31223" + } else { + iperfInfo.app = "31222" + } + + iperfInfo.throughput = iperfBwDialogTextfield.value; + + iperfInfoApi.handleIperfInfo(iperfInfo, demoIperfOnButtonCb); + }); + // STOP TRAFFIC BUTTON + $("#stop-demo-iperf-button").on("click", function () { + console.log("stop-demo-iperf-button clicked"); + + iperfBwDialogTextfield.value = "" + + var ueState = new demoSvcRestApiClient.UeState(); + ueState['trafficBw'] = 0; + ueStateApi.updateUeState(targetedUeNameDialogTextfield.value, ueState, genTrafficCb); + + var iperfInfo = new iperfTransitRestApiClient.IperfInfo(); + + iperfInfo['name'] = targetedUeNameDialogTextfield.value; + + if (portApp != "31111") { + iperfInfo.app = "31223" + } else { + iperfInfo.app = "31222" + } + + iperfInfo.throughput = "0" + + iperfInfoApi.handleIperfInfo(iperfInfo, demoIperfOffButtonCb); + }); + + + + // Set Status page + setMainContent(PAGE_STATUS); + + // Retrieve Deployed scenario status + refreshGameInfo(); + + // Set default Drone info refresh interval + refreshIntervalTextfield.value = DEFAULT_REFRESH_INTERVAL_MS; + startAutomaticRefresh(); +} + +// Set main page content +function setMainContent(targetId) { + console.log("Setting main page content to: %s", targetId); + $('.idcc-page').hide(); + if (targetId == PAGE_STATUS) { + $('#page-status').show(); + } else if (targetId == PAGE_SETTINGS) { + $('#page-settings').show(); + + // Refresh form field values here to update UI + refreshIntervalTextfield.value = refreshIntervalTextfield.value; + mapLayerSelect.value = mapLayerSelect.value; + } +} + +// Start automatic visualization updates +function startAutomaticRefresh() { + console.log("Starting drone information table automatic refresh"); + var value = refreshIntervalTextfield.value; + if (isNaN(value) || value < 500 || value > 60000) { + console.log("Invalid refresh interval: ", value); + clearInterval(refreshIntervalTimer); + refreshIntervalTextfield.valid = false; + } else { + console.log("Setting refresh interval: ", value); + clearInterval(refreshIntervalTimer); + refreshIntervalTimer = setInterval(refreshGameInfo, value); + refreshIntervalTextfield.valid = true; + } +} + +// Stop automatic visualization updates +function stopAutomaticRefresh() { + console.log("Stopping automatic refresh"); + clearInterval(refreshIntervalTimer); +} + +// Update Map layer visualization +function setMapLayer(style) { + console.log("Setting map style to: " + style); + for (var i = 0; i < mapLayers.length; ++i) { + if (mapLayers[i].type == 'TILE') { + mapLayers[i].setVisible(MAP_STYLES[i] === style); + } + } +} + + +// Initialize variables and listeners when document ready +$(document).ready(function () { + + // Initialize variables + drawer = new mdc.drawer.MDCPersistentDrawer(document.querySelector('#main-drawer')); + refreshIntervalTextfield = new mdc.textField.MDCTextField(document.querySelector('#refresh-interval-tf-div')); + mapLayerSelect = new mdc.select.MDCSelect(document.querySelector('#map-layer-select-div')); + + // Register event listeners + $('.idcc-toolbar-menu').on('click', function () { + drawer.open = !drawer.open; + }); + + const activatedClass = 'mdc-list-item--selected'; + $('.mdc-drawer__drawer').on('click', function (event) { + var target = event.target; + while (target && !$(target).hasClass('mdc-list-item')) { + target = target.parentElement; + } + if (target) { + $('.' + activatedClass).removeClass(activatedClass); + $(event.target).addClass(activatedClass); + setMainContent(target.id); + } + }); + + $("#refresh-interval-tf").change(function () { + startAutomaticRefresh(); + }); + + $("#map-layer-select").change(function () { + setMapLayer(this.value); + }); + + // Initialize UI + initializeUI(); +}); + diff --git a/examples/demo1/src/demo-frontend/webpack.config.js b/examples/demo1/src/demo-frontend/webpack.config.js new file mode 100644 index 0000000000000000000000000000000000000000..343cb13f49d40163e2ed42fed19f330f8420848b --- /dev/null +++ b/examples/demo1/src/demo-frontend/webpack.config.js @@ -0,0 +1,104 @@ +const path = require('path'); +const ExtractTextPlugin = require("extract-text-webpack-plugin"); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +var extractPlugin = new ExtractTextPlugin({ + filename: 'bundle.css' +}); +var htmlPlugin = new HtmlWebpackPlugin({ + template: 'src/index.html' +}) + +module.exports = { + mode: 'development', + entry: [ + './src/js/demo-svc.js' + ], + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, "dist"), + }, + node: { + fs: 'empty' + }, + module: { + rules: [ + { + parser: { + amd: false + } + }, + { + test: /\.jsx?$/, + exclude: /node_modules/, + use: [ + { + loader: 'babel-loader', + options: { + presets: [require.resolve('babel-preset-react')] + } + }] + }, + { + test: /\.scss$/, + use: extractPlugin.extract({ + use: [ + { + loader: 'css-loader' + }, + { + loader: 'sass-loader', + options: { + includePaths: ['./node_modules/material-components-web/node_modules', './node_modules'] + // importer: function(url, prev) { + // if (url.indexOf('@material') === 0) { + // var filePath = url.split('@material')[1]; + // var nodeModulePath = `./node_modules/material-components-web/node_modules/@material/${filePath}`; + // return { file: require('path').resolve(nodeModulePath) }; + // } + // return { file: url }; + // } + } + }] + }) + }, + { + test: /\.css$/, + use: extractPlugin.extract({ + use: ['css-loader'] + }) + }, + { + test: /\.(png|svg|jpg|gif)$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'img', + publicPath: 'img' + }, + }] + }, + { + test: /\.(ttf|woff|woff2|eot)$/, + use: [ + { + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'icons', + publicPath: 'icons' + }, + }] + }, + { + test: /\.html$/, + use: ['html-loader'] + }] + }, + plugins: [ + extractPlugin, + htmlPlugin + ] +}; diff --git a/examples/demo1/bin/demo-server/Dockerfile b/examples/demo1/src/demo-server/Dockerfile similarity index 100% rename from examples/demo1/bin/demo-server/Dockerfile rename to examples/demo1/src/demo-server/Dockerfile diff --git a/examples/demo1/src/demo-server/api/swagger.yaml b/examples/demo1/src/demo-server/api/swagger.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e02a1e86142da6970b3915cf9d32c74c3d276fe4 --- /dev/null +++ b/examples/demo1/src/demo-server/api/swagger.yaml @@ -0,0 +1,202 @@ +swagger: '2.0' +info: + description: This is the MEEP Demo App API + version: 0.0.1 + title: MEEP Demo App API + termsOfService: InterDigital Internal Only +host: '127.0.0.1:8086' +basePath: /v1 +schemes: + - http +consumes: + - application/json +produces: + - application/json +parameters: + Path.UeId: + name: ueId + in: path + description: 'Identity of a ue, refered to as ue id' + required: true + type: string + event: + name: event + in: body + description: Mobility Group event notification + required: true + schema: + $ref: '#/definitions/MobilityGroupEvent' + x-exportParamName: event +tags: + - name: Edge App Info + - name: UE State + - name: State Transfer +paths: + /edge-app: + get: + tags: + - Edge App Info + summary: Retrieve edge add info + description: '' + operationId: getEdgeInfo + produces: + - application/json + responses: + '200': + description: OK + schema: + $ref: '#/definitions/EdgeInfo' + '404': + description: Not found + '/ue/{ueId}': + get: + tags: + - UE State + summary: Retrieves the UE state values + description: '' + operationId: getUeState + produces: + - application/json + parameters: + - name: ueId + in: path + description: UE identifier + required: true + type: string + x-exportParamName: UeId + responses: + '200': + description: OK + schema: + $ref: '#/definitions/UeState' + '400': + description: Bad request + '404': + description: Not found + post: + tags: + - UE State + summary: Registers the UE and starts a counter + description: '' + operationId: createUeState + produces: + - application/json + parameters: + - name: ueId + in: path + description: UE identifier + required: true + type: string + x-exportParamName: UeId + responses: + '200': + description: OK + '400': + description: Bad request + '500': + description: Intenal server error + /mg/event: + post: + tags: + - State Transfer + summary: Send event notification to registered Mobility Group Application + description: '' + operationId: handleEvent + produces: + - application/json + parameters: + - $ref: '#/parameters/event' + responses: + '200': + description: OK + '400': + description: Bad request + '404': + description: Not found +definitions: + EdgeInfo: + type: object + properties: + svc: + type: string + description: Edge app service + name: + type: string + description: Edge app local name + ip: + type: string + description: IP address where the local edge app reside + description: Edge app basic information object + example: + edgeInfo: + - svc: game + name: edge1-zone1-game + ip: 10.32.0.13 + MobilityGroupAppState: + type: object + properties: + ueId: + type: string + description: Mobility Group UE Identifier + ueState: + type: string + description: Mobility Group Application State for provided UE + description: Mobility Group Application State + MobilityGroupEvent: + type: object + properties: + name: + type: string + description: Mobility Group event name + type: + type: string + description: Mobility Group event type + enum: + - STATE-UPDATE + - STATE-TRANSFER-START + - STATE-TRANSFER-COMPLETE + - STATE-TRANSFER-CANCEL + ueId: + type: string + description: Mobility Group UE identifier + appState: + $ref: '#/definitions/MobilityGroupAppState' + description: Event object + UeState: + type: object + properties: + duration: + type: integer + description: Duration since the game stated + description: Ue state basic information object + example: + ueState: + - duration: 32 +responses: + Std200: + description: OK + Std201: + description: Created + Std202: + description: Accepted + Std204: + description: No content + Std304: + description: Not modified + Std400: + description: Bad request + Std401: + description: Not authorized + Std403: + description: Forbidden + Std404: + description: Not found + Std409: + description: Conflict + Std416: + description: Requested range not satisfiable + Std500: + description: Internal server error +externalDocs: + description: Find out more about MEEP Demo App API + url: 'http://www.localinfo/pdf' diff --git a/examples/demo1/src/demo-server/build.sh b/examples/demo1/src/demo-server/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..4e7511da9c6e72ab5836c04fc5abced28762819e --- /dev/null +++ b/examples/demo1/src/demo-server/build.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# Get full path to script directory +SCRIPT=$(readlink -f "$0") +BASEDIR=$(dirname "$SCRIPT") + +# Create build directory +if [ "$#" -ne 1 ]; then + echo "Missing bin directory" + exit +fi +BINDIR=$1 +mkdir -p $BINDIR + +# Set GO env variables +GOOS=linux + +# Create vendor folder +cd $BASEDIR +go mod vendor + +# Build demo App server +cd $BASEDIR +go build -o $BINDIR/demo-server . diff --git a/examples/demo1/src/demo-server/go.mod b/examples/demo1/src/demo-server/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..3acee0399f86a565baa62ed5cd3a2bd0c24ec878 --- /dev/null +++ b/examples/demo1/src/demo-server/go.mod @@ -0,0 +1,11 @@ +module github.com/InterDigitalInc/AdvantEDGE/demoserver + +go 1.12 + +require ( + github.com/InterDigitalInc/AdvantEDGE/mgmanagerapi v0.0.0 + github.com/gorilla/handlers v1.4.0 + github.com/gorilla/mux v1.7.1 +) + +replace github.com/InterDigitalInc/AdvantEDGE/mgmanagerapi => ../../../../go-packages/meep-mg-manager-client diff --git a/examples/demo1/src/demo-server/go.sum b/examples/demo1/src/demo-server/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..629d555e38927e47835ecd94e625d0f896c2d2b4 --- /dev/null +++ b/examples/demo1/src/demo-server/go.sum @@ -0,0 +1,20 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= +github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= +github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 h1:tzVWzOrXxwAwdSCMrf+mbNrZFxwS0+HLP4m2qxtfdhk= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/examples/demo1/src/demo-server/go/.ue_state_api.go.swp b/examples/demo1/src/demo-server/go/.ue_state_api.go.swp new file mode 100644 index 0000000000000000000000000000000000000000..74c588ab747e4a2607e96ccd5ec73049f49e03d6 Binary files /dev/null and b/examples/demo1/src/demo-server/go/.ue_state_api.go.swp differ diff --git a/examples/demo1/src/demo-server/go/README.md b/examples/demo1/src/demo-server/go/README.md new file mode 100644 index 0000000000000000000000000000000000000000..c2dd7a80053a650d9c0df945e1ed6511409b8fbe --- /dev/null +++ b/examples/demo1/src/demo-server/go/README.md @@ -0,0 +1,25 @@ +# Go API Server for swagger + +This is the MEEP Demo App API + +## Overview +This server was generated by the [swagger-codegen] +(https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) + +- API version: 0.0.1 +- Build date: 2018-12-17T19:10:44.299Z + + +### Running the server +To run the server, follow these simple steps: + +``` +go run main.go +``` + diff --git a/examples/demo1/src/demo-server/go/edge_app_info_api.go b/examples/demo1/src/demo-server/go/edge_app_info_api.go new file mode 100644 index 0000000000000000000000000000000000000000..c853c184bce8911ed5dd2ee3a099bb55e59f5755 --- /dev/null +++ b/examples/demo1/src/demo-server/go/edge_app_info_api.go @@ -0,0 +1,44 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "encoding/json" + "fmt" + "net/http" + "os" + "strings" +) + +func GetEdgeInfo(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + + var edgeInfo EdgeInfo + //podName := os.Getenv("MEEP_POD_NAME") + serviceName := os.Getenv("MGM_APP_ID") + newString := strings.ToUpper(serviceName) + "_SERVICE_HOST" + newString = strings.Replace(newString, "-", "_", -1) + + svcName := os.Getenv("MGM_GROUP_NAME") + + edgeInfo.Svc = svcName + edgeInfo.Name = serviceName //podName + edgeInfo.Ip = os.Getenv(newString) + // Format response + jsonResponse, err := json.Marshal(edgeInfo) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Send response + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} diff --git a/examples/demo1/src/demo-server/go/edge_info.go b/examples/demo1/src/demo-server/go/edge_info.go new file mode 100644 index 0000000000000000000000000000000000000000..e6d35a5b85e4f4abb0fa4d8a6e017849e3a391c6 --- /dev/null +++ b/examples/demo1/src/demo-server/go/edge_info.go @@ -0,0 +1,23 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +// Edge app basic information object +type EdgeInfo struct { + + // Edge app service + Svc string `json:"svc,omitempty"` + + // Edge app local name + Name string `json:"name,omitempty"` + + // IP address where the local edge app reside + Ip string `json:"ip,omitempty"` +} diff --git a/examples/demo1/src/demo-server/go/localDB.go b/examples/demo1/src/demo-server/go/localDB.go new file mode 100644 index 0000000000000000000000000000000000000000..056555650cffe4c3e5005bf4fa039425450c458c --- /dev/null +++ b/examples/demo1/src/demo-server/go/localDB.go @@ -0,0 +1,194 @@ +package swagger + +import ( + "net/http" + "encoding/json" + "time" + "os" + "log" + mgm "github.com/InterDigitalInc/AdvantEDGE/mgmanagerapi" +) + +const eventTypeStateUpdate = "STATE-UPDATE" +const eventTypeStateTransferStart = "STATE-TRANSFER-START" +const eventTypeStateTransferComplete = "STATE-TRANSFER-COMPLETE" +const eventTypeStateTransferCancel = "STATE-TRANSFER-CANCEL" + +var mgManager *mgm.APIClient +var mgName string +var mgAppId string +var mgAppPort string + +var ueIdToStateValueMap map[string]UeState +var ueIdToTickerMap map[string]*time.Ticker + +func Init() { + + ueIdToStateValueMap = make(map[string]UeState) + ueIdToTickerMap = make(map[string]*time.Ticker) + + + + //state transfer app necessities + // Initialize variables from environment + mgName = os.Getenv("MGM_GROUP_NAME") + if mgName == "" { + log.Println("MGM_GROUP_NAME not set") + //return errors.New("MGM_GROUP_NAME not set") + } + mgAppId = os.Getenv("MGM_APP_ID") + if mgAppId == "" { + log.Println("MGM_APP_ID not set") + //return errors.New("MGM_APP_ID not set") + } + mgAppPort = os.Getenv("MGM_APP_PORT") + if mgAppPort == "" { + log.Println("MGM_APP_PORT not set") + //return errors.New("MGM_APP_PORT not set") + } + + // Create client for MG Manager API + mgmCfg := mgm.NewConfiguration() + mgmCfg.BasePath = "http://meep-mg-manager/v1" + mgManager = mgm.NewAPIClient(mgmCfg) + if mgManager == nil { + log.Println("Cannot find the MG Manager API") + //err := errors.New("Failed to find MG Manager API") + //return err + } + +// mgName = "demoSvc" +// mgAppId = "zone1-fog1-demoSvc" +// mgAppPort = "80" + // Register edge app instance with MG Manager + var mgApp mgm.MobilityGroupApp + mgApp.Id = mgAppId + mgApp.Url = "http://" + mgAppId + ":" + mgAppPort + "/v1" + _, err := mgManager.MembershipApi.CreateMobilityGroupApp(nil, mgName, mgAppId, mgApp) + if err != nil { + log.Println(err.Error()) + //return err + } + +} + +func updateUe(ueId string, ueState UeState) { + ueIdToStateValueMap[ueId] = ueState + ticker := ueIdToTickerMap[ueId] + if ticker == nil { + ueIdToTickerMap[ueId] = startTicker(ueId) + log.Printf("start ticker after update") + } else { + log.Printf("do no start ticker") + } +} + +func getUe(ueId string) *UeState { + ueState, ok := ueIdToStateValueMap[ueId] + if ok == false { + return nil + } + + return &ueState +} + +func addUe(ueId string) { + var ueState UeState + ueState.Duration = 0 + ueState.TrafficBw = 0 + + ueIdToStateValueMap[ueId] = ueState + ueIdToTickerMap[ueId] = startTicker(ueId) + + + // Inform MGM of presence of new UE + go func() { + var mgUe mgm.MobilityGroupUe + mgUe.Id = ueId + _, err := mgManager.MembershipApi.CreateMobilityGroupUe(nil, mgName, mgAppId, mgUe) + if err != nil { + log.Println(err.Error()) + } + }() + +} + +func restartUe(ueId string) { + var ueState UeState + ueState.Duration = 0 + ueState.TrafficBw = 0 + ueIdToStateValueMap[ueId] = ueState + //no change to ticker +} + +func startTicker(ueId string) *time.Ticker { + + ticker := time.NewTicker(1000 * time.Millisecond) + go func() { + for range ticker.C { + ueState := ueIdToStateValueMap[ueId] + ueState.Duration++ + ueIdToStateValueMap[ueId] = ueState + } + } () + return ticker +} + +func deleteUe(ueId string) { + + ticker := ueIdToTickerMap[ueId] + ticker.Stop() + delete(ueIdToStateValueMap, ueId) + delete(ueIdToTickerMap, ueId) + +} + +func localDBHandleEvent(w http.ResponseWriter, r *http.Request) { + + // Unmarshal Event from request body + var event MobilityGroupEvent + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&event) + if err != nil { + log.Println(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Process event + log.Println("event.Name: ", event.Name) + log.Println("event.Type_: ", event.Type_) + log.Println("event.UeId: ", event.UeId) + + if event.Type_ == eventTypeStateUpdate { + var ueState UeState + + err = json.Unmarshal([]byte(event.AppState.UeState), &ueState) + if err != nil { + log.Println(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + //return + } + updateUe(event.AppState.UeId, ueState) + + } else { + // Marshal UE state and send it to MG Manager + ueState := ueIdToStateValueMap[event.UeId] + var mgAppState mgm.MobilityGroupAppState + mgAppState.UeId = event.UeId + + //marshal the data + jsonResponse, err := json.Marshal(ueState) + mgAppState.UeState = string(jsonResponse) + + _, err = mgManager.StateTransferApi.TransferAppState(nil, mgName, mgAppId, mgAppState) + if err != nil { + log.Println(err.Error()) + } + } + + // Send OK response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + diff --git a/examples/demo1/src/demo-server/go/logger.go b/examples/demo1/src/demo-server/go/logger.go new file mode 100644 index 0000000000000000000000000000000000000000..2ad09fc1916cf8e447631a08dbd036611c738c7c --- /dev/null +++ b/examples/demo1/src/demo-server/go/logger.go @@ -0,0 +1,32 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/examples/demo1/src/demo-server/go/mobility_group_app_state.go b/examples/demo1/src/demo-server/go/mobility_group_app_state.go new file mode 100644 index 0000000000000000000000000000000000000000..c9d5204834060237fb5327cd4a91bd78010f0e80 --- /dev/null +++ b/examples/demo1/src/demo-server/go/mobility_group_app_state.go @@ -0,0 +1,20 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +// Mobility Group Application State +type MobilityGroupAppState struct { + + // Mobility Group UE Identifier + UeId string `json:"ueId,omitempty"` + + // Mobility Group Application State for provided UE + UeState string `json:"ueState,omitempty"` +} diff --git a/examples/demo1/src/demo-server/go/mobility_group_event.go b/examples/demo1/src/demo-server/go/mobility_group_event.go new file mode 100644 index 0000000000000000000000000000000000000000..64fca6a129950e5a6b41fff64b4337538d506229 --- /dev/null +++ b/examples/demo1/src/demo-server/go/mobility_group_event.go @@ -0,0 +1,25 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +// Event object +type MobilityGroupEvent struct { + + // Mobility Group event name + Name string `json:"name,omitempty"` + + // Mobility Group event type + Type_ string `json:"type,omitempty"` + + // Mobility Group UE identifier + UeId string `json:"ueId,omitempty"` + + AppState *MobilityGroupAppState `json:"appState,omitempty"` +} diff --git a/examples/demo1/src/demo-server/go/routers.go b/examples/demo1/src/demo-server/go/routers.go new file mode 100644 index 0000000000000000000000000000000000000000..537c0aea9a5b877c099159f7e64b6da85b7eb549 --- /dev/null +++ b/examples/demo1/src/demo-server/go/routers.go @@ -0,0 +1,102 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("./static/")))) + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "/v1/", + Index, + }, + + Route{ + "GetEdgeInfo", + strings.ToUpper("Get"), + "/v1/edge-app", + GetEdgeInfo, + }, + + Route{ + "HandleEvent", + strings.ToUpper("Post"), + "/v1/mg/event", + HandleEvent, + }, + + Route{ + "CreateUeState", + strings.ToUpper("Post"), + "/v1/ue/{ueId}", + CreateUeState, + }, + + Route{ + "DeleteUeState", + strings.ToUpper("Delete"), + "/v1/ue/{ueId}", + DeleteUeState, + }, + + Route{ + "GetUeState", + strings.ToUpper("Get"), + "/v1/ue/{ueId}", + GetUeState, + }, + + Route{ + "UpdateUeState", + strings.ToUpper("Put"), + "/v1/ue/{ueId}", + UpdateUeState, + }, + +} diff --git a/examples/demo1/src/demo-server/go/state_transfer_api.go b/examples/demo1/src/demo-server/go/state_transfer_api.go new file mode 100644 index 0000000000000000000000000000000000000000..9c5e405a1b95d875f25667eaecc6c247e177cc22 --- /dev/null +++ b/examples/demo1/src/demo-server/go/state_transfer_api.go @@ -0,0 +1,18 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "net/http" +) + +func HandleEvent(w http.ResponseWriter, r *http.Request) { + localDBHandleEvent(w, r) +} diff --git a/examples/demo1/src/demo-server/go/ue_state.go b/examples/demo1/src/demo-server/go/ue_state.go new file mode 100644 index 0000000000000000000000000000000000000000..963411177efdaf8d4a5a240bf0682326dde4e7f9 --- /dev/null +++ b/examples/demo1/src/demo-server/go/ue_state.go @@ -0,0 +1,21 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +// Ue state basic information object +type UeState struct { + + // Duration since the game stated + Duration int32 `json:"duration,omitempty"` + + // Traffic info for the registered Ue + TrafficBw int32 `json:"trafficBw,omitempty"` + +} diff --git a/examples/demo1/src/demo-server/go/ue_state_api.go b/examples/demo1/src/demo-server/go/ue_state_api.go new file mode 100644 index 0000000000000000000000000000000000000000..1dbdea267ac20d6d0a0c3d0c396b5d085461d739 --- /dev/null +++ b/examples/demo1/src/demo-server/go/ue_state_api.go @@ -0,0 +1,109 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "net/http" + "github.com/gorilla/mux" + "fmt" + "encoding/json" +) + + +func CreateUeState(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + + vars := mux.Vars(r) + ueId := vars["ueId"] + + val := getUe(ueId) + + if val == nil { + addUe(ueId) + w.WriteHeader(http.StatusOK) + } else { //ue already exists, just restart the counter + restartUe(ueId) + w.WriteHeader(http.StatusOK) + } +} + +func DeleteUeState(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + + vars := mux.Vars(r) + ueId := vars["ueId"] + + val := getUe(ueId) + + if val != nil { + deleteUe(ueId) + w.WriteHeader(http.StatusOK) + } else { + w.WriteHeader(http.StatusNotFound) + } + +} + +func GetUeState(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + + vars := mux.Vars(r) + ueId := vars["ueId"] + + val := getUe(ueId) + + if val != nil{ + + // Format response + jsonResponse, err := json.Marshal(val) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Send response + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) + + } else { + w.WriteHeader(http.StatusNotFound) + } +} + +func UpdateUeState(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + + vars := mux.Vars(r) + ueId := vars["ueId"] + + val := getUe(ueId) + + if val != nil { + // Retrieve UeState from request body + ueState := new(UeState) + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&ueState) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + //update values in the state object + //val.Duration -- no need to update this one, we keep as is + val.TrafficBw = ueState.TrafficBw + updateUe(ueId, *val) + w.WriteHeader(http.StatusOK) + + } else { + w.WriteHeader(http.StatusNotFound) + return + } +} + diff --git a/examples/demo1/src/demo-server/main.go b/examples/demo1/src/demo-server/main.go new file mode 100644 index 0000000000000000000000000000000000000000..61aa683405f9b2ec7960d4d7bf59f7ae54c76a90 --- /dev/null +++ b/examples/demo1/src/demo-server/main.go @@ -0,0 +1,34 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package main + +import ( + sw "github.com/InterDigitalInc/AdvantEDGE/demoserver/go" + "net/http" + "log" + "github.com/gorilla/handlers" +) + +func init() { + // Initialize App + sw.Init() +} + +func main() { + log.Printf("DemoSvc App API Server started") + + router := sw.NewRouter() + + methods := handlers.AllowedMethods([]string{"OPTIONS", "DELETE", "GET", "HEAD", "POST", "PUT"}) + header := handlers.AllowedHeaders([]string{"content-type"}) + + http.ListenAndServe(":80", handlers.CORS(methods, header)(router)) +} + diff --git a/examples/demo1/src/iperf-proxy-client/.swagger-codegen-ignore b/examples/demo1/src/iperf-proxy-client/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/examples/demo1/src/iperf-proxy-client/.swagger-codegen/VERSION b/examples/demo1/src/iperf-proxy-client/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..58073ef8d7f6ba5b761aca4a751a1c73d4508724 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.4.1 \ No newline at end of file diff --git a/examples/demo1/src/iperf-proxy-client/.travis.yml b/examples/demo1/src/iperf-proxy-client/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..e49f4692f7c8ca9ee3e5839187e1c68e1b6dc64c --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - "6" + - "6.1" + - "5" + - "5.11" + diff --git a/examples/demo1/src/iperf-proxy-client/js/README.md b/examples/demo1/src/iperf-proxy-client/js/README.md new file mode 100644 index 0000000000000000000000000000000000000000..90b137707e1375849e9cb5674f1d8e2abbb4f1e1 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/README.md @@ -0,0 +1,131 @@ +# demo_iperf_transit_app_api + +DemoIperfTransitAppApi - JavaScript client for demo_iperf_transit_app_api +This is the Demo iperf transit App API +This SDK is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: + +- API version: 0.0.1 +- Package version: 0.0.1 +- Build package: io.swagger.codegen.languages.JavascriptClientCodegen + +## Installation + +### For [Node.js](https://nodejs.org/) + +#### npm + +To publish the library as a [npm](https://www.npmjs.com/), +please follow the procedure in ["Publishing npm packages"](https://docs.npmjs.com/getting-started/publishing-npm-packages). + +Then install it via: + +```shell +npm install demo_iperf_transit_app_api --save +``` + +##### Local development + +To use the library locally without publishing to a remote npm registry, first install the dependencies by changing +into the directory containing `package.json` (and this README). Let's call this `JAVASCRIPT_CLIENT_DIR`. Then run: + +```shell +npm install +``` + +Next, [link](https://docs.npmjs.com/cli/link) it globally in npm with the following, also from `JAVASCRIPT_CLIENT_DIR`: + +```shell +npm link +``` + +Finally, switch to the directory you want to use your demo_iperf_transit_app_api from, and run: + +```shell +npm link /path/to/ +``` + +You should now be able to `require('demo_iperf_transit_app_api')` in javascript files from the directory you ran the last +command above from. + +#### git +# +If the library is hosted at a git repository, e.g. +https://github.com/YOUR_USERNAME/demo_iperf_transit_app_api +then install it via: + +```shell + npm install YOUR_USERNAME/demo_iperf_transit_app_api --save +``` + +### For browser + +The library also works in the browser environment via npm and [browserify](http://browserify.org/). After following +the above steps with Node.js and installing browserify with `npm install -g browserify`, +perform the following (assuming *main.js* is your entry file, that's to say your javascript file where you actually +use this library): + +```shell +browserify main.js > bundle.js +``` + +Then include *bundle.js* in the HTML pages. + +### Webpack Configuration + +Using Webpack you may encounter the following error: "Module not found: Error: +Cannot resolve module", most certainly you should disable AMD loader. Add/merge +the following section to your webpack config: + +```javascript +module: { + rules: [ + { + parser: { + amd: false + } + } + ] +} +``` + +## Getting Started + +Please follow the [installation](#installation) instruction and execute the following JS code: + +```javascript +var DemoIperfTransitAppApi = require('demo_iperf_transit_app_api'); + +var api = new DemoIperfTransitAppApi.IperfAppInfoApi() + +var iperfInfo = new DemoIperfTransitAppApi.IperfInfo(); // {IperfInfo} Demo transit Iperf Server Info + + +var callback = function(error, data, response) { + if (error) { + console.error(error); + } else { + console.log('API called successfully.'); + } +}; +api.handleIperfInfo(iperfInfo, callback); + +``` + +## Documentation for API Endpoints + +All URIs are relative to *http://127.0.0.1:8086/v1* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*DemoIperfTransitAppApi.IperfAppInfoApi* | [**handleIperfInfo**](docs/IperfAppInfoApi.md#handleIperfInfo) | **POST** /iperf-app | Sends iperf details to issue an iperf command on the host + + +## Documentation for Models + + - [DemoIperfTransitAppApi.IperfInfo](docs/IperfInfo.md) + + +## Documentation for Authorization + + All endpoints do not require authorization. + diff --git a/examples/demo1/src/iperf-proxy-client/js/build.sh b/examples/demo1/src/iperf-proxy-client/js/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..531fcb1fd7117e54e6931622fa4b3c502446f17d --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/build.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# Get full path to script directory +SCRIPT=$(readlink -f "$0") +BASEDIR=$(dirname "$SCRIPT") + +# Install node module dependencies +cd $BASEDIR +npm ci + diff --git a/examples/demo1/src/iperf-proxy-client/js/docs/IperfAppInfoApi.md b/examples/demo1/src/iperf-proxy-client/js/docs/IperfAppInfoApi.md new file mode 100644 index 0000000000000000000000000000000000000000..968fdcc58250287214f0cefbba09cc61b4b00709 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/docs/IperfAppInfoApi.md @@ -0,0 +1,55 @@ +# DemoIperfTransitAppApi.IperfAppInfoApi + +All URIs are relative to *http://127.0.0.1:8086/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**handleIperfInfo**](IperfAppInfoApi.md#handleIperfInfo) | **POST** /iperf-app | Sends iperf details to issue an iperf command on the host + + + +# **handleIperfInfo** +> handleIperfInfo(iperfInfo) + +Sends iperf details to issue an iperf command on the host + + + +### Example +```javascript +var DemoIperfTransitAppApi = require('demo_iperf_transit_app_api'); + +var apiInstance = new DemoIperfTransitAppApi.IperfAppInfoApi(); + +var iperfInfo = new DemoIperfTransitAppApi.IperfInfo(); // IperfInfo | Demo transit Iperf Server Info + + +var callback = function(error, data, response) { + if (error) { + console.error(error); + } else { + console.log('API called successfully.'); + } +}; +apiInstance.handleIperfInfo(iperfInfo, callback); +``` + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **iperfInfo** | [**IperfInfo**](IperfInfo.md)| Demo transit Iperf Server Info | + +### Return type + +null (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + diff --git a/examples/demo1/src/iperf-proxy-client/js/docs/IperfInfo.md b/examples/demo1/src/iperf-proxy-client/js/docs/IperfInfo.md new file mode 100644 index 0000000000000000000000000000000000000000..3311a60f4891ab8d589ad5052b1c72d3b618d384 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/docs/IperfInfo.md @@ -0,0 +1,10 @@ +# DemoIperfTransitAppApi.IperfInfo + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**name** | **String** | Ue Name / UeId generating the traffic | [optional] +**app** | **String** | Selected Traffic App | [optional] +**throughput** | **Number** | Throughput of Traffic App (in Mbps) | [optional] + + diff --git a/examples/demo1/src/iperf-proxy-client/js/git_push.sh b/examples/demo1/src/iperf-proxy-client/js/git_push.sh new file mode 100644 index 0000000000000000000000000000000000000000..0f1f2144ac9a384701c3b495c1bcbacc374c0566 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the Git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/examples/demo1/src/iperf-proxy-client/js/mocha.opts b/examples/demo1/src/iperf-proxy-client/js/mocha.opts new file mode 100644 index 0000000000000000000000000000000000000000..907011807d680edb272de32bab832a628e2d5064 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/mocha.opts @@ -0,0 +1 @@ +--timeout 10000 diff --git a/examples/demo1/src/iperf-proxy-client/js/package-lock.json b/examples/demo1/src/iperf-proxy-client/js/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..2e3ced41e3b202e180e5ace0ee5e1d5243e67cdc --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/package-lock.json @@ -0,0 +1,356 @@ +{ + "name": "demo_iperf_transit_app_api", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", + "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" + }, + "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=" + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "diff": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", + "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", + "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", + "dev": true + }, + "expect.js": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/expect.js/-/expect.js-0.3.1.tgz", + "integrity": "sha1-sKWaDS7/VDdUTr8M6qYBWEHQm1s=", + "dev": true + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "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" + } + }, + "formatio": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz", + "integrity": "sha1-XtPM1jZVEJc4NGXZlhmRAOhhYek=", + "dev": true, + "requires": { + "samsam": "~1.1" + } + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==" + }, + "glob": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", + "integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=", + "dev": true, + "requires": { + "graceful-fs": "~2.0.0", + "inherits": "2", + "minimatch": "~0.2.11" + } + }, + "graceful-fs": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", + "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", + "dev": true + }, + "growl": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz", + "integrity": "sha1-Sy3sjZB+k9szZiTc7AGDUC+MlCg=", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "jade": { + "version": "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", + "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", + "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", + "dev": true + }, + "mkdirp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", + "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", + "dev": true + } + } + }, + "lolex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "dev": true + }, + "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.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "requires": { + "mime-db": "~1.38.0" + } + }, + "minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "dev": true, + "requires": { + "lru-cache": "2", + "sigmund": "~1.0.0" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.3.4.tgz", + "integrity": "sha1-himm+wRPLSJapLgaKuLQAWmesmY=", + "dev": true, + "requires": { + "commander": "2.3.0", + "debug": "2.2.0", + "diff": "1.4.0", + "escape-string-regexp": "1.0.2", + "glob": "3.2.3", + "growl": "1.8.1", + "jade": "0.26.3", + "mkdirp": "0.5.0", + "supports-color": "1.2.0" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "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==" + }, + "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==" + }, + "qs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.6.0.tgz", + "integrity": "sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==" + }, + "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==", + "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" + } + }, + "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==" + }, + "samsam": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", + "integrity": "sha1-vsEf3IOp/aBjQBIQ5AF2wwJNFWc=", + "dev": true + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "sinon": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.3.tgz", + "integrity": "sha1-RNZLx0jQI4gARsFUPO/Oo0xH0X4=", + "dev": true, + "requires": { + "formatio": "1.1.1", + "lolex": "1.3.2", + "samsam": "1.1.2", + "util": ">=0.10.3 <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==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "superagent": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.7.0.tgz", + "integrity": "sha512-/8trxO6NbLx4YXb7IeeFTSmsQ35pQBiTBsLNvobZx7qBzBeHYvKCyIIhW2gNcWbLzYxPAjdgFbiepd8ypwC0Gw==", + "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.1.1", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.0.5" + } + }, + "supports-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", + "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + } + } +} diff --git a/examples/demo1/src/iperf-proxy-client/js/package.json b/examples/demo1/src/iperf-proxy-client/js/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1c70b207bfba22fe3c71105fb7f3ca7faede9f3c --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/package.json @@ -0,0 +1,21 @@ +{ + "name": "demo_iperf_proxy_app_api", + "version": "0.0.1", + "description": "This_is_the_Demo_iperf_proxy_App_API", + "license": "Unlicense", + "main": "src/index.js", + "scripts": { + "test": "./node_modules/mocha/bin/mocha --recursive" + }, + "browser": { + "fs": false + }, + "dependencies": { + "superagent": "3.7.0" + }, + "devDependencies": { + "mocha": "~2.3.4", + "sinon": "1.17.3", + "expect.js": "~0.3.1" + } +} diff --git a/examples/demo1/src/iperf-proxy-client/js/src/ApiClient.js b/examples/demo1/src/iperf-proxy-client/js/src/ApiClient.js new file mode 100644 index 0000000000000000000000000000000000000000..bdefb20214010851684433602842a68fc0601962 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/src/ApiClient.js @@ -0,0 +1,596 @@ +/** + * Demo iperf transit App API + * This is the Demo iperf transit App API + * + * OpenAPI spec version: 0.0.1 + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * + * Swagger Codegen version: 2.4.1 + * + * Do not edit the class manually. + * + */ + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['superagent', 'querystring'], factory); + } else if (typeof module === 'object' && module.exports) { + // CommonJS-like environments that support module.exports, like Node. + module.exports = factory(require('superagent'), require('querystring')); + } else { + // Browser globals (root is window) + if (!root.DemoIperfTransitAppApi) { + root.DemoIperfTransitAppApi = {}; + } + root.DemoIperfTransitAppApi.ApiClient = factory(root.superagent, root.querystring); + } +}(this, function(superagent, querystring) { + 'use strict'; + + /** + * @module ApiClient + * @version 0.0.1 + */ + + /** + * Manages low level client-server communications, parameter marshalling, etc. There should not be any need for an + * application to use this class directly - the *Api and model classes provide the public API for the service. The + * contents of this file should be regarded as internal but are documented for completeness. + * @alias module:ApiClient + * @class + */ + var exports = function() { + /** + * The base URL against which to resolve every API call's (relative) path. + * @type {String} + * @default http://127.0.0.1:8086/v1 + */ + this.basePath = 'http://127.0.0.1:8086/v1'.replace(/\/+$/, ''); + + /** + * The authentication methods to be included for all API calls. + * @type {Array.} + */ + this.authentications = { + }; + /** + * The default HTTP headers to be included for all API calls. + * @type {Array.} + * @default {} + */ + this.defaultHeaders = {}; + + /** + * The default HTTP timeout for all API calls. + * @type {Number} + * @default 60000 + */ + this.timeout = 60000; + + /** + * If set to false an additional timestamp parameter is added to all API GET calls to + * prevent browser caching + * @type {Boolean} + * @default true + */ + this.cache = true; + + /** + * If set to true, the client will save the cookies from each server + * response, and return them in the next request. + * @default false + */ + this.enableCookies = false; + + /* + * Used to save and return cookies in a node.js (non-browser) setting, + * if this.enableCookies is set to true. + */ + if (typeof window === 'undefined') { + this.agent = new superagent.agent(); + } + + /* + * Allow user to override superagent agent + */ + this.requestAgent = null; + }; + + /** + * Returns a string representation for an actual parameter. + * @param param The actual parameter. + * @returns {String} The string representation of param. + */ + exports.prototype.paramToString = function(param) { + if (param == undefined || param == null) { + return ''; + } + if (param instanceof Date) { + return param.toJSON(); + } + return param.toString(); + }; + + /** + * Builds full URL by appending the given path to the base URL and replacing path parameter place-holders with parameter values. + * NOTE: query parameters are not handled here. + * @param {String} path The path to append to the base URL. + * @param {Object} pathParams The parameter values to append. + * @returns {String} The encoded path with parameter values substituted. + */ + exports.prototype.buildUrl = function(path, pathParams) { + if (!path.match(/^\//)) { + path = '/' + path; + } + var url = this.basePath + path; + var _this = this; + url = url.replace(/\{([\w-]+)\}/g, function(fullMatch, key) { + var value; + if (pathParams.hasOwnProperty(key)) { + value = _this.paramToString(pathParams[key]); + } else { + value = fullMatch; + } + return encodeURIComponent(value); + }); + return url; + }; + + /** + * Checks whether the given content type represents JSON.
+ * JSON content type examples:
+ *
    + *
  • application/json
  • + *
  • application/json; charset=UTF8
  • + *
  • APPLICATION/JSON
  • + *
+ * @param {String} contentType The MIME content type to check. + * @returns {Boolean} true if contentType represents JSON, otherwise false. + */ + exports.prototype.isJsonMime = function(contentType) { + return Boolean(contentType != null && contentType.match(/^application\/json(;.*)?$/i)); + }; + + /** + * Chooses a content type from the given array, with JSON preferred; i.e. return JSON if included, otherwise return the first. + * @param {Array.} contentTypes + * @returns {String} The chosen content type, preferring JSON. + */ + exports.prototype.jsonPreferredMime = function(contentTypes) { + for (var i = 0; i < contentTypes.length; i++) { + if (this.isJsonMime(contentTypes[i])) { + return contentTypes[i]; + } + } + return contentTypes[0]; + }; + + /** + * Checks whether the given parameter value represents file-like content. + * @param param The parameter to check. + * @returns {Boolean} true if param represents a file. + */ + exports.prototype.isFileParam = function(param) { + // fs.ReadStream in Node.js and Electron (but not in runtime like browserify) + if (typeof require === 'function') { + var fs; + try { + fs = require('fs'); + } catch (err) {} + if (fs && fs.ReadStream && param instanceof fs.ReadStream) { + return true; + } + } + // Buffer in Node.js + if (typeof Buffer === 'function' && param instanceof Buffer) { + return true; + } + // Blob in browser + if (typeof Blob === 'function' && param instanceof Blob) { + return true; + } + // File in browser (it seems File object is also instance of Blob, but keep this for safe) + if (typeof File === 'function' && param instanceof File) { + return true; + } + return false; + }; + + /** + * Normalizes parameter values: + *
    + *
  • remove nils
  • + *
  • keep files and arrays
  • + *
  • format to string with `paramToString` for other cases
  • + *
+ * @param {Object.} params The parameters as object properties. + * @returns {Object.} normalized parameters. + */ + exports.prototype.normalizeParams = function(params) { + var newParams = {}; + for (var key in params) { + if (params.hasOwnProperty(key) && params[key] != undefined && params[key] != null) { + var value = params[key]; + if (this.isFileParam(value) || Array.isArray(value)) { + newParams[key] = value; + } else { + newParams[key] = this.paramToString(value); + } + } + } + return newParams; + }; + + /** + * Enumeration of collection format separator strategies. + * @enum {String} + * @readonly + */ + exports.CollectionFormatEnum = { + /** + * Comma-separated values. Value: csv + * @const + */ + CSV: ',', + /** + * Space-separated values. Value: ssv + * @const + */ + SSV: ' ', + /** + * Tab-separated values. Value: tsv + * @const + */ + TSV: '\t', + /** + * Pipe(|)-separated values. Value: pipes + * @const + */ + PIPES: '|', + /** + * Native array. Value: multi + * @const + */ + MULTI: 'multi' + }; + + /** + * Builds a string representation of an array-type actual parameter, according to the given collection format. + * @param {Array} param An array parameter. + * @param {module:ApiClient.CollectionFormatEnum} collectionFormat The array element separator strategy. + * @returns {String|Array} A string representation of the supplied collection, using the specified delimiter. Returns + * param as is if collectionFormat is multi. + */ + exports.prototype.buildCollectionParam = function buildCollectionParam(param, collectionFormat) { + if (param == null) { + return null; + } + switch (collectionFormat) { + case 'csv': + return param.map(this.paramToString).join(','); + case 'ssv': + return param.map(this.paramToString).join(' '); + case 'tsv': + return param.map(this.paramToString).join('\t'); + case 'pipes': + return param.map(this.paramToString).join('|'); + case 'multi': + // return the array directly as SuperAgent will handle it as expected + return param.map(this.paramToString); + default: + throw new Error('Unknown collection format: ' + collectionFormat); + } + }; + + /** + * Applies authentication headers to the request. + * @param {Object} request The request object created by a superagent() call. + * @param {Array.} authNames An array of authentication method names. + */ + exports.prototype.applyAuthToRequest = function(request, authNames) { + var _this = this; + authNames.forEach(function(authName) { + var auth = _this.authentications[authName]; + switch (auth.type) { + case 'basic': + if (auth.username || auth.password) { + request.auth(auth.username || '', auth.password || ''); + } + break; + case 'apiKey': + if (auth.apiKey) { + var data = {}; + if (auth.apiKeyPrefix) { + data[auth.name] = auth.apiKeyPrefix + ' ' + auth.apiKey; + } else { + data[auth.name] = auth.apiKey; + } + if (auth['in'] === 'header') { + request.set(data); + } else { + request.query(data); + } + } + break; + case 'oauth2': + if (auth.accessToken) { + request.set({'Authorization': 'Bearer ' + auth.accessToken}); + } + break; + default: + throw new Error('Unknown authentication type: ' + auth.type); + } + }); + }; + + /** + * Deserializes an HTTP response body into a value of the specified type. + * @param {Object} response A SuperAgent response object. + * @param {(String|Array.|Object.|Function)} returnType The type to return. Pass a string for simple types + * or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To + * return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type: + * all properties on data will be converted to this type. + * @returns A value of the specified type. + */ + exports.prototype.deserialize = function deserialize(response, returnType) { + if (response == null || returnType == null || response.status == 204) { + return null; + } + // Rely on SuperAgent for parsing response body. + // See http://visionmedia.github.io/superagent/#parsing-response-bodies + var data = response.body; + if (data == null || (typeof data === 'object' && typeof data.length === 'undefined' && !Object.keys(data).length)) { + // SuperAgent does not always produce a body; use the unparsed response as a fallback + data = response.text; + } + return exports.convertToType(data, returnType); + }; + + /** + * Callback function to receive the result of the operation. + * @callback module:ApiClient~callApiCallback + * @param {String} error Error message, if any. + * @param data The data returned by the service call. + * @param {String} response The complete HTTP response. + */ + + /** + * Invokes the REST service using the supplied settings and parameters. + * @param {String} path The base URL to invoke. + * @param {String} httpMethod The HTTP method to use. + * @param {Object.} pathParams A map of path parameters and their values. + * @param {Object.} queryParams A map of query parameters and their values. + * @param {Object.} collectionQueryParams A map of collection query parameters and their values. + * @param {Object.} headerParams A map of header parameters and their values. + * @param {Object.} formParams A map of form parameters and their values. + * @param {Object} bodyParam The value to pass as the request body. + * @param {Array.} authNames An array of authentication type names. + * @param {Array.} contentTypes An array of request MIME types. + * @param {Array.} accepts An array of acceptable response MIME types. + * @param {(String|Array|ObjectFunction)} returnType The required type to return; can be a string for simple types or the + * constructor for a complex type. + * @param {module:ApiClient~callApiCallback} callback The callback function. + * @returns {Object} The SuperAgent request object. + */ + exports.prototype.callApi = function callApi(path, httpMethod, pathParams, + queryParams, collectionQueryParams, headerParams, formParams, bodyParam, authNames, contentTypes, accepts, + returnType, callback) { + + var _this = this; + var url = this.buildUrl(path, pathParams); + var request = superagent(httpMethod, url); + + // apply authentications + this.applyAuthToRequest(request, authNames); + + // set collection query parameters + for (var key in collectionQueryParams) { + if (collectionQueryParams.hasOwnProperty(key)) { + var param = collectionQueryParams[key]; + if (param.collectionFormat === 'csv') { + // SuperAgent normally percent-encodes all reserved characters in a query parameter. However, + // commas are used as delimiters for the 'csv' collectionFormat so they must not be encoded. We + // must therefore construct and encode 'csv' collection query parameters manually. + if (param.value != null) { + var value = param.value.map(this.paramToString).map(encodeURIComponent).join(','); + request.query(encodeURIComponent(key) + "=" + value); + } + } else { + // All other collection query parameters should be treated as ordinary query parameters. + queryParams[key] = this.buildCollectionParam(param.value, param.collectionFormat); + } + } + } + + // set query parameters + if (httpMethod.toUpperCase() === 'GET' && this.cache === false) { + queryParams['_'] = new Date().getTime(); + } + request.query(this.normalizeParams(queryParams)); + + // set header parameters + request.set(this.defaultHeaders).set(this.normalizeParams(headerParams)); + + + // set requestAgent if it is set by user + if (this.requestAgent) { + request.agent(this.requestAgent); + } + + // set request timeout + request.timeout(this.timeout); + + var contentType = this.jsonPreferredMime(contentTypes); + if (contentType) { + // Issue with superagent and multipart/form-data (https://github.com/visionmedia/superagent/issues/746) + if(contentType != 'multipart/form-data') { + request.type(contentType); + } + } else if (!request.header['Content-Type']) { + request.type('application/json'); + } + + if (contentType === 'application/x-www-form-urlencoded') { + request.send(querystring.stringify(this.normalizeParams(formParams))); + } else if (contentType == 'multipart/form-data') { + var _formParams = this.normalizeParams(formParams); + for (var key in _formParams) { + if (_formParams.hasOwnProperty(key)) { + if (this.isFileParam(_formParams[key])) { + // file field + request.attach(key, _formParams[key]); + } else { + request.field(key, _formParams[key]); + } + } + } + } else if (bodyParam) { + request.send(bodyParam); + } + + var accept = this.jsonPreferredMime(accepts); + if (accept) { + request.accept(accept); + } + + if (returnType === 'Blob') { + request.responseType('blob'); + } else if (returnType === 'String') { + request.responseType('string'); + } + + // Attach previously saved cookies, if enabled + if (this.enableCookies){ + if (typeof window === 'undefined') { + this.agent.attachCookies(request); + } + else { + request.withCredentials(); + } + } + + + request.end(function(error, response) { + if (callback) { + var data = null; + if (!error) { + try { + data = _this.deserialize(response, returnType); + if (_this.enableCookies && typeof window === 'undefined'){ + _this.agent.saveCookies(response); + } + } catch (err) { + error = err; + } + } + callback(error, data, response); + } + }); + + return request; + }; + + /** + * Parses an ISO-8601 string representation of a date value. + * @param {String} str The date value as a string. + * @returns {Date} The parsed date object. + */ + exports.parseDate = function(str) { + return new Date(str.replace(/T/i, ' ')); + }; + + /** + * Converts a value to the specified type. + * @param {(String|Object)} data The data to convert, as a string or object. + * @param {(String|Array.|Object.|Function)} type The type to return. Pass a string for simple types + * or the constructor function for a complex type. Pass an array containing the type name to return an array of that type. To + * return an object, pass an object with one property whose name is the key type and whose value is the corresponding value type: + * all properties on data will be converted to this type. + * @returns An instance of the specified type or null or undefined if data is null or undefined. + */ + exports.convertToType = function(data, type) { + if (data === null || data === undefined) + return data + + switch (type) { + case 'Boolean': + return Boolean(data); + case 'Integer': + return parseInt(data, 10); + case 'Number': + return parseFloat(data); + case 'String': + return String(data); + case 'Date': + return this.parseDate(String(data)); + case 'Blob': + return data; + default: + if (type === Object) { + // generic object, return directly + return data; + } else if (typeof type === 'function') { + // for model type like: User + return type.constructFromObject(data); + } else if (Array.isArray(type)) { + // for array type like: ['String'] + var itemType = type[0]; + return data.map(function(item) { + return exports.convertToType(item, itemType); + }); + } else if (typeof type === 'object') { + // for plain object type like: {'String': 'Integer'} + var keyType, valueType; + for (var k in type) { + if (type.hasOwnProperty(k)) { + keyType = k; + valueType = type[k]; + break; + } + } + var result = {}; + for (var k in data) { + if (data.hasOwnProperty(k)) { + var key = exports.convertToType(k, keyType); + var value = exports.convertToType(data[k], valueType); + result[key] = value; + } + } + return result; + } else { + // for unknown type, return the data directly + return data; + } + } + }; + + /** + * Constructs a new map or array model from REST data. + * @param data {Object|Array} The REST data. + * @param obj {Object|Array} The target object or array. + */ + exports.constructFromObject = function(data, obj, itemType) { + if (Array.isArray(data)) { + for (var i = 0; i < data.length; i++) { + if (data.hasOwnProperty(i)) + obj[i] = exports.convertToType(data[i], itemType); + } + } else { + for (var k in data) { + if (data.hasOwnProperty(k)) + obj[k] = exports.convertToType(data[k], itemType); + } + } + }; + + /** + * The default API client implementation. + * @type {module:ApiClient} + */ + exports.instance = new exports(); + + return exports; +})); diff --git a/examples/demo1/src/iperf-proxy-client/js/src/api/IperfAppInfoApi.js b/examples/demo1/src/iperf-proxy-client/js/src/api/IperfAppInfoApi.js new file mode 100644 index 0000000000000000000000000000000000000000..4b36c56c9fd196077ab979ee49789bdfa287a22f --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/src/api/IperfAppInfoApi.js @@ -0,0 +1,98 @@ +/** + * Demo iperf transit App API + * This is the Demo iperf transit App API + * + * OpenAPI spec version: 0.0.1 + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * + * Swagger Codegen version: 2.4.1 + * + * Do not edit the class manually. + * + */ + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['ApiClient', 'model/IperfInfo'], factory); + } else if (typeof module === 'object' && module.exports) { + // CommonJS-like environments that support module.exports, like Node. + module.exports = factory(require('../ApiClient'), require('../model/IperfInfo')); + } else { + // Browser globals (root is window) + if (!root.DemoIperfTransitAppApi) { + root.DemoIperfTransitAppApi = {}; + } + root.DemoIperfTransitAppApi.IperfAppInfoApi = factory(root.DemoIperfTransitAppApi.ApiClient, root.DemoIperfTransitAppApi.IperfInfo); + } +}(this, function(ApiClient, IperfInfo) { + 'use strict'; + + /** + * IperfAppInfo service. + * @module api/IperfAppInfoApi + * @version 0.0.1 + */ + + /** + * Constructs a new IperfAppInfoApi. + * @alias module:api/IperfAppInfoApi + * @class + * @param {module:ApiClient} [apiClient] Optional API client implementation to use, + * default to {@link module:ApiClient#instance} if unspecified. + */ + var exports = function(apiClient) { + this.apiClient = apiClient || ApiClient.instance; + + + /** + * Callback function to receive the result of the handleIperfInfo operation. + * @callback module:api/IperfAppInfoApi~handleIperfInfoCallback + * @param {String} error Error message, if any. + * @param data This operation does not return a value. + * @param {String} response The complete HTTP response. + */ + + /** + * Sends iperf details to issue an iperf command on the host + * + * @param {module:model/IperfInfo} iperfInfo Demo transit Iperf Server Info + * @param {module:api/IperfAppInfoApi~handleIperfInfoCallback} callback The callback function, accepting three arguments: error, data, response + */ + this.handleIperfInfo = function(iperfInfo, callback) { + var postBody = iperfInfo; + + // verify the required parameter 'iperfInfo' is set + if (iperfInfo === undefined || iperfInfo === null) { + throw new Error("Missing the required parameter 'iperfInfo' when calling handleIperfInfo"); + } + + + var pathParams = { + }; + var queryParams = { + }; + var collectionQueryParams = { + }; + var headerParams = { + }; + var formParams = { + }; + + var authNames = []; + var contentTypes = ['application/json']; + var accepts = ['application/json']; + var returnType = null; + + return this.apiClient.callApi( + '/iperf-app', 'POST', + pathParams, queryParams, collectionQueryParams, headerParams, formParams, postBody, + authNames, contentTypes, accepts, returnType, callback + ); + } + }; + + return exports; +})); diff --git a/examples/demo1/src/iperf-proxy-client/js/src/index.js b/examples/demo1/src/iperf-proxy-client/js/src/index.js new file mode 100644 index 0000000000000000000000000000000000000000..65ae0d27ff78b41c9da3efeec3718d04491cdaad --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/src/index.js @@ -0,0 +1,77 @@ +/** + * Demo iperf transit App API + * This is the Demo iperf transit App API + * + * OpenAPI spec version: 0.0.1 + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * + * Swagger Codegen version: 2.4.1 + * + * Do not edit the class manually. + * + */ + +(function(factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['ApiClient', 'model/IperfInfo', 'api/IperfAppInfoApi'], factory); + } else if (typeof module === 'object' && module.exports) { + // CommonJS-like environments that support module.exports, like Node. + module.exports = factory(require('./ApiClient'), require('./model/IperfInfo'), require('./api/IperfAppInfoApi')); + } +}(function(ApiClient, IperfInfo, IperfAppInfoApi) { + 'use strict'; + + /** + * This_is_the_Demo_iperf_transit_App_API.
+ * The index module provides access to constructors for all the classes which comprise the public API. + *

+ * An AMD (recommended!) or CommonJS application will generally do something equivalent to the following: + *

+   * var DemoIperfTransitAppApi = require('index'); // See note below*.
+   * var xxxSvc = new DemoIperfTransitAppApi.XxxApi(); // Allocate the API class we're going to use.
+   * var yyyModel = new DemoIperfTransitAppApi.Yyy(); // Construct a model instance.
+   * yyyModel.someProperty = 'someValue';
+   * ...
+   * var zzz = xxxSvc.doSomething(yyyModel); // Invoke the service.
+   * ...
+   * 
+ * *NOTE: For a top-level AMD script, use require(['index'], function(){...}) + * and put the application logic within the callback function. + *

+ *

+ * A non-AMD browser application (discouraged) might do something like this: + *

+   * var xxxSvc = new DemoIperfTransitAppApi.XxxApi(); // Allocate the API class we're going to use.
+   * var yyy = new DemoIperfTransitAppApi.Yyy(); // Construct a model instance.
+   * yyyModel.someProperty = 'someValue';
+   * ...
+   * var zzz = xxxSvc.doSomething(yyyModel); // Invoke the service.
+   * ...
+   * 
+ *

+ * @module index + * @version 0.0.1 + */ + var exports = { + /** + * The ApiClient constructor. + * @property {module:ApiClient} + */ + ApiClient: ApiClient, + /** + * The IperfInfo model constructor. + * @property {module:model/IperfInfo} + */ + IperfInfo: IperfInfo, + /** + * The IperfAppInfoApi service constructor. + * @property {module:api/IperfAppInfoApi} + */ + IperfAppInfoApi: IperfAppInfoApi + }; + + return exports; +})); diff --git a/examples/demo1/src/iperf-proxy-client/js/src/model/IperfInfo.js b/examples/demo1/src/iperf-proxy-client/js/src/model/IperfInfo.js new file mode 100644 index 0000000000000000000000000000000000000000..5a778a18d8780e31a6dc72b43e12b472bc59505a --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/src/model/IperfInfo.js @@ -0,0 +1,101 @@ +/** + * Demo iperf transit App API + * This is the Demo iperf transit App API + * + * OpenAPI spec version: 0.0.1 + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * + * Swagger Codegen version: 2.4.1 + * + * Do not edit the class manually. + * + */ + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['ApiClient'], factory); + } else if (typeof module === 'object' && module.exports) { + // CommonJS-like environments that support module.exports, like Node. + module.exports = factory(require('../ApiClient')); + } else { + // Browser globals (root is window) + if (!root.DemoIperfTransitAppApi) { + root.DemoIperfTransitAppApi = {}; + } + root.DemoIperfTransitAppApi.IperfInfo = factory(root.DemoIperfTransitAppApi.ApiClient); + } +}(this, function(ApiClient) { + 'use strict'; + + + + + /** + * The IperfInfo model module. + * @module model/IperfInfo + * @version 0.0.1 + */ + + /** + * Constructs a new IperfInfo. + * Iperf info for transit iperf server basic information object + * @alias module:model/IperfInfo + * @class + */ + var exports = function() { + var _this = this; + + + + + }; + + /** + * Constructs a IperfInfo from a plain JavaScript object, optionally creating a new instance. + * Copies all relevant properties from data to obj if supplied or a new instance if not. + * @param {Object} data The plain JavaScript object bearing properties of interest. + * @param {module:model/IperfInfo} obj Optional instance to populate. + * @return {module:model/IperfInfo} The populated IperfInfo instance. + */ + exports.constructFromObject = function(data, obj) { + if (data) { + obj = obj || new exports(); + + if (data.hasOwnProperty('name')) { + obj['name'] = ApiClient.convertToType(data['name'], 'String'); + } + if (data.hasOwnProperty('app')) { + obj['app'] = ApiClient.convertToType(data['app'], 'String'); + } + if (data.hasOwnProperty('throughput')) { + obj['throughput'] = ApiClient.convertToType(data['throughput'], 'Number'); + } + } + return obj; + } + + /** + * Ue Name / UeId generating the traffic + * @member {String} name + */ + exports.prototype['name'] = undefined; + /** + * Selected Traffic App + * @member {String} app + */ + exports.prototype['app'] = undefined; + /** + * Throughput of Traffic App (in Mbps) + * @member {Number} throughput + */ + exports.prototype['throughput'] = undefined; + + + + return exports; +})); + + diff --git a/examples/demo1/src/iperf-proxy-client/js/test/api/IperfAppInfoApi.spec.js b/examples/demo1/src/iperf-proxy-client/js/test/api/IperfAppInfoApi.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..bc5068ae4fac580318781f2976623df237335dce --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/test/api/IperfAppInfoApi.spec.js @@ -0,0 +1,65 @@ +/** + * Demo iperf transit App API + * This is the Demo iperf transit App API + * + * OpenAPI spec version: 0.0.1 + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * + * Swagger Codegen version: 2.4.1 + * + * Do not edit the class manually. + * + */ + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. + define(['expect.js', '../../src/index'], factory); + } else if (typeof module === 'object' && module.exports) { + // CommonJS-like environments that support module.exports, like Node. + factory(require('expect.js'), require('../../src/index')); + } else { + // Browser globals (root is window) + factory(root.expect, root.DemoIperfTransitAppApi); + } +}(this, function(expect, DemoIperfTransitAppApi) { + 'use strict'; + + var instance; + + beforeEach(function() { + instance = new DemoIperfTransitAppApi.IperfAppInfoApi(); + }); + + var getProperty = function(object, getter, property) { + // Use getter method if present; otherwise, get the property directly. + if (typeof object[getter] === 'function') + return object[getter](); + else + return object[property]; + } + + var setProperty = function(object, setter, property, value) { + // Use setter method if present; otherwise, set the property directly. + if (typeof object[setter] === 'function') + object[setter](value); + else + object[property] = value; + } + + describe('IperfAppInfoApi', function() { + describe('handleIperfInfo', function() { + it('should call handleIperfInfo successfully', function(done) { + //uncomment below and update the code to test handleIperfInfo + //instance.handleIperfInfo(function(error) { + // if (error) throw error; + //expect().to.be(); + //}); + done(); + }); + }); + }); + +})); diff --git a/examples/demo1/src/iperf-proxy-client/js/test/model/IperfInfo.spec.js b/examples/demo1/src/iperf-proxy-client/js/test/model/IperfInfo.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..d0d0b3d7e985403127bbdd55dda1a0cdceba3dd1 --- /dev/null +++ b/examples/demo1/src/iperf-proxy-client/js/test/model/IperfInfo.spec.js @@ -0,0 +1,79 @@ +/** + * Demo iperf transit App API + * This is the Demo iperf transit App API + * + * OpenAPI spec version: 0.0.1 + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * + * Swagger Codegen version: 2.4.1 + * + * Do not edit the class manually. + * + */ + +(function(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. + define(['expect.js', '../../src/index'], factory); + } else if (typeof module === 'object' && module.exports) { + // CommonJS-like environments that support module.exports, like Node. + factory(require('expect.js'), require('../../src/index')); + } else { + // Browser globals (root is window) + factory(root.expect, root.DemoIperfTransitAppApi); + } +}(this, function(expect, DemoIperfTransitAppApi) { + 'use strict'; + + var instance; + + beforeEach(function() { + instance = new DemoIperfTransitAppApi.IperfInfo(); + }); + + var getProperty = function(object, getter, property) { + // Use getter method if present; otherwise, get the property directly. + if (typeof object[getter] === 'function') + return object[getter](); + else + return object[property]; + } + + var setProperty = function(object, setter, property, value) { + // Use setter method if present; otherwise, set the property directly. + if (typeof object[setter] === 'function') + object[setter](value); + else + object[property] = value; + } + + describe('IperfInfo', function() { + it('should create an instance of IperfInfo', function() { + // uncomment below and update the code to test IperfInfo + //var instance = new DemoIperfTransitAppApi.IperfInfo(); + //expect(instance).to.be.a(DemoIperfTransitAppApi.IperfInfo); + }); + + it('should have the property name (base name: "name")', function() { + // uncomment below and update the code to test the property name + //var instance = new DemoIperfTransitAppApi.IperfInfo(); + //expect(instance).to.be(); + }); + + it('should have the property app (base name: "app")', function() { + // uncomment below and update the code to test the property app + //var instance = new DemoIperfTransitAppApi.IperfInfo(); + //expect(instance).to.be(); + }); + + it('should have the property throughput (base name: "throughput")', function() { + // uncomment below and update the code to test the property throughput + //var instance = new DemoIperfTransitAppApi.IperfInfo(); + //expect(instance).to.be(); + }); + + }); + +})); diff --git a/examples/demo1/src/iperf-proxy/api/swagger.yaml b/examples/demo1/src/iperf-proxy/api/swagger.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b9017c56b2c02e1baec51420b03a23779cf9b651 --- /dev/null +++ b/examples/demo1/src/iperf-proxy/api/swagger.yaml @@ -0,0 +1,98 @@ +--- +swagger: "2.0" +info: + description: "This is the Demo iperf transit App API" + version: "0.0.1" + title: "Demo iperf transit App API" + termsOfService: "InterDigital Internal Only" +host: "127.0.0.1:8086" +basePath: "/v1" +tags: +- name: "Iperf App Info" +schemes: +- "http" +consumes: +- "application/json" +produces: +- "application/json" +paths: + /iperf-app: + post: + tags: + - "Iperf App Info" + summary: "Sends iperf details to issue an iperf command on the host" + description: "" + operationId: "handleIperfInfo" + produces: + - "application/json" + parameters: + - in: "body" + name: "iperfInfo" + description: "Demo transit Iperf Server Info" + required: true + schema: + $ref: "#/definitions/IperfInfo" + x-exportParamName: "IperfInfo" + responses: + 200: + description: "OK" + 400: + description: "Bad request" + 500: + description: "Intenal server error" +definitions: + IperfInfo: + type: "object" + properties: + name: + type: "string" + description: "Ue Name / UeId generating the traffic" + app: + type: "string" + description: "Selected Traffic App" + throughput: + type: "integer" + description: "Throughput of Traffic App (in Mbps)" + description: "Iperf info for transit iperf server basic information object" + example: + edgeInfo: + - name: "ue2" + app: "iperf" + throughput: 50 +parameters: + iperfInfo: + in: "body" + name: "iperfInfo" + description: "Demo transit Iperf Server Info" + required: true + schema: + $ref: "#/definitions/IperfInfo" + x-exportParamName: "IperfInfo" +responses: + Std200: + description: "OK" + Std201: + description: "Created" + Std202: + description: "Accepted" + Std204: + description: "No content" + Std304: + description: "Not modified" + Std400: + description: "Bad request" + Std401: + description: "Not authorized" + Std403: + description: "Forbidden" + Std404: + description: "Not found" + Std409: + description: "Conflict" + Std416: + description: "Requested range not satisfiable" + Std500: + description: "Internal server error" +externalDocs: + description: "Find out more about Demo Iperf Transit Server App API" + url: "http://www.localinfo/pdf" diff --git a/examples/demo1/src/iperf-proxy/build.sh b/examples/demo1/src/iperf-proxy/build.sh new file mode 100755 index 0000000000000000000000000000000000000000..a770abb70ad267e1a3e7799bc3eddc30b1afd44a --- /dev/null +++ b/examples/demo1/src/iperf-proxy/build.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# Get full path to script directory +SCRIPT=$(readlink -f "$0") +BASEDIR=$(dirname "$SCRIPT") + +# Create build directory +if [ "$#" -ne 1 ]; then + echo "Missing bin directory" + exit +fi +BINDIR=$1 +mkdir -p $BINDIR + +# Set GO env variables +GOOS=linux + +# Create vendor folder +cd $BASEDIR +go mod vendor + +# Build demo App iperf proxy server +cd $BASEDIR +go build -o $BINDIR/iperf-proxy . diff --git a/examples/demo1/src/iperf-proxy/go.mod b/examples/demo1/src/iperf-proxy/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..d381de3123ab0f6a130a75f32973fb2bb0fc46ca --- /dev/null +++ b/examples/demo1/src/iperf-proxy/go.mod @@ -0,0 +1,8 @@ +module github.com/InterDigitalInc/AdvantEDGE/iperfproxy + +go 1.12 + +require ( + github.com/gorilla/handlers v1.4.0 + github.com/gorilla/mux v1.7.1 +) diff --git a/examples/demo1/src/iperf-proxy/go.sum b/examples/demo1/src/iperf-proxy/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..41c8eb75608647f04e9f95400cf1aafb67fff99d --- /dev/null +++ b/examples/demo1/src/iperf-proxy/go.sum @@ -0,0 +1,4 @@ +github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= +github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= +github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= diff --git a/examples/demo1/src/iperf-proxy/go/README.md b/examples/demo1/src/iperf-proxy/go/README.md new file mode 100644 index 0000000000000000000000000000000000000000..26604e4def38d81bb94da4b9c040a1a3a9d87da0 --- /dev/null +++ b/examples/demo1/src/iperf-proxy/go/README.md @@ -0,0 +1,25 @@ +# Go API Server for swagger + +This is the Demo iperf transit App API + +## Overview +This server was generated by the [swagger-codegen] +(https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) + +- API version: 0.0.1 +- Build date: 2019-01-28T21:29:39.905Z + + +### Running the server +To run the server, follow these simple steps: + +``` +go run main.go +``` + diff --git a/examples/demo1/src/iperf-proxy/go/api_iperf_app_info.go b/examples/demo1/src/iperf-proxy/go/api_iperf_app_info.go new file mode 100644 index 0000000000000000000000000000000000000000..749431b133869dd2950e0cdc7efa967cba39fb46 --- /dev/null +++ b/examples/demo1/src/iperf-proxy/go/api_iperf_app_info.go @@ -0,0 +1,119 @@ +/* + * Demo iperf transit App API + * + * This is the Demo iperf transit App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "log" + "net/http" + "encoding/json" + "net" + "os/exec" + "strings" + "strconv" +) + +type IperfInfoBasic struct { + name string + portApp string +} + + +var iperfRunningJobs map[IperfInfoBasic]int + +func Init() { + iperfRunningJobs = make(map[IperfInfoBasic]int) +} + +func GetOutboundIP() net.IP { + conn, err := net.Dial("udp", "8.8.8.8:80") + if err != nil { + log.Fatal(err) + } + defer conn.Close() + + localAddr := conn.LocalAddr().(*net.UDPAddr) + + return localAddr.IP +} + +func cmdExec(cli string) (int, error) { + parts := strings.Fields(cli) + head := parts[0] + parts = parts[1:len(parts)] + + cmd := exec.Command(head, parts...) + err := cmd.Start() + if err != nil { + return 0, err + } + + pid := cmd.Process.Pid + go func() { + err = cmd.Wait() +/* if err == nil { + log.Printf("process terminated normally for pid %d", pid) + } else { + log.Printf("iperf terminated abnormally for pid %d: %s", pid, err) + } +*/ + } () + + return pid, nil +} + +func deletePidProcess(pid int) { + + str := "kill -9 " + strconv.Itoa(pid); + _, _ = cmdExec(str) +} + +func HandleIperfInfo(w http.ResponseWriter, r *http.Request) { + + iperfInfo := new(IperfInfo) + + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&iperfInfo) + + if err != nil { + log.Println(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + targetIp := GetOutboundIP() + // debug printout +/* log.Printf("%s - %s - %s -%s\n", + iperfInfo.Name, + iperfInfo.App, + iperfInfo.Throughput, + targetIp) +*/ + var iperfInfoBasic IperfInfoBasic + iperfInfoBasic.name = iperfInfo.Name + iperfInfoBasic.portApp = iperfInfo.App + + pidExists := iperfRunningJobs[iperfInfoBasic] + + if pidExists != 0 { + deletePidProcess(pidExists) + } + + if iperfInfo.Throughput != "0" && iperfInfo.Throughput != "" { + str := "iperf -u -c " + targetIp.String() + " -t 3600 -p " + iperfInfo.App + " -b " + iperfInfo.Throughput + "M" + + pid, err := cmdExec(str) + if err != nil { + log.Printf("ERROR: %s", err) + } + + iperfRunningJobs[iperfInfoBasic] = pid + } + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} diff --git a/examples/demo1/src/iperf-proxy/go/logger.go b/examples/demo1/src/iperf-proxy/go/logger.go new file mode 100644 index 0000000000000000000000000000000000000000..3027b6ef443646501503c112a17f0dbb08241ac8 --- /dev/null +++ b/examples/demo1/src/iperf-proxy/go/logger.go @@ -0,0 +1,32 @@ +/* + * Demo iperf transit App API + * + * This is the Demo iperf transit App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/examples/demo1/src/iperf-proxy/go/model_iperf_info.go b/examples/demo1/src/iperf-proxy/go/model_iperf_info.go new file mode 100644 index 0000000000000000000000000000000000000000..e5eaa301fa49cf312e1abd8a5ed43642f2a8dd69 --- /dev/null +++ b/examples/demo1/src/iperf-proxy/go/model_iperf_info.go @@ -0,0 +1,23 @@ +/* + * Demo iperf transit App API + * + * This is the Demo iperf transit App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +// Iperf info for transit iperf server basic information object +type IperfInfo struct { + + // Ue Name / UeId generating the traffic + Name string `json:"name,omitempty"` + + // Selected Traffic App + App string `json:"app,omitempty"` + + // Throughput of Traffic App (in Mbps) + Throughput string `json:"throughput,omitempty"` +} diff --git a/examples/demo1/src/iperf-proxy/go/routers.go b/examples/demo1/src/iperf-proxy/go/routers.go new file mode 100644 index 0000000000000000000000000000000000000000..5777be65fd4eebb9f25213b9e81e86313bee685f --- /dev/null +++ b/examples/demo1/src/iperf-proxy/go/routers.go @@ -0,0 +1,64 @@ +/* + * Demo iperf transit App API + * + * This is the Demo iperf transit App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "/v1/", + Index, + }, + + Route{ + "HandleIperfInfo", + strings.ToUpper("Post"), + "/v1/iperf-app", + HandleIperfInfo, + }, +} diff --git a/examples/demo1/src/iperf-proxy/main.go b/examples/demo1/src/iperf-proxy/main.go new file mode 100644 index 0000000000000000000000000000000000000000..a9be72ec3c0cb70f5ff614614ce8a3db3f1fbb14 --- /dev/null +++ b/examples/demo1/src/iperf-proxy/main.go @@ -0,0 +1,34 @@ +/* + * MEEP Demo App API + * + * This is the MEEP Demo App API + * + * API version: 0.0.1 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package main + +import ( + sw "github.com/InterDigitalInc/AdvantEDGE/iperfproxy/go" + "net/http" + "log" + "github.com/gorilla/handlers" +) + +func init() { + // Initialize App + sw.Init() +} + +func main() { + log.Printf("Demo Iperf transit App API Server started") + + router := sw.NewRouter() + + methods := handlers.AllowedMethods([]string{"OPTIONS", "DELETE", "GET", "HEAD", "POST", "PUT"}) + header := handlers.AllowedHeaders([]string{"content-type"}) + + http.ListenAndServe(":30220", handlers.CORS(methods, header)(router)) +} + diff --git a/examples/demo2/README.md b/examples/demo2/README.md index f1c28b52fac6db70fd7afe46969ed91f32c1ce63..dabee3c0bfd561bf10ae1f56f76aa4ab56ae2c0f 100644 --- a/examples/demo2/README.md +++ b/examples/demo2/README.md @@ -1,6 +1,16 @@ # Demo2 -This scenario is the same as [demo1](../demo1/README.md) except that it uses a different deployment technique. -Demo2 uses _user charts_ to deploy its components deployment instead of using dynamic chart generation. +This scenario is the same as [demo1](../demo1/README.md) except that it uses _user charts_ to deploy its components instead of using dynamic chart generation. -Functionally it is the same as demo1 +## Prerequisites + +- Running AdvantEDGE platform +- Demo1 docker images + - [Build demo1](../demo1/README.md) + - [Dockerized demo1](../demo1/README.md) + +## Using the scenario + +- [Import scenario in MEEP](../../docs/use/base-ops.md#import-demo1-scenario-in-advantedge) +- Deploy scenario + - Scenario behavior is identical to [demo1](../demo1/README.md) \ No newline at end of file diff --git a/examples/demo2/charts/iperf/Chart.yaml b/examples/demo2/charts/iperf/Chart.yaml new file mode 100755 index 0000000000000000000000000000000000000000..3c8d6e64ba18b3e42e7e73c9db29e136e52d0e28 --- /dev/null +++ b/examples/demo2/charts/iperf/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0.0" +description: Meep Demo Iperf Helm chart for Kubernetes +name: demo-iperf +version: 1.0.0 diff --git a/examples/demo2/charts/iperf/templates/_helpers.tpl b/examples/demo2/charts/iperf/templates/_helpers.tpl new file mode 100755 index 0000000000000000000000000000000000000000..b39eb82fb2c1537c4de3c785122a91948e1fdcab --- /dev/null +++ b/examples/demo2/charts/iperf/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "meep.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "meep.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "meep.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/examples/demo2/charts/iperf/templates/deployment.yaml b/examples/demo2/charts/iperf/templates/deployment.yaml new file mode 100755 index 0000000000000000000000000000000000000000..49dc9bba069cacb684920b442639afbfcb55e59a --- /dev/null +++ b/examples/demo2/charts/iperf/templates/deployment.yaml @@ -0,0 +1,27 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "meep.fullname" . }} + namespace: {{ .Values.namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ template "meep.name" . }} + release: {{ .Release.Name }} + template: + metadata: + namespace: {{ .Values.namespace }} + labels: + app: {{ template "meep.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: iperf + image: {{ .Values.deployment.image.name }} + imagePullPolicy: {{ .Values.deployment.image.pullpolicy }} + command: + - /bin/bash + args: + - -c + - export; iperf -s -p $IPERF_SERVICE_PORT; diff --git a/examples/demo2/charts/iperf/templates/service.yaml b/examples/demo2/charts/iperf/templates/service.yaml new file mode 100755 index 0000000000000000000000000000000000000000..33760e60265a429cbef2841bfd4215f59107f707 --- /dev/null +++ b/examples/demo2/charts/iperf/templates/service.yaml @@ -0,0 +1,18 @@ +kind: Service +apiVersion: v1 +metadata: + {{- if (eq "" .Values.service.name) }} + name: {{ template "meep.fullname" . }} + {{- else }} + name: {{ .Values.service.name }} + {{- end }} + namespace: default +spec: + type: ClusterIP + selector: + app: {{ template "meep.name" . }} + release: {{ .Release.Name }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: {{ .Values.service.protocol }} \ No newline at end of file diff --git a/examples/demo2/zoneX-edgeX-svc/values.yaml b/examples/demo2/charts/iperf/values.yaml similarity index 51% rename from examples/demo2/zoneX-edgeX-svc/values.yaml rename to examples/demo2/charts/iperf/values.yaml index 6c8abc8d88f71f52ee0b4fd341da6812dcb0ad50..43fbd2c92d883c9af425c78b88f0248419c199c1 100644 --- a/examples/demo2/zoneX-edgeX-svc/values.yaml +++ b/examples/demo2/charts/iperf/values.yaml @@ -2,10 +2,15 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -name: meep-demo2-svc-zoneX-edgeX-svc +namespace: default deployment: - name: zoneX-edgeX-svc - + image: + name: gophernet/iperf-server + pullpolicy: IfNotPresent + service: - name: zoneX-edgeX-svc + name: "" + port: 80 + protocol: UDP + group: iperf diff --git a/examples/demo2/charts/svc/Chart.yaml b/examples/demo2/charts/svc/Chart.yaml new file mode 100755 index 0000000000000000000000000000000000000000..99117f113980388246d03a1e76626ea67109e0b5 --- /dev/null +++ b/examples/demo2/charts/svc/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0.0" +description: Meep Demo Service Helm chart for Kubernetes +name: demo-svc +version: 1.0.0 diff --git a/examples/demo2/charts/svc/templates/_helpers.tpl b/examples/demo2/charts/svc/templates/_helpers.tpl new file mode 100755 index 0000000000000000000000000000000000000000..b39eb82fb2c1537c4de3c785122a91948e1fdcab --- /dev/null +++ b/examples/demo2/charts/svc/templates/_helpers.tpl @@ -0,0 +1,32 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "meep.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "meep.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "meep.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} diff --git a/examples/demo2/charts/svc/templates/deployment.yaml b/examples/demo2/charts/svc/templates/deployment.yaml new file mode 100755 index 0000000000000000000000000000000000000000..c715eae6c715352cce3966775e099a383347e8cc --- /dev/null +++ b/examples/demo2/charts/svc/templates/deployment.yaml @@ -0,0 +1,29 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ template "meep.fullname" . }} + namespace: {{ .Values.namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ template "meep.name" . }} + release: {{ .Release.Name }} + template: + metadata: + namespace: {{ .Values.namespace }} + labels: + app: {{ template "meep.name" . }} + release: {{ .Release.Name }} + spec: + containers: + - name: svc + image: {{ .Values.deployment.image.name }} + imagePullPolicy: {{ .Values.deployment.image.pullpolicy }} + env: + - name: MGM_APP_ID + value: "{{ .Values.service.name }}" + - name: MGM_APP_PORT + value: "{{ .Values.service.port }}" + - name: MGM_GROUP_NAME + value: "{{ .Values.service.group }}" diff --git a/examples/demo2/charts/svc/templates/service.yaml b/examples/demo2/charts/svc/templates/service.yaml new file mode 100755 index 0000000000000000000000000000000000000000..a0faaedb9b3d5e5e47ddbd521e7dfd677605e8e5 --- /dev/null +++ b/examples/demo2/charts/svc/templates/service.yaml @@ -0,0 +1,19 @@ +kind: Service +apiVersion: v1 +metadata: + {{- if (eq "" .Values.service.name) }} + name: {{ template "meep.fullname" . }} + {{- else }} + name: {{ .Values.service.name }} + {{- end }} + namespace: default +spec: + type: ClusterIP + selector: + app: {{ template "meep.name" . }} + release: {{ .Release.Name }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.service.port }} + protocol: {{ .Values.service.protocol }} + diff --git a/examples/demo2/zoneX-edgeX-iperf/values.yaml b/examples/demo2/charts/svc/values.yaml similarity index 53% rename from examples/demo2/zoneX-edgeX-iperf/values.yaml rename to examples/demo2/charts/svc/values.yaml index 515307228ced35f181f1e73426dee7903c6dc2cc..c5b49aa52fcd316552f5ea92ce0fe139a0d35220 100644 --- a/examples/demo2/zoneX-edgeX-iperf/values.yaml +++ b/examples/demo2/charts/svc/values.yaml @@ -2,10 +2,15 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -name: meep-demo-svc-zoneX-edgeX-iperf +namespace: default deployment: - name: zoneX-edgeX-iperf - + image: + name: demo-server + pullpolicy: IfNotPresent + service: - name: zoneX-edgeX-iperf + name: "" + port: 80 + protocol: TCP + group: svc diff --git a/examples/demo2/demo2-scenario.yaml b/examples/demo2/demo2-scenario.yaml index 8e3a918f81b0e1724a32f0b18d0d46f9ac531e4c..4d4bd2f8834f69a2b1f2a4a8ea7e72542e6670cf 100755 --- a/examples/demo2/demo2-scenario.yaml +++ b/examples/demo2/demo2-scenario.yaml @@ -66,8 +66,8 @@ deployment: id: cloud1-svc name: cloud1-svc type: CLOUD-APP - image: demo-svc-app-svr - environment: 'MGM_GROUP_NAME=svc-cloud, MGM_APP_ID=cloud1-svc, MGM_APP_PORT=80, MEEP_POD_NAME=cloud1-svc' + image: demo-server + environment: 'MGM_GROUP_NAME=cloud1-svc,MGM_APP_ID=cloud1-svc,MGM_APP_PORT=80' serviceConfig: name: cloud1-svc ports: @@ -156,21 +156,18 @@ deployment: id: zone1-edge1-iperf name: zone1-edge1-iperf type: EDGE-APP - serviceConfig: - name: zone1-edge1-iperf - ports: - - {protocol: null, port: null, externalPort: null} - meSvcName: null - userChartLocation: /home/englab/sim/zoneX-edgeX-iperf - userChartAlternateValues: /home/englab/sim/zone1-edge1-iperf-value.yaml - userChartGroup: 'azone1-edge1-iperf:iperf:80:UDP' + userChartLocation: ~/AdvantEDGE/examples/demo2/charts/iperf + userChartAlternateValues: ~/AdvantEDGE/examples/demo2/values/z1-e1-iperf-values.yaml + userChartGroup: 'zone1-edge1-iperf:iperf:80:UDP' isExternal: null image: null environment: null commandArguments: null commandExe: null + serviceConfig: null externalConfig: null status: null + userChartAlternateValues: null - id: zone1-edge1-svc name: zone1-edge1-svc @@ -180,9 +177,9 @@ deployment: ports: - {protocol: null, port: null, externalPort: null} meSvcName: null - userChartLocation: /home/englab/sim/zoneX-edgeX-svc - userChartAlternateValues: /home/englab/sim/zone1-edge1-svc-value.yaml - userChartGroup: 'azone1-edge1-svc:svc:80:TCP' + userChartLocation: ~/AdvantEDGE/examples/demo2/charts/svc + userChartAlternateValues: ~/AdvantEDGE/examples/demo2/values/z1-e1-svc-values.yaml + userChartGroup: 'zone1-edge1-svc:svc:80:TCP' isExternal: null image: null environment: null @@ -209,21 +206,18 @@ deployment: id: zone1-fog1-iperf name: zone1-fog1-iperf type: EDGE-APP - serviceConfig: - name: zone1-fog1-iperf - ports: - - {protocol: null, port: null, externalPort: null} - meSvcName: null - userChartLocation: /home/englab/sim/zoneX-edgeX-iperf - userChartAlternateValues: /home/englab/sim/zone1-fog1-iperf-value.yaml - userChartGroup: 'azone1-fog1-iperf:iperf:80:UDP' + userChartLocation: ~/AdvantEDGE/examples/demo2/charts/iperf + userChartAlternateValues: ~/AdvantEDGE/examples/demo2/values/z1-f1-iperf-values.yaml + userChartGroup: 'zone1-fog1-iperf:iperf:80:UDP' isExternal: null image: null environment: null commandArguments: null commandExe: null + serviceConfig: null externalConfig: null status: null + userChartAlternateValues: null - id: zone1-fog1-svc name: zone1-fog1-svc @@ -233,9 +227,9 @@ deployment: ports: - {protocol: null, port: null, externalPort: null} meSvcName: null - userChartLocation: /home/englab/sim/zoneX-edgeX-svc - userChartAlternateValues: /home/englab/sim/zone1-fog1-svc-value.yaml - userChartGroup: 'azone1-fog1-svc:svc:80:TCP' + userChartLocation: ~/AdvantEDGE/examples/demo2/charts/svc + userChartAlternateValues: ~/AdvantEDGE/examples/demo2/values/z1-f1-svc-values.yaml + userChartGroup: 'zone1-fog1-svc:svc:80:TCP' isExternal: null image: null environment: null @@ -360,21 +354,18 @@ deployment: id: zone2-edge1-iperf name: zone2-edge1-iperf type: EDGE-APP - serviceConfig: - name: zone2-edge1-iperf - ports: - - {protocol: null, port: null, externalPort: null} - meSvcName: null - userChartLocation: /home/englab/sim/zoneX-edgeX-iperf - userChartAlternateValues: /home/englab/sim/zone2-edge1-iperf-value.yaml - userChartGroup: 'azone2-edge1-iperf:iperf:80:UDP' + userChartLocation: ~/AdvantEDGE/examples/demo2/charts/iperf + userChartAlternateValues: ~/AdvantEDGE/examples/demo2/values/z2-e1-iperf-values.yaml + userChartGroup: 'zone2-edge1-iperf:iperf:80:UDP' isExternal: null image: null environment: null commandArguments: null commandExe: null + serviceConfig: null externalConfig: null status: null + userChartAlternateValues: null - id: zone2-edge1-svc name: zone2-edge1-svc @@ -384,9 +375,9 @@ deployment: ports: - {protocol: null, port: null, externalPort: null} meSvcName: null - userChartLocation: /home/englab/sim/zoneX-edgeX-svc - userChartAlternateValues: /home/englab/sim/zone2-edge1-svc-value.yaml - userChartGroup: 'azone2-edge1-svc:svc:80:TCP' + userChartLocation: ~/AdvantEDGE/examples/demo2/charts/svc + userChartAlternateValues: ~/AdvantEDGE/examples/demo2/values/z2-e1-svc-values.yaml + userChartGroup: 'zone2-edge1-svc:svc:80:TCP' isExternal: null image: null environment: null diff --git a/examples/demo2/zone1-fog1-svc-value.yaml b/examples/demo2/values/z1-e1-iperf-values.yaml similarity index 59% rename from examples/demo2/zone1-fog1-svc-value.yaml rename to examples/demo2/values/z1-e1-iperf-values.yaml index 1da2bfef2dce08beed1880b771aa79e62c0e7323..a1e7fde6df2a3233498b4830cf1dd9ae7a848ffe 100644 --- a/examples/demo2/zone1-fog1-svc-value.yaml +++ b/examples/demo2/values/z1-e1-iperf-values.yaml @@ -2,10 +2,5 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -name: meep-demo2-zone1-fog1-svc - -deployment: - name: zone1-fog1-svc - service: - name: azone1-fog1-svc + name: "zone1-edge1-iperf" \ No newline at end of file diff --git a/examples/demo2/zone2-edge1-svc-value.yaml b/examples/demo2/values/z1-e1-svc-values.yaml similarity index 58% rename from examples/demo2/zone2-edge1-svc-value.yaml rename to examples/demo2/values/z1-e1-svc-values.yaml index 4a0c51ee85695b5d6b8b8cfe1fe659313a634281..6400f8d26d6bfe9514d79967dfba13cc5e01925f 100644 --- a/examples/demo2/zone2-edge1-svc-value.yaml +++ b/examples/demo2/values/z1-e1-svc-values.yaml @@ -2,10 +2,5 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -name: meep-demo2-zone2-edge1-svc - -deployment: - name: zone2-edge1-svc - service: - name: azone2-edge1-svc + name: "zone1-edge1-svc" \ No newline at end of file diff --git a/examples/demo2/zone1-edge1-svc-value.yaml b/examples/demo2/values/z1-f1-iperf-values.yaml similarity index 58% rename from examples/demo2/zone1-edge1-svc-value.yaml rename to examples/demo2/values/z1-f1-iperf-values.yaml index 807b24dc3c519ba07981e06314758b47b7acedbe..d1384d60b3905703521541e543e49c322d8e18c7 100644 --- a/examples/demo2/zone1-edge1-svc-value.yaml +++ b/examples/demo2/values/z1-f1-iperf-values.yaml @@ -2,10 +2,5 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -name: meep-demo2-zone1-edge1-svc - -deployment: - name: zone1-edge1-svc - service: - name: azone1-edge1-svc + name: "zone1-fog1-iperf" \ No newline at end of file diff --git a/examples/demo2/zone1-fog1-iperf-value.yaml b/examples/demo2/values/z1-f1-svc-values.yaml similarity index 57% rename from examples/demo2/zone1-fog1-iperf-value.yaml rename to examples/demo2/values/z1-f1-svc-values.yaml index 545ebb43162171cc3adf84d94b9edca8d111cf40..92d84ef791dc0a27f4367fd695fbd7994938016a 100644 --- a/examples/demo2/zone1-fog1-iperf-value.yaml +++ b/examples/demo2/values/z1-f1-svc-values.yaml @@ -2,10 +2,5 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -name: meep-demo2-zone1-fog1-iperf - -deployment: - name: zone1-fog1-iperf - service: - name: azone1-fog1-iperf + name: "zone1-fog1-svc" \ No newline at end of file diff --git a/examples/demo2/values/z2-e1-iperf-values.yaml b/examples/demo2/values/z2-e1-iperf-values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3ede0f7ee84e56e8b473a7fdb9756249637eee12 --- /dev/null +++ b/examples/demo2/values/z2-e1-iperf-values.yaml @@ -0,0 +1,6 @@ +# Default values for generic values.yaml +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +service: + name: "zone2-edge1-iperf" diff --git a/examples/demo2/values/z2-e1-svc-values.yaml b/examples/demo2/values/z2-e1-svc-values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f5f0cae7780f18c8be139bdaeb221c64bf5bc35f --- /dev/null +++ b/examples/demo2/values/z2-e1-svc-values.yaml @@ -0,0 +1,6 @@ +# Default values for generic values.yaml +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +service: + name: "zone2-edge1-svc" diff --git a/examples/demo2/zone1-edge1-iperf-value.yaml b/examples/demo2/zone1-edge1-iperf-value.yaml deleted file mode 100644 index fc7fa7ca1474a1bf795e99dab77bb4437e5d0623..0000000000000000000000000000000000000000 --- a/examples/demo2/zone1-edge1-iperf-value.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Default values for generic values.yaml -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -name: meep-demo2-zone1-edge1-iperf - -deployment: - name: zone1-edge1-iperf - -service: - name: azone1-edge1-iperf diff --git a/examples/demo2/zone2-edge1-iperf-value.yaml b/examples/demo2/zone2-edge1-iperf-value.yaml deleted file mode 100644 index 56c1f281061c1b7c2499d46fb90c3e4cb989a245..0000000000000000000000000000000000000000 --- a/examples/demo2/zone2-edge1-iperf-value.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# Default values for generic values.yaml -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -name: meep-demo2-zone2-edge1-iperf - -deployment: - name: zone2-edge1-iperf - -service: - name: azone2-edge1-iperf diff --git a/examples/demo2/zoneX-edgeX-iperf/Chart.yaml b/examples/demo2/zoneX-edgeX-iperf/Chart.yaml deleted file mode 100755 index 18ddc36eece4241181c2d57398c751d66798359a..0000000000000000000000000000000000000000 --- a/examples/demo2/zoneX-edgeX-iperf/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0.0" -description: Meep Demo App Helm chart for Kubernetes -name: meep-demo -version: 1.0.0 diff --git a/examples/demo2/zoneX-edgeX-iperf/templates/_helpers.tpl b/examples/demo2/zoneX-edgeX-iperf/templates/_helpers.tpl deleted file mode 100755 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/examples/demo2/zoneX-edgeX-iperf/templates/deployment.yaml b/examples/demo2/zoneX-edgeX-iperf/templates/deployment.yaml deleted file mode 100755 index e498e00003831f46633109ce8fc5d0cac2d2a9cd..0000000000000000000000000000000000000000 --- a/examples/demo2/zoneX-edgeX-iperf/templates/deployment.yaml +++ /dev/null @@ -1,27 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .Values.name }} - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - dummy: "dummy" - template: - metadata: - namespace: default - labels: - dummy: "dummy" - - spec: - serviceAccountName: meep-user - containers: - - name: {{ .Values.deployment.name }} - image: gophernet/iperf-server - imagePullPolicy: IfNotPresent - command: - - /bin/bash - args: - - -c - - export; iperf -s -p $IPERF_SERVICE_PORT; diff --git a/examples/demo2/zoneX-edgeX-iperf/templates/service.yaml b/examples/demo2/zoneX-edgeX-iperf/templates/service.yaml deleted file mode 100755 index 1a55c9bec7cbb5fdce944269d05d8ddbaabf9f94..0000000000000000000000000000000000000000 --- a/examples/demo2/zoneX-edgeX-iperf/templates/service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: {{ .Values.service.name }} - namespace: default - labels: - dummy: "dummy" -spec: - type: ClusterIP - selector: - dummy: "dummy" - ports: - - name: port-80 - port: 80 - targetPort: 80 - protocol: UDP - diff --git a/examples/demo2/zoneX-edgeX-svc/Chart.yaml b/examples/demo2/zoneX-edgeX-svc/Chart.yaml deleted file mode 100755 index 18ddc36eece4241181c2d57398c751d66798359a..0000000000000000000000000000000000000000 --- a/examples/demo2/zoneX-edgeX-svc/Chart.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -appVersion: "1.0.0" -description: Meep Demo App Helm chart for Kubernetes -name: meep-demo -version: 1.0.0 diff --git a/examples/demo2/zoneX-edgeX-svc/templates/_helpers.tpl b/examples/demo2/zoneX-edgeX-svc/templates/_helpers.tpl deleted file mode 100755 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/examples/demo2/zoneX-edgeX-svc/templates/deployment.yaml b/examples/demo2/zoneX-edgeX-svc/templates/deployment.yaml deleted file mode 100755 index afa5d873c7da6721df7816b0029da6a27cdd9703..0000000000000000000000000000000000000000 --- a/examples/demo2/zoneX-edgeX-svc/templates/deployment.yaml +++ /dev/null @@ -1,31 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ .Values.name }} - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - dummy: "dummy" - template: - metadata: - namespace: default - labels: - dummy: "dummy" - - spec: - serviceAccountName: meep-user - containers: - - name: {{ .Values.deployment.name }} - image: demo1-server - imagePullPolicy: IfNotPresent - env: - - name: MGM_APP_ID - value: {{ .Values.deployment.name }} - - name: MGM_APP_PORT - value: "80" - - name: MGM_GROUP_NAME - value: "svc" - - name: MEEP_POD_NAME - value: {{ .Values.deployment.name }} diff --git a/examples/demo2/zoneX-edgeX-svc/templates/service.yaml b/examples/demo2/zoneX-edgeX-svc/templates/service.yaml deleted file mode 100755 index 64047b455b65ed7a45a94d4a67d083358a177b97..0000000000000000000000000000000000000000 --- a/examples/demo2/zoneX-edgeX-svc/templates/service.yaml +++ /dev/null @@ -1,17 +0,0 @@ -kind: Service -apiVersion: v1 -metadata: - name: {{ .Values.service.name }} - namespace: default - labels: - dummy: "dummy" -spec: - type: ClusterIP - selector: - dummy: "dummy" - ports: - - name: port-80 - port: 80 - targetPort: 80 - protocol: TCP - diff --git a/go-apps/meep-ctrl-engine/.swagger-codegen-ignore b/go-apps/meep-ctrl-engine/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/go-apps/meep-ctrl-engine/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/go-apps/meep-ctrl-engine/.swagger-codegen/VERSION b/go-apps/meep-ctrl-engine/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..a6254504e40175d135cea7feb34ad31fa0d0bca3 --- /dev/null +++ b/go-apps/meep-ctrl-engine/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.1 \ No newline at end of file diff --git a/go-apps/meep-ctrl-engine/.vscode/launch.json b/go-apps/meep-ctrl-engine/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..88f947a593849d51805fb76b92313628d13a263c --- /dev/null +++ b/go-apps/meep-ctrl-engine/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch", + "type": "go", + "request": "launch", + "mode": "debug", + "remotePath": "", + "port": 2345, + "host": "127.0.0.1", + "program": "${fileDirname}", + "env": {}, + "args": [], + "showLog": true + } + ] +} \ No newline at end of file diff --git a/go-apps/meep-ctrl-engine/Dockerfile b/go-apps/meep-ctrl-engine/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..d9d03d53b6b0e5524237305b793dffb6fc84754c --- /dev/null +++ b/go-apps/meep-ctrl-engine/Dockerfile @@ -0,0 +1,11 @@ +# Copyright (c) 2019 +# InterDigital Communications, Inc. +# All rights reserved. +# +# The information provided herein is the proprietary and confidential +# information of InterDigital Communications, Inc. + +FROM debian:9.6-slim +COPY ./meep-ctrl-engine /meep-ctrl-engine +COPY ./static /static +ENTRYPOINT /meep-ctrl-engine diff --git a/bin/meep-ctrl-engine/static/api/meep-ctrl-engine.yaml b/go-apps/meep-ctrl-engine/api/swagger.yaml similarity index 99% rename from bin/meep-ctrl-engine/static/api/meep-ctrl-engine.yaml rename to go-apps/meep-ctrl-engine/api/swagger.yaml index 15a6b4766d024ddeae86a132b441ce01c1b86246..2bd4fafe5116a4e3e2f74b61b506e78b2447ccda 100644 --- a/bin/meep-ctrl-engine/static/api/meep-ctrl-engine.yaml +++ b/go-apps/meep-ctrl-engine/api/swagger.yaml @@ -1,7 +1,9 @@ --- swagger: "2.0" info: - description: "MEEP Controller REST API" + description: "Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved.\ + \ The information provided herein is the proprietary and confidential information\ + \ of InterDigital Communications, Inc.\n" version: "1.0.0" title: "MEEP Controller REST API" basePath: "/v1" @@ -2462,12 +2464,6 @@ definitions: nbPodRestart: "15005" startTime: "2018-09-10 14:24:00 +0000 UTC" parameters: - AppName: - in: "body" - name: "appName" - description: "App name string" - required: true - x-exportParamName: "AppName" Name: name: "name" in: "path" @@ -2498,18 +2494,6 @@ parameters: schema: $ref: "http://localhost:8291/meep-model.yaml#/definitions/Event" x-exportParamName: "Event" - PodName: - in: "body" - name: "podName" - description: "Pod name string" - required: true - x-exportParamName: "PodName" - PodType: - in: "body" - name: "podType" - description: "Pod type string" - required: true - x-exportParamName: "PodType" Settings: in: "body" name: "settings" @@ -2518,12 +2502,6 @@ parameters: schema: $ref: "http://localhost:8291/meep-model.yaml#/definitions/Settings" x-exportParamName: "Settings" - ScenarioName: - in: "body" - name: "scenarioName" - description: "Scenario name string" - required: true - x-exportParamName: "ScenarioName" responses: Std200: description: "OK" diff --git a/go-apps/meep-ctrl-engine/go.mod b/go-apps/meep-ctrl-engine/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..a44f706ee5d4804ffc1cbe6ca949870405c28f6e --- /dev/null +++ b/go-apps/meep-ctrl-engine/go.mod @@ -0,0 +1,42 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-ctrl-engine + +go 1.12 + +require ( + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-virt-engine-client v0.0.0 + github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db // indirect + github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351 + github.com/flimzy/diff v0.1.5 // indirect + github.com/flimzy/kivik v1.8.1 + github.com/flimzy/testy v0.1.16 // indirect + github.com/go-kivik/couchdb v1.8.1 + github.com/go-redis/redis v6.15.2+incompatible + github.com/gogo/protobuf v1.2.1 // indirect + github.com/google/btree v1.0.0 // indirect + github.com/google/gofuzz v1.0.0 // indirect + github.com/googleapis/gnostic v0.2.0 // indirect + github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e // indirect + github.com/gorilla/handlers v1.4.0 + github.com/gorilla/mux v1.7.1 + github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect + github.com/imdario/mergo v0.3.7 // indirect + github.com/json-iterator/go v1.1.6 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pkg/errors v0.8.1 // indirect + github.com/sirupsen/logrus v1.4.1 + github.com/spf13/pflag v1.0.3 // indirect + golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect + k8s.io/api v0.0.0-20181204000039-89a74a8d264d // indirect + k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 // indirect + k8s.io/client-go v10.0.0+incompatible // indirect + k8s.io/klog v0.0.0-20181108234604-8139d8cb77af // indirect + sigs.k8s.io/yaml v1.1.0 // indirect +) + +replace github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-virt-engine-client => ../../go-packages/meep-virt-engine-client diff --git a/go-apps/meep-ctrl-engine/go.sum b/go-apps/meep-ctrl-engine/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..d2b8e823571e28cc9dfc3cd3b50665093224f700 --- /dev/null +++ b/go-apps/meep-ctrl-engine/go.sum @@ -0,0 +1,114 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db h1:Zkf5kwhxdW0xV7WM/crqIcOP5LCFGnAmumWSFAewJ74= +github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db/go.mod h1:RU+6d0CNIRSp6yo1mXLIIrnFa/3LHhvcDVLVJyovptM= +github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351 h1:1u1XrfCBnY+GijnyU6O1k4odp5TnqZQTsp5v7+n/E4Y= +github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351/go.mod h1:HxwfbuElTuGf+/uKZfjJrCnv0BmmpkPJDI7gBwj1KkM= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/flimzy/diff v0.1.5 h1:QfOwp+TuGCeWWFxFtXqCdepnz0SeaImgNfMm6vWz3y8= +github.com/flimzy/diff v0.1.5/go.mod h1:lFJtC7SPsK0EroDmGTSrdtWKAxOk3rO+q+e04LL05Hs= +github.com/flimzy/kivik v1.8.1 h1:URl7e0OnfSvAu3ZHQ5BkvzRZlCmyYuDyWUCcPWIHlU0= +github.com/flimzy/kivik v1.8.1/go.mod h1:S2aPycbG0eDFll4wgXt9uacSNkXISPufutnc9sv+mdA= +github.com/flimzy/testy v0.1.16 h1:nchF7XYCkfHJiZKMRhAVKQp8jzpXFPwJYnSrnFysqlI= +github.com/flimzy/testy v0.1.16/go.mod h1:3szguN8NXqgq9bt9Gu8TQVj698PJWmyx/VY1frwwKrM= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-kivik/couchdb v1.8.1 h1:2yjmysS48JYpyWTkx2E3c7ASZP8Kh0eABWnkKlV8bbw= +github.com/go-kivik/couchdb v1.8.1/go.mod h1:5XJRkAMpBlEVA4q0ktIZjUPYBjoBmRoiWvwUBzP3BOQ= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e h1:XWcjeEtTFTOVA9Fs1w7n2XBftk5ib4oZrhzWk0B+3eA= +github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= +github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= +github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 h1:tzVWzOrXxwAwdSCMrf+mbNrZFxwS0+HLP4m2qxtfdhk= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +k8s.io/api v0.0.0-20181204000039-89a74a8d264d h1:HQoGWsWUe/FmRcX9BU440AAMnzBFEf+DBo4nbkQlNzs= +k8s.io/api v0.0.0-20181204000039-89a74a8d264d/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 h1:tT6oQBi0qwLbbZSfDkdIsb23EwaLY85hoAV4SpXfdao= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34= +k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/klog v0.0.0-20181108234604-8139d8cb77af h1:s6rm8OxBbyDNSRkpyAd5OL4icUdBICVw9+mFADa+t5E= +k8s.io/klog v0.0.0-20181108234604-8139d8cb77af/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/go-apps/meep-ctrl-engine/log/meeplog.go b/go-apps/meep-ctrl-engine/log/meeplog.go new file mode 100644 index 0000000000000000000000000000000000000000..7e4c1b9929b777dc58143c556063ecbf25340bc8 --- /dev/null +++ b/go-apps/meep-ctrl-engine/log/meeplog.go @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package logmain + +import ( + log "github.com/sirupsen/logrus" +) + +func MeepJSONLogInit() { + log.SetFormatter(&log.JSONFormatter{}) + log.SetLevel(log.DebugLevel) +} + +func Info(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "ctrl-engine", + }).Info(args...) +} + +func Debug(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "ctrl-engine", + }).Debug(args...) +} + +func Warn(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "ctrl-engine", + }).Warn(args...) +} +func Error(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "ctrl-engine", + }).Error(args...) +} +func Panic(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "ctrl-engine", + }).Panic(args...) +} + +func Fatal(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "ctrl-engine", + }).Fatal(args...) +} + +func WithFields(fields log.Fields) *log.Entry { + return log.WithFields(fields) +} diff --git a/go-apps/meep-ctrl-engine/main.go b/go-apps/meep-ctrl-engine/main.go new file mode 100644 index 0000000000000000000000000000000000000000..a22fa1bdc8ec8cffc9da9d90a855474653058846 --- /dev/null +++ b/go-apps/meep-ctrl-engine/main.go @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "net/http" + "os" + "os/signal" + "syscall" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-ctrl-engine/log" + server "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-ctrl-engine/server" + + "github.com/gorilla/handlers" +) + +func init() { + log.MeepJSONLogInit() +} + +func main() { + log.Info(os.Args) + + log.Info("Starting MEEP Controller Engine") + + run := true + go func() { + sigchan := make(chan os.Signal, 10) + signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) + <-sigchan + log.Info("Program killed !") + // do last actions and wait for all write operations to end + run = false + }() + + go func() { + // Initialize Ctrl Engine + err := server.CtrlEngineInit() + if err != nil { + log.Error("Failed to initialize Ctrl Engine") + run = false + return + } + + // Start REST API Server + router := server.NewRouter() + methods := handlers.AllowedMethods([]string{"OPTIONS", "DELETE", "GET", "HEAD", "POST", "PUT"}) + header := handlers.AllowedHeaders([]string{"content-type"}) + log.Fatal(http.ListenAndServe(":80", handlers.CORS(methods, header)(router))) + run = false + }() + + count := 0 + for { + if !run { + log.Info("Ran for", count, "seconds") + break + } + time.Sleep(time.Second) + count++ + } +} diff --git a/go-apps/meep-ctrl-engine/main_test.go b/go-apps/meep-ctrl-engine/main_test.go new file mode 100644 index 0000000000000000000000000000000000000000..ce7bd1d1262bba26de1d4e0c994a995a8153e2dc --- /dev/null +++ b/go-apps/meep-ctrl-engine/main_test.go @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "os" + "strings" + "testing" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-ctrl-engine/log" +) + +// Build: +// $ go test -covermode=count -coverpkg=./... -c -o +// Run: +// $ ./ -test.coverprofile=cover.out __DEVEL--code-cov + +// TestMain is a hack that allows us to figure out what the coverage is during +// integration tests. I would not recommend that you use a binary built using +// this hack outside of a test suite. +func TestMain(t *testing.T) { + var ( + args []string + run bool + ) + + log.Info(os.Args) + for _, arg := range os.Args { + switch { + case arg == "__DEVEL--code-cov": + run = true + case strings.HasPrefix(arg, "-test"): + case strings.HasPrefix(arg, "__DEVEL"): + default: + args = append(args, arg) + } + } + os.Args = args + log.Info(os.Args) + + if run { + main() + } +} diff --git a/go-apps/meep-ctrl-engine/meep-ctrl.code-workspace b/go-apps/meep-ctrl-engine/meep-ctrl.code-workspace new file mode 100644 index 0000000000000000000000000000000000000000..876a1499c09dc083612f43c53c0ae71b9c30c5b1 --- /dev/null +++ b/go-apps/meep-ctrl-engine/meep-ctrl.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/go-apps/meep-ctrl-engine/server/README.md b/go-apps/meep-ctrl-engine/server/README.md new file mode 100644 index 0000000000000000000000000000000000000000..b89401f81474f3eaa442255a8f240cd8ba07d3ec --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/README.md @@ -0,0 +1,25 @@ +# Go API Server for server + +Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + +## Overview +This server was generated by the [swagger-codegen] +(https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) + +- API version: 1.0.0 +- Build date: 2019-05-15T12:26:15.220-04:00 + + +### Running the server +To run the server, follow these simple steps: + +``` +go run main.go +``` + diff --git a/go-apps/meep-ctrl-engine/server/client_service_map.go b/go-apps/meep-ctrl-engine/server/client_service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..d159dfe1a7ade80f90ed9c3b6680f76494c2f74a --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/client_service_map.go @@ -0,0 +1,19 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Client-specific list of mappings of exposed port to internal service +type ClientServiceMap struct { + + // Unique external client identifier + Client string `json:"client,omitempty"` + + ServiceMap []ServiceMap `json:"serviceMap,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/ctrl-engine.go b/go-apps/meep-ctrl-engine/server/ctrl-engine.go new file mode 100644 index 0000000000000000000000000000000000000000..1a6f8227e22ba4156c7c7340fc03a5a48c0274b4 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/ctrl-engine.go @@ -0,0 +1,1180 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package server + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "sort" + "strings" + + "github.com/flimzy/kivik" + _ "github.com/go-kivik/couchdb" + "github.com/gorilla/mux" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-ctrl-engine/log" + ve "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-virt-engine-client" +) + +const scenarioDBName = "scenarios" +const activeScenarioName = "active" +const moduleCtrlEngine string = "ctrl-engine" +const moduleMonEngine string = "mon-engine" + +const typeActive string = "active" +const channelCtrlActive string = moduleCtrlEngine + "-" + typeActive + +const ALLUP = "0" +const ATLEASTONENOTUP = "1" +const NOUP = "2" + +const NB_CORE_PODS = 9 //although virt-engine is not a pod yet... it is considered as one as is appended to the list of pods + +var virtEngine *ve.APIClient + +var db *kivik.DB + +var clientServiceMapList []ClientServiceMap + +func getCorePodsList() map[string]bool { + + innerMap := map[string]bool{ + "meep-couchdb": false, + "meep-ctrl-engine": false, + "meep-webhook": false, + "meep-mg-manager": false, + "meep-mon-engine": false, + "meep-tc-engine": false, + "meep-metricbeat": false, + "virt-engine": false, + } + return innerMap +} + +// Establish new couchDB connection +func connectDb(dbName string) (*kivik.DB, error) { + + // Connect to Couch DB + log.Debug("Establish new couchDB connection") + dbClient, err := kivik.New(context.TODO(), "couch", "http://meep-couchdb-svc-couchdb:5984/") + if err != nil { + return nil, err + } + + // Create Scenario DB if id does not exist + log.Debug("Check if scenario DB exists: " + dbName) + debExists, err := dbClient.DBExists(context.TODO(), dbName) + if err != nil { + return nil, err + } + if !debExists { + log.Debug("Create new DB: " + dbName) + err = dbClient.CreateDB(context.TODO(), dbName) + if err != nil { + return nil, err + } + } + + // Open scenario DB + log.Debug("Open scenario DB: " + dbName) + db, err := dbClient.DB(context.TODO(), dbName) + if err != nil { + return nil, err + } + + return db, nil +} + +// Get scenario from DB +func getScenario(returnNilOnNotFound bool, db *kivik.DB, scenarioName string, scenario interface{}) error { + + // Get scenario from DB + log.Debug("Get scenario from DB: " + scenarioName) + row, err := db.Get(context.TODO(), scenarioName) + if err != nil { + //that's a call to the couch DB.. in order not to return nil, we override it + if returnNilOnNotFound { + if err.Error() == "Not Found: deleted" { + //specifically for the case where there is nothing.. so the scenario object will be empty + return nil + } + } + return err + } + // Decode JSON-encoded document + return row.ScanDoc(scenario) +} + +// Get scenario list from DB +func getScenarioList(db *kivik.DB, scenarioList *ScenarioList) error { + + // Retrieve all scenarios from DB + log.Debug("Get all scenarios from DB") + rows, err := db.AllDocs(context.TODO()) + if err != nil { + return err + } + + // Loop through scenarios and populate scenario list to return + log.Debug("Loop through scenarios") + for rows.Next() { + var scenario Scenario + if rows.ID() != activeScenarioName { + err = getScenario(false, db, rows.ID(), &scenario) + if err == nil { + // Append scenario to list + scenarioList.Scenarios = append(scenarioList.Scenarios, scenario) + } + } + } + + return nil +} + +// Add scenario to DB +func addScenario(db *kivik.DB, scenarioName string, scenario interface{}) (string, error) { + + // Add scenario to DB + log.Debug("Add new scenario to DB: " + scenarioName) + rev, err := db.Put(context.TODO(), scenarioName, scenario) + if err != nil { + return "", err + } + + // Add active scenario to Redis DB & publish update + // - Marshal object to JSON string + // - Store in Redis DB as REJSON object + // - Publish active scenario update event + if scenarioName == activeScenarioName { + jsonScenario, err := json.Marshal(scenario) + if err != nil { + log.Error(err.Error()) + return "", err + } + err = RedisDBJsonSetEntry(moduleCtrlEngine+":"+scenarioName, ".", string(jsonScenario)) + if err != nil { + log.Error(err.Error()) + return "", err + } + err = RedisDBPublish(channelCtrlActive, "") + if err != nil { + log.Error(err.Error()) + } + } + + return rev, nil +} + +// Update scenario in DB +func setScenario(db *kivik.DB, scenarioName string, scenario Scenario) (string, error) { + + // Remove previous version + err := removeScenario(db, scenarioName) + if err != nil { + return "", err + } + + // Add updated version + rev, err := addScenario(db, scenarioName, scenario) + if err != nil { + return "", err + } + + return rev, nil +} + +// Remove scenario from DB +func removeScenario(db *kivik.DB, scenarioName string) error { + + // Get latest Rev of stored scenario to remove + rev, err := db.Rev(context.TODO(), scenarioName) + if err != nil { + return err + } + + // Remove scenario from DB + log.Debug("Remove scenario from DB: " + scenarioName) + _, err = db.Delete(context.TODO(), scenarioName, rev) + if err != nil { + return err + } + + // Remove active scenario from Redis DB + // NOTE: Update not published here because remove is also called on updates + // TODO: Don't remove on update... + if scenarioName == activeScenarioName { + err = RedisDBJsonDelEntry(moduleCtrlEngine+":"+scenarioName, ".") + if err != nil { + log.Error(err.Error()) + return err + } + } + + return nil +} + +// Remove all scenarios from DB +func removeAllScenarios(db *kivik.DB) error { + + // Retrieve all scenarios from DB + log.Debug("Get all scenarios from DB") + rows, err := db.AllDocs(context.TODO()) + if err != nil { + return err + } + + // Loop through scenarios and remove each one + log.Debug("Loop through scenarios") + for rows.Next() { + _ = removeScenario(db, rows.ID()) + } + + return nil +} + +func populateClientServiceMap(activeScenario *Scenario) { + + // Clear client service mapping if there is no active scenario + if activeScenario == nil { + clientServiceMapList = nil + return + } + + // Parse through scenario and fill external client service mappings + for _, domain := range activeScenario.Deployment.Domains { + for _, zone := range domain.Zones { + for _, nl := range zone.NetworkLocations { + for _, pl := range nl.PhysicalLocations { + for _, proc := range pl.Processes { + if proc.IsExternal { + // Create new client service map + var clientServiceMap ClientServiceMap + clientServiceMap.Client = proc.Name + clientServiceMap.ServiceMap = append(clientServiceMap.ServiceMap, + proc.ExternalConfig.IngressServiceMap...) + + // Add new map to list + clientServiceMapList = append(clientServiceMapList, clientServiceMap) + } + } + } + } + } + } +} + +// CtrlEngineInit Initializes the Controller Engine +func CtrlEngineInit() (err error) { + log.Debug("CtrlEngineInit") + + // Make Scenario DB connection + db, err = connectDb(scenarioDBName) + if err != nil { + log.Error("Failed connection to Scenario DB. Error: ", err) + return err + } + log.Info("Connected to Scenario DB") + + // Connect to Redis DB + err = RedisDBConnect() + if err != nil { + log.Error("Failed connection to Active DB. Error: ", err) + return err + } + log.Info("Connected to Active DB") + + // Create client for Virtualization Engine API + veCfg := ve.NewConfiguration() + veCfg.BasePath = "http://meep-virt-engine/v1" + virtEngine = ve.NewAPIClient(veCfg) + if virtEngine == nil { + log.Debug("Cannot find the Virtualization Engine API") + return err + } + log.Info("Created Virt Engine client") + + return nil +} + +// Create a new scenario in store +func ceCreateScenario(w http.ResponseWriter, r *http.Request) { + log.Debug("ceCreateScenario") + + // Get scenario name from request parameters + vars := mux.Vars(r) + scenarioName := vars["name"] + log.Debug("Scenario name: ", scenarioName) + + // Retrieve scenario from request body + var scenario Scenario + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Add new scenario to DB + rev, err := addScenario(db, scenarioName, scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + log.Debug("Scenario added with rev: ", rev) + + // OK + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// Delete scenario from store +func ceDeleteScenario(w http.ResponseWriter, r *http.Request) { + log.Debug("ceDeleteScenario") + + // Get scenario name from request parameters + vars := mux.Vars(r) + scenarioName := vars["name"] + log.Debug("Scenario name: ", scenarioName) + + // Remove scenario from DB + err := removeScenario(db, scenarioName) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + // OK + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// Remove all scenarios from DB +func ceDeleteScenarioList(w http.ResponseWriter, r *http.Request) { + log.Debug("ceDeleteScenarioList") + + // Remove all scenario from DB + err := removeAllScenarios(db) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// Retrieve the requested scenario +func ceGetScenario(w http.ResponseWriter, r *http.Request) { + log.Debug("ceGetScenario") + + // Get scenario name from request parameters + vars := mux.Vars(r) + scenarioName := vars["name"] + log.Debug("Scenario name: ", scenarioName) + + // Validate scenario name + if scenarioName == "" { + log.Debug("Invalid scenario name") + http.Error(w, "Invalid scenario name", http.StatusBadRequest) + return + } + + // Retrieve scenario from DB + var scenario Scenario + err := getScenario(false, db, scenarioName, &scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + // Format response + jsonResponse, err := json.Marshal(scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Send response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} + +func ceGetScenarioList(w http.ResponseWriter, r *http.Request) { + log.Debug("ceGetScenarioList") + + // Retrieve scenario list from DB + var scenarioList ScenarioList + err := getScenarioList(db, &scenarioList) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + // Format response + jsonResponse, err := json.Marshal(scenarioList) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} + +// Update stored scenario +func ceSetScenario(w http.ResponseWriter, r *http.Request) { + log.Debug("ceSetScenario") + + // Get scenario name from request parameters + vars := mux.Vars(r) + scenarioName := vars["name"] + log.Debug("Scenario name: ", scenarioName) + + // Retrieve scenario from request body + var scenario Scenario + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Update scenario in DB + rev, err := setScenario(db, scenarioName, scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + log.Debug("Scenario updated with rev: ", rev) + + // OK + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// Activate/Deploy scenario +func ceActivateScenario(w http.ResponseWriter, r *http.Request) { + log.Debug("ceActivateScenario") + + // Get scenario name from request parameters + vars := mux.Vars(r) + scenarioName := vars["name"] + log.Debug("Scenario name: ", scenarioName) + + // Make sure scenario is not already deployed + var activeScenario Scenario + err := getScenario(false, db, activeScenarioName, &activeScenario) + if err == nil { + log.Error("Scenario already active") + http.Error(w, "Scenario already active", http.StatusBadRequest) + return + } + + // Retrieve scenario to activate from DB + + // !!!!! IMPORTANT NOTE !!!!! + // Scenario stored in DB is unmarshalled into a VE Scenario object + var veScenario ve.Scenario + err = getScenario(false, db, scenarioName, &veScenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + // Set active scenario in DB + rev, err := addScenario(db, activeScenarioName, veScenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + log.Debug("Active scenario set with rev: ", rev) + + // Activate scenario in virtualization Engine + //lint:ignore SA1012 context.TODO not supported here + resp, err := virtEngine.ScenarioDeploymentApi.ActivateScenario(nil, veScenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + _ = removeScenario(db, activeScenarioName) + return + } + + // Retrieve active scenario stored in DB + err = getScenario(false, db, activeScenarioName, &activeScenario) + if err != nil { + log.Error("Scenario not active") + http.Error(w, "Scenario not active", http.StatusBadRequest) + _ = removeScenario(db, activeScenarioName) + return + } + + // Populate active external client service map + populateClientServiceMap(&activeScenario) + + // Return response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + if resp != nil { + w.WriteHeader(resp.StatusCode) + } else { + w.WriteHeader(http.StatusOK) + } +} + +// ceGetActiveScenario retrieves the deployed scenario status +func ceGetActiveScenario(w http.ResponseWriter, r *http.Request) { + log.Debug("CEGetActiveScenario") + + // Retrieve active scenario + var scenario Scenario + err := getScenario(true, db, activeScenarioName, &scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + // NOTE: For now, return full scenario without status information. + // Eventually, we will need to fetch latest status information from DB or k8s. + + // // Create Scenario object + // var deployment Deployment + // var scenario Scenario + // scenario.Name = "Edge-Enabled 5G Video" + // scenario.Deployment = &deployment + + // err := monitorActiveDeployment(&deployment) + // if err != nil { + // log.Error(err.Error()) + // http.Error(w, err.Error(), http.StatusInternalServerError) + // return + // } + + // Format response + jsonResponse, err := json.Marshal(scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Send response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} + +// ceGetActiveClientServiceMaps retrieves the deployed scenario external client service mappings +// NOTE: query parameters 'client' and 'service' may be specified to filter results +func ceGetActiveClientServiceMaps(w http.ResponseWriter, r *http.Request) { + log.Debug("ceGetActiveClientServiceMaps") + var filteredList *[]ClientServiceMap + + // Retrieve client ID & service name from query parameters + query := r.URL.Query() + client := query.Get("client") + service := query.Get("service") + + // Filter only requested service mappings from client service map list + if client == "" && service == "" { + // Any client & service + filteredList = &clientServiceMapList + } else { + filteredList = new([]ClientServiceMap) + if service == "" { + // Any service for requested client + for _, clientServiceMap := range clientServiceMapList { + if clientServiceMap.Client == client { + *filteredList = append(*filteredList, clientServiceMap) + break + } + } + } else if client == "" { + // Any client for requested service + for _, clientServiceMap := range clientServiceMapList { + var svcMap ClientServiceMap + svcMap.Client = clientServiceMap.Client + for _, serviceMap := range clientServiceMap.ServiceMap { + if serviceMap.Name == service { + svcMap.ServiceMap = append(svcMap.ServiceMap, serviceMap) + break + } + } + + // Only append if at least one match found + if len(svcMap.ServiceMap) > 0 { + *filteredList = append(*filteredList, svcMap) + } + } + } else { + // Requested client and service + for _, clientServiceMap := range clientServiceMapList { + if clientServiceMap.Client == client { + for _, serviceMap := range clientServiceMap.ServiceMap { + if serviceMap.Name == service { + var svcMap ClientServiceMap + svcMap.Client = clientServiceMap.Client + svcMap.ServiceMap = append(svcMap.ServiceMap, serviceMap) + + *filteredList = append(*filteredList, svcMap) + break + } + } + break + } + } + } + } + + // Format response + jsonResponse, err := json.Marshal(*filteredList) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Send response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} + +// Terminate the active/deployed scenario +func ceTerminateScenario(w http.ResponseWriter, r *http.Request) { + log.Debug("ceTerminateScenario") + + // Clear active external client service map + populateClientServiceMap(nil) + + // Retrieve active scenario from DB + var scenario Scenario + err := getScenario(false, db, activeScenarioName, &scenario) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + // Remove active scenario from DB + err = removeScenario(db, activeScenarioName) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + // Publish active scenario update event + err = RedisDBPublish(channelCtrlActive, "") + if err != nil { + log.Error(err.Error()) + } + + // Terminate scenario in virtualization Engine + //lint:ignore SA1012 context.TODO not supported here + resp, err := virtEngine.ScenarioDeploymentApi.TerminateScenario(nil, scenario.Name) + if err != nil { + log.Error(err.Error()) + } + + // Send response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + if resp != nil { + w.WriteHeader(resp.StatusCode) + } else { + w.WriteHeader(http.StatusOK) + } +} + +func ceGetEventList(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func sendEventNetworkCharacteristics(event Event) (string, int) { + + // Retrieve active scenario + var scenario Scenario + err := getScenario(false, db, activeScenarioName, &scenario) + if err != nil { + return err.Error(), http.StatusNotFound + } + + elementFound := false + netChar := event.EventNetworkCharacteristicsUpdate + + // Retrieve element name & type + elementName := netChar.ElementName + elementType := strings.ToUpper(netChar.ElementType) + + // Find the element + if elementType == "SCENARIO" { + scenario.Deployment.InterDomainLatency = netChar.Latency + scenario.Deployment.InterDomainLatencyVariation = netChar.LatencyVariation + scenario.Deployment.InterDomainThroughput = netChar.Throughput + scenario.Deployment.InterDomainPacketLoss = netChar.PacketLoss + elementFound = true + } + + for dIndex, d := range scenario.Deployment.Domains { + if elementFound { + break + } else if elementType == "OPERATOR" && elementName == d.Name { + domain := &scenario.Deployment.Domains[dIndex] + domain.InterZoneLatency = netChar.Latency + domain.InterZoneLatencyVariation = netChar.LatencyVariation + domain.InterZoneThroughput = netChar.Throughput + domain.InterZonePacketLoss = netChar.PacketLoss + elementFound = true + break + } + + // Parse zones + for zIndex, z := range d.Zones { + if elementFound { + break + } else if elementType == "ZONE-INTER-EDGE" && elementName == z.Name { + zone := &scenario.Deployment.Domains[dIndex].Zones[zIndex] + zone.InterEdgeLatency = netChar.Latency + zone.InterEdgeLatencyVariation = netChar.LatencyVariation + zone.InterEdgeThroughput = netChar.Throughput + zone.InterEdgePacketLoss = netChar.PacketLoss + elementFound = true + break + } else if elementType == "ZONE-INTER-FOG" && elementName == z.Name { + zone := &scenario.Deployment.Domains[dIndex].Zones[zIndex] + zone.InterFogLatency = netChar.Latency + zone.InterFogLatencyVariation = netChar.LatencyVariation + zone.InterFogThroughput = netChar.Throughput + zone.InterFogPacketLoss = netChar.PacketLoss + elementFound = true + break + } else if elementType == "ZONE-EDGE-FOG" && elementName == z.Name { + zone := &scenario.Deployment.Domains[dIndex].Zones[zIndex] + zone.EdgeFogLatency = netChar.Latency + zone.EdgeFogLatencyVariation = netChar.LatencyVariation + zone.EdgeFogThroughput = netChar.Throughput + zone.EdgeFogPacketLoss = netChar.PacketLoss + elementFound = true + break + } + + // Parse Network Locations + for nlIndex, nl := range z.NetworkLocations { + if elementType == "POA" && elementName == nl.Name { + netloc := &scenario.Deployment.Domains[dIndex].Zones[zIndex].NetworkLocations[nlIndex] + netloc.TerminalLinkLatency = netChar.Latency + netloc.TerminalLinkLatencyVariation = netChar.LatencyVariation + netloc.TerminalLinkThroughput = netChar.Throughput + netloc.TerminalLinkPacketLoss = netChar.PacketLoss + elementFound = true + break + + } + } + } + } + + if elementFound { + log.Debug("element was found and updates should be applied") + } else { + return "Element not found in the scenario", http.StatusNotFound + } + + // Store updated active scenario in DB + rev, err := setScenario(db, activeScenarioName, scenario) + if err != nil { + return err.Error(), http.StatusNotFound + } + log.Debug("Active scenario updated with rev: ", rev) + + // TODO in Execution Engine: + // - Update any deployed location services + // - Inform monitoring engine? + + return "", -1 +} + +func sendEventUeMobility(event Event) (string, int) { + + // Retrieve active scenario + var scenario Scenario + err := getScenario(false, db, activeScenarioName, &scenario) + if err != nil { + return err.Error(), http.StatusNotFound + } + + // Retrieve UE name and destination PoA name + ueName := event.EventUeMobility.Ue + poaName := event.EventUeMobility.Dest + + var oldNL *NetworkLocation + var newNL *NetworkLocation + var ue *PhysicalLocation + var ueIndex int + + // Find UE & destination PoA + log.Debug("Searching for UE and destination PoA in active scenario") + for i := range scenario.Deployment.Domains { + domain := &scenario.Deployment.Domains[i] + + for j := range domain.Zones { + zone := &domain.Zones[j] + + for k := range zone.NetworkLocations { + nl := &zone.NetworkLocations[k] + + // Destination PoA + if nl.Name == poaName { + newNL = nl + } + + for l := range nl.PhysicalLocations { + pl := &nl.PhysicalLocations[l] + + // UE to move + if pl.Type_ == "UE" && pl.Name == ueName { + oldNL = nl + ue = pl + ueIndex = l + } + } + } + } + } + + // Update UE location if necessary + if ue != nil && oldNL != nil && newNL != nil && oldNL != newNL { + log.Debug("Found UE and destination PoA. Updating UE location.") + + // Add UE to new location + newNL.PhysicalLocations = append(newNL.PhysicalLocations, *ue) + + // Remove UE from old location + oldNL.PhysicalLocations[ueIndex] = oldNL.PhysicalLocations[len(oldNL.PhysicalLocations)-1] + oldNL.PhysicalLocations = oldNL.PhysicalLocations[:len(oldNL.PhysicalLocations)-1] + + // Store updated active scenario in DB + rev, err := setScenario(db, activeScenarioName, scenario) + if err != nil { + return err.Error(), http.StatusNotFound + } + log.Debug("Active scenario updated with rev: ", rev) + + // TODO in Execution Engine: + // - Update any deployed location services + // - Inform monitoring engine? + + } else { + err := "Failed to find UE or destination PoA" + return err, http.StatusNotFound + } + return "", -1 +} + +func sendEventPoasInRange(event Event) (string, int) { + var ue *PhysicalLocation + + // Retrieve active scenario + var scenario Scenario + err := getScenario(false, db, activeScenarioName, &scenario) + if err != nil { + return err.Error(), http.StatusNotFound + } + + // Retrieve UE name + ueName := event.EventPoasInRange.Ue + + // Retrieve list of visible POAs and sort them + poasInRange := event.EventPoasInRange.PoasInRange + sort.Strings(poasInRange) + + // Find UE + log.Debug("Searching for UE in active scenario") + for i := range scenario.Deployment.Domains { + domain := &scenario.Deployment.Domains[i] + + for j := range domain.Zones { + zone := &domain.Zones[j] + + for k := range zone.NetworkLocations { + nl := &zone.NetworkLocations[k] + + for l := range nl.PhysicalLocations { + pl := &nl.PhysicalLocations[l] + + // UE to update + if pl.Type_ == "UE" && pl.Name == ueName { + ue = pl + break + } + } + if ue != nil { + break + } + } + if ue != nil { + break + } + } + if ue != nil { + break + } + } + + // Update POAS in range if necessary + if ue != nil { + log.Debug("UE Found. Checking for update to visible POAs") + + // Compare new list of poas with current UE list and update if necessary + if !Equal(poasInRange, ue.NetworkLocationsInRange) { + log.Debug("Updating POAs in range for UE: " + ue.Name) + ue.NetworkLocationsInRange = poasInRange + + // Store updated active scenario in DB + rev, err := setScenario(db, activeScenarioName, scenario) + if err != nil { + return err.Error(), http.StatusNotFound + } + log.Debug("Active scenario updated with rev: ", rev) + } else { + log.Debug("POA list unchanged. Ignoring.") + } + } else { + err := "Failed to find UE" + return err, http.StatusNotFound + } + return "", -1 +} + +// Equal tells whether a and b contain the same elements. +// A nil argument is equivalent to an empty slice. +func Equal(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} + +func ceSendEvent(w http.ResponseWriter, r *http.Request) { + log.Debug("ceSendEvent") + + // Get event type from request parameters + vars := mux.Vars(r) + eventType := vars["type"] + log.Debug("Event Type: ", eventType) + + // Retrieve event from request body + var event Event + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&event) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Process Event + var httpStatus int + var error string + switch eventType { + case "UE-MOBILITY": + error, httpStatus = sendEventUeMobility(event) + case "NETWORK-CHARACTERISTICS-UPDATE": + error, httpStatus = sendEventNetworkCharacteristics(event) + case "POAS-IN-RANGE": + error, httpStatus = sendEventPoasInRange(event) + default: + error = "Unsupported event type" + httpStatus = http.StatusBadRequest + } + + if error != "" { + log.Error(error) + http.Error(w, error, httpStatus) + return + } + + // Send response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func ceGetMeepSettings(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func ceSetMeepSettings(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func getPodDetails(key string, fields map[string]string, userData interface{}) error { + + podsStatus := userData.(*PodsStatus) + var podStatus PodStatus + if fields["meepApp"] != "" { + podStatus.Name = fields["meepApp"] + } else { + podStatus.Name = fields["name"] + } + + podStatus.Namespace = fields["namespace"] + podStatus.MeepApp = fields["meepApp"] + podStatus.MeepOrigin = fields["meepOrigin"] + podStatus.MeepScenario = fields["meepScenario"] + podStatus.Phase = fields["phase"] + podStatus.PodInitialized = fields["initialised"] + podStatus.PodScheduled = fields["scheduled"] + podStatus.PodReady = fields["ready"] + podStatus.PodUnschedulable = fields["unschedulable"] + podStatus.PodConditionError = fields["condition-error"] + podStatus.NbOkContainers = fields["nbOkContainers"] + podStatus.NbTotalContainers = fields["nbTotalContainers"] + podStatus.NbPodRestart = fields["nbPodRestart"] + podStatus.LogicalState = fields["logicalState"] + podStatus.StartTime = fields["startTime"] + + podsStatus.PodStatus = append(podsStatus.PodStatus, podStatus) + return nil +} + +func getPodStatesOnly(key string, fields map[string]string, userData interface{}) error { + podsStatus := userData.(*PodsStatus) + var podStatus PodStatus + if fields["meepApp"] != "" { + podStatus.Name = fields["meepApp"] + } else { + podStatus.Name = fields["name"] + } + podStatus.LogicalState = fields["logicalState"] + + podsStatus.PodStatus = append(podsStatus.PodStatus, podStatus) + + return nil +} + +func ceGetStates(w http.ResponseWriter, r *http.Request) { + + subKey := "" + var podsStatus PodsStatus + // Retrieve client ID & service name from query parameters + query := r.URL.Query() + longParam := query.Get("long") + typeParam := query.Get("type") + + detailed := false + if longParam == "true" { + detailed = true + } + + if typeParam == "" { + subKey = "MO-scenario:" + } else { + subKey = "MO-" + typeParam + ":" + } + + //values for pod name + keyName := moduleMonEngine + "*" + subKey + "*" + + //get will be unique... but reusing the generic function + var err error + if detailed { + err = RedisDBForEachEntry(keyName, getPodDetails, &podsStatus) + } else { + err = RedisDBForEachEntry(keyName, getPodStatesOnly, &podsStatus) + } + + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if typeParam == "core" { + // ***** virt-engine is not a pod yet, but we need to make sure it is started to have a functional system + var podStatus PodStatus + podStatus.Name = "virt-engine" + //we do not care about the content of the answer, simply that there is one + //lint:ignore SA1012 context.TODO not supported here + _, resp, _ := virtEngine.ScenarioDeploymentApi.GetActiveScenario(nil, "dummy") + + if resp != nil { + if resp.StatusCode == http.StatusOK { + podStatus.LogicalState = "Running" + } else { + podStatus.LogicalState = "InternalError" + } + } else { + podStatus.LogicalState = "NotRunning" + } + podsStatus.PodStatus = append(podsStatus.PodStatus, podStatus) + // ***** virt-engine running or not code END + + //if some are missing... its because its coming up and as such... we cannot return a success yet... adding one entry that will be false + + corePods := getCorePodsList() + + //loop through each of them by name + for _, statusPod := range podsStatus.PodStatus { + for corePod := range corePods { + if strings.Contains(statusPod.Name, corePod) { + corePods[corePod] = true + break + } + } + } + + //loop through the list of pods to see which one might be missing + for corePod := range corePods { + if !corePods[corePod] { + var podStatus PodStatus + podStatus.Name = corePod + podStatus.LogicalState = "NotAvailable" + podsStatus.PodStatus = append(podsStatus.PodStatus, podStatus) + } + } + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + + // Format response + jsonResponse, err := json.Marshal(podsStatus) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Send response + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} diff --git a/go-apps/meep-ctrl-engine/server/deployment.go b/go-apps/meep-ctrl-engine/server/deployment.go new file mode 100644 index 0000000000000000000000000000000000000000..acffdd34514678dd09d014953e36938d3521fd07 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/deployment.go @@ -0,0 +1,28 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Network deployment object +type Deployment struct { + + // Latency in ms between domains + InterDomainLatency int32 `json:"interDomainLatency,omitempty"` + + // Latency variation in ms between domains + InterDomainLatencyVariation int32 `json:"interDomainLatencyVariation,omitempty"` + + // The limit of the traffic supported between domains + InterDomainThroughput int32 `json:"interDomainThroughput,omitempty"` + + // Packet lost (in terms of percentage) between domains + InterDomainPacketLoss float64 `json:"interDomainPacketLoss,omitempty"` + + Domains []Domain `json:"domains,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/domain.go b/go-apps/meep-ctrl-engine/server/domain.go new file mode 100644 index 0000000000000000000000000000000000000000..1ae71955184fb2b40a9fa6633b545056c34a50c2 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/domain.go @@ -0,0 +1,37 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Operator domain object +type Domain struct { + + // Unique domain ID + Id string `json:"id,omitempty"` + + // Domain name + Name string `json:"name,omitempty"` + + // Domain type + Type_ string `json:"type,omitempty"` + + // Latency in ms between zones within domain + InterZoneLatency int32 `json:"interZoneLatency,omitempty"` + + // Latency variation in ms between zones within domain + InterZoneLatencyVariation int32 `json:"interZoneLatencyVariation,omitempty"` + + // The limit of the traffic supported between zones within the domain + InterZoneThroughput int32 `json:"interZoneThroughput,omitempty"` + + // Packet lost (in terms of percentage) between zones within the domain + InterZonePacketLoss float64 `json:"interZonePacketLoss,omitempty"` + + Zones []Zone `json:"zones,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/event.go b/go-apps/meep-ctrl-engine/server/event.go new file mode 100644 index 0000000000000000000000000000000000000000..430df7eeaa4d518f2cbf45b05f396192dc0811c8 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/event.go @@ -0,0 +1,28 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Event object +type Event struct { + + // Event name + Name string `json:"name,omitempty"` + + // Event type + Type_ string `json:"type,omitempty"` + + EventNetworkCharacteristicsUpdate *EventNetworkCharacteristicsUpdate `json:"eventNetworkCharacteristicsUpdate,omitempty"` + + EventUeMobility *EventUeMobility `json:"eventUeMobility,omitempty"` + + EventPoasInRange *EventPoasInRange `json:"eventPoasInRange,omitempty"` + + EventOther *EventOther `json:"eventOther,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/event_list.go b/go-apps/meep-ctrl-engine/server/event_list.go new file mode 100644 index 0000000000000000000000000000000000000000..44dfedc2ef335e0fc20eac213b6327de0bd06aaf --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/event_list.go @@ -0,0 +1,15 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Event list object +type EventList struct { + Events []Event `json:"events,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/event_network_characteristics_update.go b/go-apps/meep-ctrl-engine/server/event_network_characteristics_update.go new file mode 100644 index 0000000000000000000000000000000000000000..49ec79c0708b103a14dc67e4564302f477ce3bab --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/event_network_characteristics_update.go @@ -0,0 +1,32 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Network Characteristics update Event object +type EventNetworkCharacteristicsUpdate struct { + + // Name of the network element to be updated + ElementName string `json:"elementName,omitempty"` + + // Type of the network element to be updated + ElementType string `json:"elementType,omitempty"` + + // Latency in ms + Latency int32 `json:"latency,omitempty"` + + // Latency variation in ms + LatencyVariation int32 `json:"latencyVariation,omitempty"` + + // Throughput limit + Throughput int32 `json:"throughput,omitempty"` + + // Packet loss percentage + PacketLoss float64 `json:"packetLoss,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/event_other.go b/go-apps/meep-ctrl-engine/server/event_other.go new file mode 100644 index 0000000000000000000000000000000000000000..5cd00cb377be46ee909d0428db55c75a51138d7c --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/event_other.go @@ -0,0 +1,17 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Other Event object +type EventOther struct { + + // Other event string + Event string `json:"event,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/event_poas_in_range.go b/go-apps/meep-ctrl-engine/server/event_poas_in_range.go new file mode 100644 index 0000000000000000000000000000000000000000..90ddc30a9bf6521a02bf75b3364e2e7359c74b2c --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/event_poas_in_range.go @@ -0,0 +1,19 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// POAs In Range Event object +type EventPoasInRange struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + PoasInRange []string `json:"poasInRange,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/event_ue_mobility.go b/go-apps/meep-ctrl-engine/server/event_ue_mobility.go new file mode 100644 index 0000000000000000000000000000000000000000..3c3e8d811186e0afc5ec47b60d19011e0f72b9ec --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/event_ue_mobility.go @@ -0,0 +1,20 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// UE Mobility Event object +type EventUeMobility struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + // Destination identifier + Dest string `json:"dest,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/external_config.go b/go-apps/meep-ctrl-engine/server/external_config.go new file mode 100644 index 0000000000000000000000000000000000000000..a2b56e26c409b9db8f79e31b549098c55fcd976e --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/external_config.go @@ -0,0 +1,17 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// External Process configuration. NOTE: Only valid if 'isExternal' is set. +type ExternalConfig struct { + IngressServiceMap []ServiceMap `json:"ingressServiceMap,omitempty"` + + EgressServiceMap []ServiceMap `json:"egressServiceMap,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/logger.go b/go-apps/meep-ctrl-engine/server/logger.go new file mode 100644 index 0000000000000000000000000000000000000000..92a3aa968e4c0116e7c3c13e9d03392c6cfc0f4e --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/logger.go @@ -0,0 +1,32 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/go-apps/meep-ctrl-engine/server/meep_settings_api.go b/go-apps/meep-ctrl-engine/server/meep_settings_api.go new file mode 100644 index 0000000000000000000000000000000000000000..391ae3ca705c1fd34d93ee7e587edbd63696c735 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/meep_settings_api.go @@ -0,0 +1,22 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func GetMeepSettings(w http.ResponseWriter, r *http.Request) { + ceGetMeepSettings(w, r) +} + +func SetMeepSettings(w http.ResponseWriter, r *http.Request) { + ceSetMeepSettings(w, r) +} diff --git a/go-apps/meep-ctrl-engine/server/network_location.go b/go-apps/meep-ctrl-engine/server/network_location.go new file mode 100644 index 0000000000000000000000000000000000000000..afb0e1d5fdf9f1a1230958e94d883f953ed8885f --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/network_location.go @@ -0,0 +1,37 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Logical network location object +type NetworkLocation struct { + + // Unique network location ID + Id string `json:"id,omitempty"` + + // Network location name + Name string `json:"name,omitempty"` + + // Network location type + Type_ string `json:"type,omitempty"` + + // Latency in ms for all terminal links within network location + TerminalLinkLatency int32 `json:"terminalLinkLatency,omitempty"` + + // Latency variation in ms for all terminal links within network location + TerminalLinkLatencyVariation int32 `json:"terminalLinkLatencyVariation,omitempty"` + + // The limit of the traffic supported for all terminal links within the network location + TerminalLinkThroughput int32 `json:"terminalLinkThroughput,omitempty"` + + // Packet lost (in terms of percentage) for all terminal links within the network location + TerminalLinkPacketLoss float64 `json:"terminalLinkPacketLoss,omitempty"` + + PhysicalLocations []PhysicalLocation `json:"physicalLocations,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/physical_location.go b/go-apps/meep-ctrl-engine/server/physical_location.go new file mode 100644 index 0000000000000000000000000000000000000000..acfafd4b5b69ef9e83ce645c59f04b59f82d7d44 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/physical_location.go @@ -0,0 +1,30 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Physical location object +type PhysicalLocation struct { + + // Unique physical location ID + Id string `json:"id,omitempty"` + + // Physical location name + Name string `json:"name,omitempty"` + + // Physical location type + Type_ string `json:"type,omitempty"` + + // true: Physical location is external to MEEP false: Physical location is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + NetworkLocationsInRange []string `json:"networkLocationsInRange,omitempty"` + + Processes []Process `json:"processes,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/pod_states_api.go b/go-apps/meep-ctrl-engine/server/pod_states_api.go new file mode 100644 index 0000000000000000000000000000000000000000..d3be50e7b381d0a2620f38d9c0b47bebb23c79f0 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/pod_states_api.go @@ -0,0 +1,18 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func GetStates(w http.ResponseWriter, r *http.Request) { + ceGetStates(w, r) +} diff --git a/go-apps/meep-ctrl-engine/server/pod_status.go b/go-apps/meep-ctrl-engine/server/pod_status.go new file mode 100644 index 0000000000000000000000000000000000000000..cab6c5b96fbdd14157f2fd870b4d6ab2f9637b15 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/pod_status.go @@ -0,0 +1,64 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +type PodStatus struct { + + // Pod name + Name string `json:"name,omitempty"` + + // Pod namespace + Namespace string `json:"namespace,omitempty"` + + // Pod process name + MeepApp string `json:"meepApp,omitempty"` + + // Pod origin(core, scenario) + MeepOrigin string `json:"meepOrigin,omitempty"` + + // Pod scenario name + MeepScenario string `json:"meepScenario,omitempty"` + + // Pod phase + Phase string `json:"phase,omitempty"` + + // Pod initialized (true/false) + PodInitialized string `json:"podInitialized,omitempty"` + + // Pod ready (true/false) + PodReady string `json:"podReady,omitempty"` + + // Pod scheduled (true/false) + PodScheduled string `json:"podScheduled,omitempty"` + + // Pod unschedulable (true/false) + PodUnschedulable string `json:"podUnschedulable,omitempty"` + + // Pod error message + PodConditionError string `json:"podConditionError,omitempty"` + + // Failed container error message + ContainerStatusesMsg string `json:"containerStatusesMsg,omitempty"` + + // Number of containers that are up + NbOkContainers string `json:"nbOkContainers,omitempty"` + + // Number of total containers in the pod + NbTotalContainers string `json:"nbTotalContainers,omitempty"` + + // Number of container failures leading to pod restarts + NbPodRestart string `json:"nbPodRestart,omitempty"` + + // State that is mapping the kubernetes api state + LogicalState string `json:"logicalState,omitempty"` + + // Pod creation time + StartTime string `json:"startTime,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/pods_status.go b/go-apps/meep-ctrl-engine/server/pods_status.go new file mode 100644 index 0000000000000000000000000000000000000000..7ee4d8ccd3fab11d10e2ecea6d50ef4a643d389b --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/pods_status.go @@ -0,0 +1,15 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// List of all pods status +type PodsStatus struct { + PodStatus []PodStatus `json:"podStatus,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/process.go b/go-apps/meep-ctrl-engine/server/process.go new file mode 100644 index 0000000000000000000000000000000000000000..76307e6e72bcb0cbf16e53764fc1ac0e98734004 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/process.go @@ -0,0 +1,54 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Application or service object +type Process struct { + + // Unique process ID + Id string `json:"id,omitempty"` + + // Process name + Name string `json:"name,omitempty"` + + // Process type + Type_ string `json:"type,omitempty"` + + // true: process is external to MEEP false: process is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + // Docker image to deploy inside MEEP + Image string `json:"image,omitempty"` + + // Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" + Environment string `json:"environment,omitempty"` + + // Arguments to command executable + CommandArguments string `json:"commandArguments,omitempty"` + + // Executable to invoke at container start up + CommandExe string `json:"commandExe,omitempty"` + + ServiceConfig *ServiceConfig `json:"serviceConfig,omitempty"` + + ExternalConfig *ExternalConfig `json:"externalConfig,omitempty"` + + // Process status + Status string `json:"status,omitempty"` + + // Chart location for the deployment of the chart provided by the user + UserChartLocation string `json:"userChartLocation,omitempty"` + + // Chart values.yaml file location for the deployment of the chart provided by the user + UserChartAlternateValues string `json:"userChartAlternateValues,omitempty"` + + // Chart supplemental information related to the group (service) + UserChartGroup string `json:"userChartGroup,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/redisDB.go b/go-apps/meep-ctrl-engine/server/redisDB.go new file mode 100755 index 0000000000000000000000000000000000000000..edb9064e2b6093deafb86fd79a8256e380891aa9 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/redisDB.go @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package server + +import ( + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-ctrl-engine/log" + + "github.com/KromDaniel/rejonson" + "github.com/go-redis/redis" +) + +var dbClient *rejonson.Client +var dbClientStarted = false + +// RedisDBConnect - Establish connection to DB +func RedisDBConnect() error { + if !dbClientStarted { + err := openDB() + if err != nil { + return err + } + } + return nil +} + +func openDB() error { + goRedisClient := redis.NewClient(&redis.Options{ + Addr: "meep-redis-master:6379", + Password: "", // no password set + DB: 0, // use default DB + }) + client := rejonson.ExtendClient(goRedisClient) + + pong, err := client.Ping().Result() + if pong == "" { + log.Info("pong is null") + return err + } + + if err != nil { + log.Info("Redis DB not accessible") + return err + } + dbClientStarted = true + dbClient = client + + log.Info("Redis DB opened and well!") + return nil +} + +// RedisDBFlush - Empty DB +func RedisDBFlush(module string) error { + var cursor uint64 + var err error + log.Debug("DBFlush module: ", module) + + // Find all module keys + // Process in chunks of 50 matching entries to optimize processing speed & memory + keyMatchStr := module + ":*" + for { + var keys []string + keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() + if err != nil { + log.Debug("ERROR: ", err) + break + } + + // Delete all matching entries + if len(keys) > 0 { + _, err = dbClient.Del(keys...).Result() + if err != nil { + log.Debug("Failed to retrieve entry fields") + break + } + } + + // Stop searching if cursor is back at beginning + if cursor == 0 { + break + } + } + + return nil +} + +// RedisDBSetEntry - Update existing entry or create new entry if it does not exist +func RedisDBSetEntry(key string, fields map[string]interface{}) error { + // Update existing entry or create new entry if it does not exist + _, err := dbClient.HMSet(key, fields).Result() + if err != nil { + return err + } + return nil +} + +// RedisDBRemoveEntry - Remove existing entries +func RedisDBRemoveEntry(keys ...string) error { + _, err := dbClient.Del(keys...).Result() + if err != nil { + return err + } + return nil +} + +// RedisDBJsonSetEntry - Update existing entry or create new entry if it does not exist +func RedisDBJsonSetEntry(key string, path string, json string) error { + // Update existing entry or create new entry if it does not exist + _, err := dbClient.JsonSet(key, path, json).Result() + if err != nil { + return err + } + return nil +} + +// RedisDBJsonDelEntry - Remove existing entry +func RedisDBJsonDelEntry(key string, path string) error { + _, err := dbClient.JsonDel(key, path).Result() + if err != nil { + return err + } + return nil +} + +// RedisDBForEachEntry - Search for matching keys and run handler for each entry +func RedisDBForEachEntry(keyMatchStr string, entryHandler func(string, map[string]string, interface{}) error, userData interface{}) error { + var cursor uint64 + var err error + + // Process in chunks of 50 matching entries to optimize processing speed & memory + for { + var keys []string + keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() + if err != nil { + log.Debug("ERROR: ", err) + break + } + + if len(keys) > 0 { + for i := 0; i < len(keys); i++ { + fields, err := dbClient.HGetAll(keys[i]).Result() + if err != nil || fields == nil { + log.Debug("Failed to retrieve entry fields") + break + } + + // Invoke handler to process entry + err = entryHandler(keys[i], fields, userData) + if err != nil { + return err + } + } + } + + // Stop searching if cursor is back at beginning + if cursor == 0 { + break + } + } + return nil +} + +// RedisDBPublish - Publish message to channel +func RedisDBPublish(channel string, message string) error { + log.Info("Publish to channel: ", channel, " Message: ", message) + _, err := dbClient.Publish(channel, message).Result() + return err +} diff --git a/go-apps/meep-ctrl-engine/server/routers.go b/go-apps/meep-ctrl-engine/server/routers.go new file mode 100644 index 0000000000000000000000000000000000000000..617adc5db6dcb95a5442e7b4992da635fe196672 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/routers.go @@ -0,0 +1,165 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler = route.HandlerFunc + // handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + router.PathPrefix("/").Handler(http.StripPrefix("/", http.FileServer(http.Dir("./static/")))) + + // router.PathPrefix("/api").Handler(http.StripPrefix("/", http.FileServer(http.Dir("./static/api/")))) + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "/v1/", + Index, + }, + + Route{ + "GetMeepSettings", + strings.ToUpper("Get"), + "/v1/settings", + GetMeepSettings, + }, + + Route{ + "SetMeepSettings", + strings.ToUpper("Put"), + "/v1/settings", + SetMeepSettings, + }, + + Route{ + "GetStates", + strings.ToUpper("Get"), + "/v1/states", + GetStates, + }, + + Route{ + "CreateScenario", + strings.ToUpper("Post"), + "/v1/scenarios/{name}", + CreateScenario, + }, + + Route{ + "DeleteScenario", + strings.ToUpper("Delete"), + "/v1/scenarios/{name}", + DeleteScenario, + }, + + Route{ + "DeleteScenarioList", + strings.ToUpper("Delete"), + "/v1/scenarios", + DeleteScenarioList, + }, + + Route{ + "GetScenario", + strings.ToUpper("Get"), + "/v1/scenarios/{name}", + GetScenario, + }, + + Route{ + "GetScenarioList", + strings.ToUpper("Get"), + "/v1/scenarios", + GetScenarioList, + }, + + Route{ + "SetScenario", + strings.ToUpper("Put"), + "/v1/scenarios/{name}", + SetScenario, + }, + + Route{ + "ActivateScenario", + strings.ToUpper("Post"), + "/v1/active/{name}", + ActivateScenario, + }, + + Route{ + "GetActiveClientServiceMaps", + strings.ToUpper("Get"), + "/v1/active/serviceMaps", + GetActiveClientServiceMaps, + }, + + Route{ + "GetActiveScenario", + strings.ToUpper("Get"), + "/v1/active", + GetActiveScenario, + }, + + Route{ + "GetEventList", + strings.ToUpper("Get"), + "/v1/events", + GetEventList, + }, + + Route{ + "SendEvent", + strings.ToUpper("Post"), + "/v1/events/{type}", + SendEvent, + }, + + Route{ + "TerminateScenario", + strings.ToUpper("Delete"), + "/v1/active", + TerminateScenario, + }, +} diff --git a/go-apps/meep-ctrl-engine/server/scenario.go b/go-apps/meep-ctrl-engine/server/scenario.go new file mode 100644 index 0000000000000000000000000000000000000000..61c85929605b11c2c73672b6afdc28c853048b6b --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/scenario.go @@ -0,0 +1,21 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Scenario object +type Scenario struct { + + // Unique scenario name + Name string `json:"name,omitempty"` + + Config *ScenarioConfig `json:"config,omitempty"` + + Deployment *Deployment `json:"deployment,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/scenario_config.go b/go-apps/meep-ctrl-engine/server/scenario_config.go new file mode 100644 index 0000000000000000000000000000000000000000..7358761596acc9ef8436428f544a5cb4661ddd99 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/scenario_config.go @@ -0,0 +1,20 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Scenario configuration +type ScenarioConfig struct { + + // Visualization configuration + Visualization string `json:"visualization,omitempty"` + + // Other scenario configuration + Other string `json:"other,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/scenario_configuration_api.go b/go-apps/meep-ctrl-engine/server/scenario_configuration_api.go new file mode 100644 index 0000000000000000000000000000000000000000..db7eb50e155f51c23c43f9d269e8c7bdb57cdfc2 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/scenario_configuration_api.go @@ -0,0 +1,38 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func CreateScenario(w http.ResponseWriter, r *http.Request) { + ceCreateScenario(w, r) +} + +func DeleteScenario(w http.ResponseWriter, r *http.Request) { + ceDeleteScenario(w, r) +} + +func DeleteScenarioList(w http.ResponseWriter, r *http.Request) { + ceDeleteScenarioList(w, r) +} + +func GetScenario(w http.ResponseWriter, r *http.Request) { + ceGetScenario(w, r) +} + +func GetScenarioList(w http.ResponseWriter, r *http.Request) { + ceGetScenarioList(w, r) +} + +func SetScenario(w http.ResponseWriter, r *http.Request) { + ceSetScenario(w, r) +} diff --git a/go-apps/meep-ctrl-engine/server/scenario_execution_api.go b/go-apps/meep-ctrl-engine/server/scenario_execution_api.go new file mode 100644 index 0000000000000000000000000000000000000000..4a049770669c6b306da37fdb88b2f224c93ad474 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/scenario_execution_api.go @@ -0,0 +1,38 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func ActivateScenario(w http.ResponseWriter, r *http.Request) { + ceActivateScenario(w, r) +} + +func GetActiveScenario(w http.ResponseWriter, r *http.Request) { + ceGetActiveScenario(w, r) +} + +func GetActiveClientServiceMaps(w http.ResponseWriter, r *http.Request) { + ceGetActiveClientServiceMaps(w, r) +} + +func GetEventList(w http.ResponseWriter, r *http.Request) { + ceGetEventList(w, r) +} + +func SendEvent(w http.ResponseWriter, r *http.Request) { + ceSendEvent(w, r) +} + +func TerminateScenario(w http.ResponseWriter, r *http.Request) { + ceTerminateScenario(w, r) +} diff --git a/go-apps/meep-ctrl-engine/server/scenario_list.go b/go-apps/meep-ctrl-engine/server/scenario_list.go new file mode 100644 index 0000000000000000000000000000000000000000..aea2c72e0251e8fb12bb38678e4467654b947a87 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/scenario_list.go @@ -0,0 +1,15 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Scenario list object +type ScenarioList struct { + Scenarios []Scenario `json:"scenarios,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/service_config.go b/go-apps/meep-ctrl-engine/server/service_config.go new file mode 100644 index 0000000000000000000000000000000000000000..c32e7be682f2516d7ffef3a70160808207d85380 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/service_config.go @@ -0,0 +1,22 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Service object +type ServiceConfig struct { + + // Unique service name + Name string `json:"name,omitempty"` + + // Multi-Edge service name, if any + MeSvcName string `json:"meSvcName,omitempty"` + + Ports []ServicePort `json:"ports,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/service_map.go b/go-apps/meep-ctrl-engine/server/service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..891633c9159e532febf00e69eb9b6f9ec410e177 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/service_map.go @@ -0,0 +1,29 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Mapping of exposed ports to internal or external services +type ServiceMap struct { + + // Service name + Name string `json:"name,omitempty"` + + // Service IP address for external service only (egress)
  • N/A for internal services + Ip string `json:"ip,omitempty"` + + // Service port number + Port int32 `json:"port,omitempty"` + + // Port used to expose internal service only (ingress)
  • Must be unique port in range (30000 - 32767)
  • N/A for external services + ExternalPort int32 `json:"externalPort,omitempty"` + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/service_port.go b/go-apps/meep-ctrl-engine/server/service_port.go new file mode 100644 index 0000000000000000000000000000000000000000..035ed92ee98b0c5ec8091bf52c2ec43b4b6a3a37 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/service_port.go @@ -0,0 +1,23 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Service port object +type ServicePort struct { + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` + + // Port number that the service is listening on + Port int32 `json:"port,omitempty"` + + // External port number on which to expose the application (30000 - 32767)
  • Only one application allowed per external port
  • Scenario builder must configure to prevent conflicts + ExternalPort int32 `json:"externalPort,omitempty"` +} diff --git a/go-apps/meep-ctrl-engine/server/settings.go b/go-apps/meep-ctrl-engine/server/settings.go new file mode 100644 index 0000000000000000000000000000000000000000..7adc2a8e67c48ef593171561d30730b376cb21b0 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/settings.go @@ -0,0 +1,14 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// MEEP settings +type Settings struct { +} diff --git a/go-apps/meep-ctrl-engine/server/zone.go b/go-apps/meep-ctrl-engine/server/zone.go new file mode 100644 index 0000000000000000000000000000000000000000..8dfdaace96e9891eb13f1bfd45caff7d8422b0b6 --- /dev/null +++ b/go-apps/meep-ctrl-engine/server/zone.go @@ -0,0 +1,61 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Logical zone (MEC network) object +type Zone struct { + + // Unique zone ID + Id string `json:"id,omitempty"` + + // Zone name + Name string `json:"name,omitempty"` + + // Zone type + Type_ string `json:"type,omitempty"` + + // Latency in ms between fog nodes (or PoAs) within zone + InterFogLatency int32 `json:"interFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) within zone + InterFogLatencyVariation int32 `json:"interFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) within the zone + InterFogThroughput int32 `json:"interFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone + InterFogPacketLoss float64 `json:"interFogPacketLoss,omitempty"` + + // Latency in ms between edge nodes within zone + InterEdgeLatency int32 `json:"interEdgeLatency,omitempty"` + + // Latency variation in ms between edge nodes within zone + InterEdgeLatencyVariation int32 `json:"interEdgeLatencyVariation,omitempty"` + + // The limit of the traffic supported between edge nodes within the zone + InterEdgeThroughput int32 `json:"interEdgeThroughput,omitempty"` + + // Packet lost (in terms of percentage) between edge nodes within the zone + InterEdgePacketLoss float64 `json:"interEdgePacketLoss,omitempty"` + + // Latency in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatency int32 `json:"edgeFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatencyVariation int32 `json:"edgeFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogThroughput int32 `json:"edgeFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogPacketLoss float64 `json:"edgeFogPacketLoss,omitempty"` + + NetworkLocations []NetworkLocation `json:"networkLocations,omitempty"` +} diff --git a/go-apps/meep-mg-manager/.swagger-codegen-ignore b/go-apps/meep-mg-manager/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/go-apps/meep-mg-manager/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/go-apps/meep-mg-manager/.swagger-codegen/VERSION b/go-apps/meep-mg-manager/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..a6254504e40175d135cea7feb34ad31fa0d0bca3 --- /dev/null +++ b/go-apps/meep-mg-manager/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.1 \ No newline at end of file diff --git a/go-apps/meep-mg-manager/Dockerfile b/go-apps/meep-mg-manager/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..315e901edb528dd3a349c19b9dc55d7de54fbd19 --- /dev/null +++ b/go-apps/meep-mg-manager/Dockerfile @@ -0,0 +1,10 @@ +# Copyright (c) 2019 +# InterDigital Communications, Inc. +# All rights reserved. +# +# The information provided herein is the proprietary and confidential +# information of InterDigital Communications, Inc. + +FROM debian:9.6-slim +COPY ./meep-mg-manager /meep-mg-manager +ENTRYPOINT /meep-mg-manager diff --git a/bin/meep-ctrl-engine/static/api/meep-mg-manager.yaml b/go-apps/meep-mg-manager/api/swagger.yaml similarity index 98% rename from bin/meep-ctrl-engine/static/api/meep-mg-manager.yaml rename to go-apps/meep-mg-manager/api/swagger.yaml index a747857f9e63d931a03c1e8bee5fbf3c2ad662c7..6bbb1f97c38ae6e30ccae96f968411cd20e5f3de 100644 --- a/bin/meep-ctrl-engine/static/api/meep-mg-manager.yaml +++ b/go-apps/meep-mg-manager/api/swagger.yaml @@ -1,7 +1,9 @@ --- swagger: "2.0" info: - description: "MEEP Mobility Group Manager REST API" + description: "Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved.\ + \ The information provided herein is the proprietary and confidential information\ + \ of InterDigital Communications, Inc.\n" version: "1.0.0" title: "MEEP Mobility Group Manager REST API" basePath: "/v1" diff --git a/bin/meep-ctrl-engine/static/api/meep-mg-app.yaml b/go-apps/meep-mg-manager/client-app-api/swagger.yaml similarity index 100% rename from bin/meep-ctrl-engine/static/api/meep-mg-app.yaml rename to go-apps/meep-mg-manager/client-app-api/swagger.yaml diff --git a/go-apps/meep-mg-manager/go.mod b/go-apps/meep-mg-manager/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..d0059c5b775b0085bdb654a4ad877efe3b284fd0 --- /dev/null +++ b/go-apps/meep-mg-manager/go.mod @@ -0,0 +1,27 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mg-manager + +go 1.12 + +require ( + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model v0.0.0 + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-app-client v0.0.0 + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-manager-model v0.0.0 + github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db // indirect + github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351 + github.com/RyanCarrier/dijkstra v0.0.0-20180928224145-3fe1cac16289 + github.com/RyanCarrier/dijkstra-1 v0.0.0-20170512020943-0e5801a26345 // indirect + github.com/albertorestifo/dijkstra v0.0.0-20160910063646-aba76f725f72 // indirect + github.com/go-redis/redis v6.15.2+incompatible + github.com/gorilla/handlers v1.4.0 + github.com/gorilla/mux v1.7.1 + github.com/mattomatic/dijkstra v0.0.0-20130617153013-6f6d134eb237 // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect + github.com/sirupsen/logrus v1.4.1 +) + +replace ( + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model => ../../go-packages/meep-ctrl-engine-model + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-app-client => ../../go-packages/meep-mg-app-client + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-manager-model => ../../go-packages/meep-mg-manager-model +) diff --git a/go-apps/meep-mg-manager/go.sum b/go-apps/meep-mg-manager/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..bdeae3609796cd5dfaede010f8ed64a4b29d8a3e --- /dev/null +++ b/go-apps/meep-mg-manager/go.sum @@ -0,0 +1,69 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db h1:Zkf5kwhxdW0xV7WM/crqIcOP5LCFGnAmumWSFAewJ74= +github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db/go.mod h1:RU+6d0CNIRSp6yo1mXLIIrnFa/3LHhvcDVLVJyovptM= +github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351 h1:1u1XrfCBnY+GijnyU6O1k4odp5TnqZQTsp5v7+n/E4Y= +github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351/go.mod h1:HxwfbuElTuGf+/uKZfjJrCnv0BmmpkPJDI7gBwj1KkM= +github.com/RyanCarrier/dijkstra v0.0.0-20180928224145-3fe1cac16289 h1:xAvSALVtCcHbLjLQJhZFLC/XXoXgAywXPBw3+PvCP6g= +github.com/RyanCarrier/dijkstra v0.0.0-20180928224145-3fe1cac16289/go.mod h1:DdR6ymcLl8+sN/XOVNjnYO1NDYfgHskGjreZUDuQCTY= +github.com/RyanCarrier/dijkstra-1 v0.0.0-20170512020943-0e5801a26345 h1:fgSpoKViTSqRb4hjDNj10ig5wUvO0CayCzFdLf6fuRM= +github.com/RyanCarrier/dijkstra-1 v0.0.0-20170512020943-0e5801a26345/go.mod h1:OK4EvWJ441LQqGzed5NGB6vKBAE34n3z7iayPcEwr30= +github.com/albertorestifo/dijkstra v0.0.0-20160910063646-aba76f725f72 h1:uGeGZl8PxSq8VZGG4QK5njJTFA4/G/x5CYORvQVXtAE= +github.com/albertorestifo/dijkstra v0.0.0-20160910063646-aba76f725f72/go.mod h1:o+JdB7VetTHjLhU0N57x18B9voDBQe0paApdEAEoEfw= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= +github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= +github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/mattomatic/dijkstra v0.0.0-20130617153013-6f6d134eb237 h1:acuCHBjzG7MFTugvx3buC4m5rLDLaKC9J8C9jtlraRc= +github.com/mattomatic/dijkstra v0.0.0-20130617153013-6f6d134eb237/go.mod h1:UOnLAUmVG5paym8pD3C4B9BQylUDC2vXFJJpT7JrlEA= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 h1:tzVWzOrXxwAwdSCMrf+mbNrZFxwS0+HLP4m2qxtfdhk= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/go-apps/meep-mg-manager/log/meeplog.go b/go-apps/meep-mg-manager/log/meeplog.go new file mode 100644 index 0000000000000000000000000000000000000000..b3a75975e6ee92553f71c831467ae9851914dc9a --- /dev/null +++ b/go-apps/meep-mg-manager/log/meeplog.go @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package logmain + +import ( + log "github.com/sirupsen/logrus" +) + +const meepComponentField = "meep.component" +const meepComponent = "mg-manager" + +// MeepJSONLogInit -- Log init function +func MeepJSONLogInit() { + log.SetFormatter(&log.JSONFormatter{}) + log.SetLevel(log.DebugLevel) +} + +// Info -- Info logs +func Info(args ...interface{}) { + log.WithFields(log.Fields{meepComponentField: meepComponent}).Info(args...) +} + +// Debug -- Debug logs +func Debug(args ...interface{}) { + log.WithFields(log.Fields{meepComponentField: meepComponent}).Debug(args...) +} + +// Warn -- Warn logs +func Warn(args ...interface{}) { + log.WithFields(log.Fields{meepComponentField: meepComponent}).Warn(args...) +} + +// Error -- Error logs +func Error(args ...interface{}) { + log.WithFields(log.Fields{meepComponentField: meepComponent}).Error(args...) +} + +// Panic -- Panic logs +func Panic(args ...interface{}) { + log.WithFields(log.Fields{meepComponentField: meepComponent}).Panic(args...) +} + +// Fatal -- Fatal logs +func Fatal(args ...interface{}) { + log.WithFields(log.Fields{meepComponentField: meepComponent}).Fatal(args...) +} + +// WithFields -- Log with fields +func WithFields(fields log.Fields) *log.Entry { + return log.WithFields(fields) +} diff --git a/go-apps/meep-mg-manager/main.go b/go-apps/meep-mg-manager/main.go new file mode 100644 index 0000000000000000000000000000000000000000..8521b356e0d6b0261b4a0965905ef2e83241758d --- /dev/null +++ b/go-apps/meep-mg-manager/main.go @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "net/http" + "os" + "os/signal" + "syscall" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mg-manager/log" + server "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mg-manager/server" + + "github.com/gorilla/handlers" +) + +func init() { + log.MeepJSONLogInit() +} + +func main() { + log.Info(os.Args) + + log.Info("Starting MG Manager") + + run := true + go func() { + sigchan := make(chan os.Signal, 10) + signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) + <-sigchan + log.Info("Program killed !") + // do last actions and wait for all write operations to end + run = false + }() + + go func() { + // Initialize MG Manager + err := server.Init() + if err != nil { + log.Error("Failed to initialize MG Manager") + run = false + return + } + + // Start MG Manager Event Handler thread + go server.Run() + + // Start MG Manager REST API Server + router := server.NewRouter() + methods := handlers.AllowedMethods([]string{"OPTIONS", "DELETE", "GET", "HEAD", "POST", "PUT"}) + header := handlers.AllowedHeaders([]string{"content-type"}) + log.Fatal(http.ListenAndServe(":80", handlers.CORS(methods, header)(router))) + run = false + }() + + count := 0 + for { + if !run { + log.Info("Ran for", count, "seconds") + break + } + time.Sleep(time.Second) + count++ + } + +} diff --git a/go-apps/meep-mg-manager/main_test.go b/go-apps/meep-mg-manager/main_test.go new file mode 100644 index 0000000000000000000000000000000000000000..1a76fc260bff388d0b62dba3d508831357149de1 --- /dev/null +++ b/go-apps/meep-mg-manager/main_test.go @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "os" + "strings" + "testing" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mg-manager/log" +) + +// Build: +// $ go test -covermode=count -coverpkg=./... -c -o +// Run: +// $ ./ -test.coverprofile=cover.out __DEVEL--code-cov + +// TestMain is a hack that allows us to figure out what the coverage is during +// integration tests. I would not recommend that you use a binary built using +// this hack outside of a test suite. +func TestMain(t *testing.T) { + var ( + args []string + run bool + ) + + log.Info(os.Args) + for _, arg := range os.Args { + switch { + case arg == "__DEVEL--code-cov": + run = true + case strings.HasPrefix(arg, "-test"): + case strings.HasPrefix(arg, "__DEVEL"): + default: + args = append(args, arg) + } + } + os.Args = args + log.Info(os.Args) + + if run { + main() + } +} diff --git a/go-apps/meep-mg-manager/server/README.md b/go-apps/meep-mg-manager/server/README.md new file mode 100644 index 0000000000000000000000000000000000000000..49ea2e5f617419c606a2258f01b5c8f732e8e106 --- /dev/null +++ b/go-apps/meep-mg-manager/server/README.md @@ -0,0 +1,25 @@ +# Go API Server for server + +Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + +## Overview +This server was generated by the [swagger-codegen] +(https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) + +- API version: 1.0.0 +- Build date: 2019-05-15T12:26:23.591-04:00 + + +### Running the server +To run the server, follow these simple steps: + +``` +go run main.go +``` + diff --git a/go-apps/meep-mg-manager/server/db.go b/go-apps/meep-mg-manager/server/db.go new file mode 100755 index 0000000000000000000000000000000000000000..dea4efcc2c4c75470f330fe656fb801e12a2d35e --- /dev/null +++ b/go-apps/meep-mg-manager/server/db.go @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package server + +import ( + "errors" + "net" + "reflect" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mg-manager/log" + + "github.com/KromDaniel/rejonson" + "github.com/go-redis/redis" +) + +var dbClient *rejonson.Client +var dbClientStarted = false + +var pubsub *redis.PubSub + +// DBConnect - Establish connection to DB +func DBConnect() error { + if !dbClientStarted { + err := openDB() + if err != nil { + return err + } + } + return nil +} + +func openDB() error { + + redisClient := redis.NewClient(&redis.Options{ + Addr: "meep-redis-master:6379", + Password: "", // no password set + DB: 0, // use default DB + }) + rejonsonClient := rejonson.ExtendClient(redisClient) + + pong, err := rejonsonClient.Ping().Result() + + if pong == "" { + log.Info("pong is null") + return err + } + + if err != nil { + log.Info("Redis DB not accessible") + return err + } + dbClientStarted = true + dbClient = rejonsonClient + log.Info("Redis DB opened and well!") + return nil +} + +// DBFlush - Empty DB +func DBFlush(module string) error { + var cursor uint64 + var err error + log.Debug("DBFlush module: ", module) + + // Find all module keys + // Process in chunks of 50 matching entries to optimize processing speed & memory + keyMatchStr := module + ":*" + for { + var keys []string + keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() + if err != nil { + log.Debug("ERROR: ", err) + break + } + + // Delete all matching entries + if len(keys) > 0 { + _, err = dbClient.Del(keys...).Result() + if err != nil { + log.Debug("Failed to retrieve entry fields") + break + } + } + + // Stop searching if cursor is back at beginning + if cursor == 0 { + break + } + } + + return nil +} + +// DBForEachEntry - Search for matching keys and run handler for each entry +func DBForEachEntry(keyMatchStr string, entryHandler func(string, map[string]string, interface{}) error, userData interface{}) error { + var cursor uint64 + var err error + + // Process in chunks of 50 matching entries to optimize processing speed & memory + for { + var keys []string + keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() + if err != nil { + log.Debug("ERROR: ", err) + break + } + + if len(keys) > 0 { + for i := 0; i < len(keys); i++ { + fields, err := dbClient.HGetAll(keys[i]).Result() + if err != nil || fields == nil { + log.Debug("Failed to retrieve entry fields") + break + } + + // Invoke handler to process entry + err = entryHandler(keys[i], fields, userData) + if err != nil { + return err + } + } + } + + // Stop searching if cursor is back at beginning + if cursor == 0 { + break + } + } + return nil +} + +// DBSetEntry - Update existing entry or create new entry if it does not exist +func DBSetEntry(key string, fields map[string]interface{}) error { + // Update existing entry or create new entry if it does not exist + _, err := dbClient.HMSet(key, fields).Result() + if err != nil { + return err + } + return nil +} + +// DBRemoveEntry - Remove entry from DB +func DBRemoveEntry(key string) error { + _, err := dbClient.Del(key).Result() + if err != nil { + return err + } + return nil +} + +// DBJsonGetEntry - Retrieve entry from DB +func DBJsonGetEntry(key string, path string) (string, error) { + // Update existing entry or create new entry if it does not exist + json, err := dbClient.JsonGet(key, path).Result() + if err != nil { + return "", err + } + return json, nil +} + +// DBJsonSetEntry - Update existing entry or create new entry if it does not exist +func DBJsonSetEntry(key string, path string, json string) error { + // Update existing entry or create new entry if it does not exist + _, err := dbClient.JsonSet(key, path, json).Result() + if err != nil { + return err + } + return nil +} + +// DBJsonDelEntry - Remove existing entry +func DBJsonDelEntry(key string, path string) error { + _, err := dbClient.JsonDel(key, path).Result() + if err != nil { + return err + } + return nil +} + +// Subscribe - Register as a listener for provided channels +func Subscribe(channels ...string) error { + pubsub = dbClient.Subscribe(channels...) + return nil +} + +// Listen - Wait for subscribed events +func Listen(handler func(string, string)) error { + + // Make sure listener is subscribed to pubsub + if pubsub == nil { + return errors.New("Not subscribed to pubsub") + } + + // Main listening loop + for { + // Wait for subscribed channel events, or timeout + msg, err := pubsub.ReceiveTimeout(time.Second) + if err != nil { + if reflect.TypeOf(err) == reflect.TypeOf(&net.OpError{}) && + reflect.TypeOf(err.(*net.OpError).Err).String() == "*net.timeoutError" { + // Timeout, ignore and wait for next event + continue + } + } + + // Process published event + switch m := msg.(type) { + + // Process Subscription + case *redis.Subscription: + log.Info("Subscription Message: ", m.Kind, " to channel ", m.Channel, ". Total subscriptions: ", m.Count) + + // Process received Message + case *redis.Message: + log.Info("MSG on ", m.Channel, ": ", m.Payload) + handler(m.Channel, m.Payload) + } + } +} + +// Publish - Publish message to channel +func Publish(channel string, message string) error { + log.Info("Publish to channel: ", channel, " Message: ", message) + _, err := dbClient.Publish(channel, message).Result() + return err +} diff --git a/go-apps/meep-mg-manager/server/logger.go b/go-apps/meep-mg-manager/server/logger.go new file mode 100644 index 0000000000000000000000000000000000000000..d7353fd90a441a6894eb93eec0a06ee428c69775 --- /dev/null +++ b/go-apps/meep-mg-manager/server/logger.go @@ -0,0 +1,32 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/go-apps/meep-mg-manager/server/membership_api.go b/go-apps/meep-mg-manager/server/membership_api.go new file mode 100644 index 0000000000000000000000000000000000000000..43a0df7a7468b5900e97c4cdada6483ca071e4d6 --- /dev/null +++ b/go-apps/meep-mg-manager/server/membership_api.go @@ -0,0 +1,58 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func CreateMobilityGroup(w http.ResponseWriter, r *http.Request) { + mgCreateMobilityGroup(w, r) +} + +func CreateMobilityGroupApp(w http.ResponseWriter, r *http.Request) { + mgCreateMobilityGroupApp(w, r) +} + +func CreateMobilityGroupUe(w http.ResponseWriter, r *http.Request) { + mgCreateMobilityGroupUe(w, r) +} + +func DeleteMobilityGroup(w http.ResponseWriter, r *http.Request) { + mgDeleteMobilityGroup(w, r) +} + +func DeleteMobilityGroupApp(w http.ResponseWriter, r *http.Request) { + mgDeleteMobilityGroupApp(w, r) +} + +func GetMobilityGroup(w http.ResponseWriter, r *http.Request) { + mgGetMobilityGroup(w, r) +} + +func GetMobilityGroupApp(w http.ResponseWriter, r *http.Request) { + mgGetMobilityGroupApp(w, r) +} + +func GetMobilityGroupAppList(w http.ResponseWriter, r *http.Request) { + mgGetMobilityGroupAppList(w, r) +} + +func GetMobilityGroupList(w http.ResponseWriter, r *http.Request) { + mgGetMobilityGroupList(w, r) +} + +func SetMobilityGroup(w http.ResponseWriter, r *http.Request) { + mgSetMobilityGroup(w, r) +} + +func SetMobilityGroupApp(w http.ResponseWriter, r *http.Request) { + mgSetMobilityGroupApp(w, r) +} diff --git a/go-apps/meep-mg-manager/server/mg-manager.go b/go-apps/meep-mg-manager/server/mg-manager.go new file mode 100644 index 0000000000000000000000000000000000000000..c5f290e0e829d9cc35bae01d33d27a9b09e50d77 --- /dev/null +++ b/go-apps/meep-mg-manager/server/mg-manager.go @@ -0,0 +1,1283 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package server + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "strings" + "sync" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mg-manager/log" + ceModel "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model" + mga "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-app-client" + mgModel "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-manager-model" + + "github.com/RyanCarrier/dijkstra" + "github.com/gorilla/mux" +) + +const moduleCtrlEngine string = "ctrl-engine" +const moduleMgManager string = "mg-manager" + +const typeActive string = "active" +const typeLb string = "lb" + +const channelCtrlActive string = moduleCtrlEngine + "-" + typeActive +const channelMgManagerLb string = moduleMgManager + "-" + typeLb + +const eventTypeStateUpdate = "STATE-UPDATE" +const eventTypeStateTransferStart = "STATE-TRANSFER-START" +const eventTypeStateTransferComplete = "STATE-TRANSFER-COMPLETE" +const eventTypeStateTransferCancel = "STATE-TRANSFER-CANCEL" + +// const stateTransModeStateDirect = "STATE-DIRECT" +const stateTransModeStateManaged = "STATE-MANAGED" + +// const stateTransModeInstanceDirect = "INSTANCE-DIRECT" +// const stateTransModeInstanceManaged = "INSTANCE-MANAGED" +// const stateTransModeNone = "NONE" + +const stateTransTrigNetLocInRange = "NET-LOC-IN-RANGE" +const stateTransTrigNetLocChange = "NET-LOC-CHANGE" + +// const stateTransTrigGPSProximity = "GPS-PROXIMITY" +// const stateTransTrigNone = "NONE" + +// const sessionTransModeGraceful = "GRACEFUL" +const sessionTransModeForced = "FORCED" + +const lbAlgoHopCount = "HOP-COUNT" + +// const lbAlgoLatency = "LATENCY" +// const lbAlgoDistance = "DISTANCE" +// const lbAlgoNone = "NONE" + +type mgInfo struct { + mg mgModel.MobilityGroup + appInfoMap map[string]*appInfo + ueInfoMap map[string]*ueInfo + netLocAppMap map[string]string + defaultNetLocAppMap map[string]string +} + +type appInfo struct { + app mgModel.MobilityGroupApp + appClient *mga.APIClient +} + +type ueInfo struct { + ue mgModel.MobilityGroupUe + appsInRange map[string]bool + state string +} + +type netElemInfo struct { + name string + phyLoc string + netLoc string + netLocsInRange map[string]bool + mgSvcMap map[string]*svcMapInfo + transferInProgress bool +} + +type svcMapInfo struct { + mgSvcName string + lbSvcName string +} + +type serviceInfo struct { + name string + node string + mgSvc *mgServiceInfo +} + +type mgServiceInfo struct { + name string + services map[string]*serviceInfo +} + +// Mutex +var mutex sync.Mutex + +// Scenario network graph +var networkGraph *dijkstra.Graph + +// Scenario network location list +var netLocList = []string{} + +// Scenario service mappings +var svcInfoMap = map[string]*serviceInfo{} +var mgSvcInfoMap = map[string]*mgServiceInfo{} + +// mapping from element name to svc name for usercharts +var svcToElemMap = map[string]string{} +var elemToSvcMap = map[string]string{} + +// Network Element Info mapping +var netElemInfoMap = map[string]*netElemInfo{} + +// Mobility Group Data Map +var mgInfoMap = map[string]*mgInfo{} + +// Init - Mobility Group Manager Init +func Init() (err error) { + + // Connect to Redis DB + err = DBConnect() + if err != nil { + log.Error("Failed connection to Active DB. Error: ", err) + return err + } + log.Info("Connected to Active DB") + + // Subscribe to Pub-Sub events for MEEP Controller + // NOTE: Current implementation is RedisDB Pub-Sub + err = Subscribe(channelCtrlActive) + if err != nil { + log.Error("Failed to subscribe to Pub/Sub events. Error: ", err) + return + } + log.Info("Subscribed to Pub/Sub events") + + // Flush module data + DBFlush(moduleMgManager) + + // Initialize Edge-LB rules with current active scenario + processActiveScenarioUpdate() + + return nil +} + +// Run - MEEP MG Manager execution +func Run() { + + // Listen for subscribed events. Provide event handler method. + _ = Listen(eventHandler) +} + +func eventHandler(channel string, payload string) { + // Handle Message according to Rx Channel + switch channel { + + // MEEP Ctrl Engine active scenario update Channel + case channelCtrlActive: + log.Debug("Event received on channel: ", channelCtrlActive) + processActiveScenarioUpdate() + + default: + log.Warn("Unsupported channel") + } +} + +func processActiveScenarioUpdate() { + // Retrieve active scenario from DB + jsonScenario, err := DBJsonGetEntry(moduleCtrlEngine+":"+typeActive, ".") + if err != nil { + log.Error(err.Error()) + clearScenario() + return + } + + // Unmarshal Active scenario + var scenario ceModel.Scenario + err = json.Unmarshal([]byte(jsonScenario), &scenario) + if err != nil { + log.Error(err.Error()) + clearScenario() + return + } + + // Parse scenario + parseScenario(scenario) + + // Set Default Edge-LB mapping + setDefaultNetLocAppMaps() + + // Re-evaluate MG Service mapping + refreshMgSvcMapping() + + // Store & Apply latest MG Service mappings + applyMgSvcMapping() +} + +func clearScenario() { + log.Debug("clearScenario() -- Resetting all variables") + + networkGraph = nil + netLocList = []string{} + svcInfoMap = map[string]*serviceInfo{} + mgSvcInfoMap = map[string]*mgServiceInfo{} + svcToElemMap = map[string]string{} + elemToSvcMap = map[string]string{} + netElemInfoMap = map[string]*netElemInfo{} + mgInfoMap = map[string]*mgInfo{} + + // Flush module data and send update + DBFlush(moduleMgManager) + _ = Publish(channelMgManagerLb, "") +} + +func parseScenario(scenario ceModel.Scenario) { + log.Debug("parseScenario") + + // Create new network graph + networkGraph = dijkstra.NewGraph() + + // Parse Domains + for _, domain := range scenario.Deployment.Domains { + addNode(networkGraph, domain.Name, "") + + // Parse Zones + for _, zone := range domain.Zones { + addNode(networkGraph, zone.Name, domain.Name) + + // Parse Network Locations + for _, nl := range zone.NetworkLocations { + addNode(networkGraph, nl.Name, zone.Name) + netLocList = append(netLocList, nl.Name) + + // Parse Physical locations + for _, pl := range nl.PhysicalLocations { + addNode(networkGraph, pl.Name, nl.Name) + + // Parse Processes + for _, proc := range pl.Processes { + addNode(networkGraph, proc.Name, pl.Name) + + // Get network element from list or create new one if it does not exist + netElem := getNetElem(proc.Name) + + // Set current physical & network location and network locations in range + netElem.phyLoc = pl.Name + netElem.netLoc = nl.Name + netElem.netLocsInRange = map[string]bool{} + for _, netLoc := range pl.NetworkLocationsInRange { + netElem.netLocsInRange[netLoc] = true + } + + // Store service information from service config + if proc.ServiceConfig != nil { + addServiceInfo(proc.ServiceConfig.Name, proc.ServiceConfig.MeSvcName, proc.Name) + } + + // Store service information from user chart + // Format: :[group service name]:: + if proc.UserChartLocation != "" && proc.UserChartGroup != "" { + userChartGroup := strings.Split(proc.UserChartGroup, ":") + addServiceInfo(userChartGroup[0], userChartGroup[1], proc.Name) + } + } + } + } + } + } +} + +func addNode(graph *dijkstra.Graph, node string, parent string) { + graph.AddMappedVertex(node) + if parent != "" { + _ = graph.AddMappedArc(parent, node, 1) + _ = graph.AddMappedArc(node, parent, 1) + } +} + +// Create & store new service & MG service information +func addServiceInfo(svcName string, mgSvcName string, nodeName string) { + svcInfo := new(serviceInfo) + svcInfo.name = svcName + svcInfo.node = nodeName + + // Store MG Service info + if mgSvcName != "" { + // Add MG service to MG service info map if it does not exist yet + mgSvcInfo, found := mgSvcInfoMap[mgSvcName] + if !found { + mgSvcInfo = new(mgServiceInfo) + mgSvcInfo.services = make(map[string]*serviceInfo) + mgSvcInfo.name = mgSvcName + mgSvcInfoMap[mgSvcInfo.name] = mgSvcInfo + } + + // Add service instance reference to MG service list + mgSvcInfo.services[svcInfo.name] = svcInfo + + // Add MG Service reference to service instance + svcInfo.mgSvc = mgSvcInfo + + // Create Mobility Group + // NOTE: Hardcoded defaults here can be overridden via REST API + var mg mgModel.MobilityGroup + mg.Name = mgSvcName + mg.StateTransferMode = stateTransModeStateManaged + mg.StateTransferTrigger = stateTransTrigNetLocInRange + mg.SessionTransferMode = sessionTransModeForced + mg.LoadBalancingAlgorithm = lbAlgoHopCount + _ = mgCreate(&mg) + } + + // Add service instance to service info map + svcInfoMap[svcInfo.name] = svcInfo + svcToElemMap[svcInfo.name] = svcInfo.name + elemToSvcMap[svcInfo.name] = svcInfo.name +} + +func getNetElem(name string) *netElemInfo { + // Get existing entry, if any + netElem := netElemInfoMap[name] + if netElem == nil { + // Create new net elem + netElem = new(netElemInfo) + netElem.name = name + netElem.netLocsInRange = map[string]bool{} + netElem.mgSvcMap = map[string]*svcMapInfo{} + netElem.transferInProgress = false + netElemInfoMap[name] = netElem + } + return netElem +} + +func setDefaultNetLocAppMaps() { + log.Debug("setDefaultNetLocAppMaps") + + // For each MG Service & net location in scenario, use Group App instances from scenario and + // default LB algorithm to determine which App instance is best for net location + for _, mgInfo := range mgInfoMap { + // Only set on first pass + if len(mgInfo.defaultNetLocAppMap) == 0 { + for _, netLoc := range netLocList { + mgInfo.defaultNetLocAppMap[netLoc] = runLbAlgoHopCount(mgSvcInfoMap[mgInfo.mg.Name].services, netLoc) + } + } + } +} + +func refreshNetLocAppMap(mgInfo *mgInfo) { + log.Debug("refreshNetLocAppMap") + + // Reset Net Loc App map + mgInfo.netLocAppMap = make(map[string]string) + + // Retrieve list of registered app services + var mgApps = map[string]*serviceInfo{} + for _, appInfo := range mgInfo.appInfoMap { + mgApps[appInfo.app.Id] = svcInfoMap[appInfo.app.Id] + if mgApps[appInfo.app.Id] == nil { + + mgApps[appInfo.app.Id] = svcInfoMap[svcToElemMap[appInfo.app.Id]] + } + } + + // For each net location in scenario, use Group LB algorithm to determine which + // registered Group App is best for net location + for _, netLoc := range netLocList { + if mgInfo.mg.LoadBalancingAlgorithm == lbAlgoHopCount { + mgInfo.netLocAppMap[netLoc] = runLbAlgoHopCount(mgApps, netLoc) + } else { + log.Error("LB algorithm not yet supported: ", mgInfo.mg.LoadBalancingAlgorithm) + break + } + } +} + +func refreshMgSvcMapping() { + log.Debug("refreshMgSvcMapping") + + // For each network element, populate MG Service mapping + for _, netElemInfo := range netElemInfoMap { + + // For each MG Service, determine which instance to use + for _, mgSvcInfo := range mgSvcInfoMap { + + // Ignore if no mobility group exists + mgInfo := mgInfoMap[mgSvcInfo.name] + if mgInfo == nil { + log.Error("No MG for MG Service: ", mgSvcInfo.name) + continue + } + + // PATCH: If no registered app instances, use default net loc app map + if len(mgInfo.appInfoMap) == 0 { + setSvcMap(netElemInfo, mgInfo.mg.Name, mgInfo.defaultNetLocAppMap[netElemInfo.netLoc]) + continue + } + + // If Net Elem is not tracked, apply update immediately + ueInfo := mgInfo.ueInfoMap[netElemInfo.phyLoc] + if ueInfo == nil { + setSvcMap(netElemInfo, mgInfo.mg.Name, mgInfo.netLocAppMap[netElemInfo.netLoc]) + continue + } + // If UE is tracked, use MG settings to determine if a notification must be sent + if mgInfo.mg.StateTransferTrigger == stateTransTrigNetLocChange { + // Trigger start/stop on location change only + var currentApp = netElemInfo.mgSvcMap[mgInfo.mg.Name].lbSvcName + var bestApp = mgInfo.netLocAppMap[netElemInfo.netLoc] + + // If new location requires a new Group App instance, send Transfer Complete + // notification and update mapping + if bestApp != currentApp { + log.Info("Best App: " + bestApp + " != Current App: " + currentApp) + completeStateTransfer(mgInfo, netElemInfo, ueInfo, elemToSvcMap[currentApp]) + setSvcMap(netElemInfo, mgInfo.mg.Name, bestApp) + } + + } else if mgInfo.mg.StateTransferTrigger == stateTransTrigNetLocInRange { + // Trigger start/complete/cancel based on network location & locations in range + var currentApp = netElemInfo.mgSvcMap[mgInfo.mg.Name].lbSvcName + var bestApp = mgInfo.netLocAppMap[netElemInfo.netLoc] + + // Find all Group Apps in range based on Net Locations in range + mutex.Lock() + ueInfo.appsInRange = map[string]bool{} + ueInfo.appsInRange[bestApp] = true + for netLoc := range netElemInfo.netLocsInRange { + if netLoc != netElemInfo.netLoc { + ueInfo.appsInRange[mgInfo.netLocAppMap[netLoc]] = true + } + } + mutex.Unlock() + + // If new location requires a new Group App instance, send Transfer Complete + // notification and update mapping + if bestApp != currentApp { + log.Info("Best App: " + bestApp + " != Current App: " + currentApp) + completeStateTransfer(mgInfo, netElemInfo, ueInfo, elemToSvcMap[currentApp]) + setSvcMap(netElemInfo, mgInfo.mg.Name, bestApp) + } + + // Start or cancel State Transfer based on the following conditions: + // - How many apps are in range + // - Whether a transfer was already in progress + if len(ueInfo.appsInRange) > 1 && !netElemInfo.transferInProgress { + startStateTransfer(mgInfo, netElemInfo, ueInfo, bestApp) + } else if len(ueInfo.appsInRange) == 1 && netElemInfo.transferInProgress { + cancelStateTransfer(mgInfo, netElemInfo, ueInfo, bestApp) + } + + } else { + log.Error("LB algorithm not yet supported: ", mgInfo.mg.LoadBalancingAlgorithm) + continue + } + } + } +} + +func setSvcMap(netElemInfo *netElemInfo, mgSvcName string, lbSvcName string) { + + // Get existing entry, if any + svcMap := netElemInfo.mgSvcMap[mgSvcName] + if svcMap == nil { + // Create new MG Service Map + svcMap = new(svcMapInfo) + netElemInfo.mgSvcMap[mgSvcName] = svcMap + } + + // Set MG & LB Service Names + svcMap.mgSvcName = mgSvcName + svcMap.lbSvcName = lbSvcName +} + +// LB Algorithm: +// - Compare hop count from current pod to each instance +// - Choose closest instance +func runLbAlgoHopCount(services map[string]*serviceInfo, elem string) string { + var minDist int64 = -1 + var lbSvc = "" + + for _, svc := range services { + // Calculate shortest distance + src, _ := networkGraph.GetMapping(elem) + dst, _ := networkGraph.GetMapping(svc.node) + path, _ := networkGraph.Shortest(src, dst) + + // Store as LB service if closest service instance + if lbSvc == "" || path.Distance < minDist { + minDist = path.Distance + lbSvc = svc.name + } + } + return lbSvc +} + +func startStateTransfer(group *mgInfo, elem *netElemInfo, ue *ueInfo, app string) { + log.Info("Sending " + eventTypeStateTransferStart + " Notification for " + ue.ue.Id + " to " + app) + + go func() { + var event mga.MobilityGroupEvent + event.Name = eventTypeStateTransferStart + event.Type_ = eventTypeStateTransferStart + event.UeId = ue.ue.Id + //lint:ignore SA1012 context.TODO not supported here + _, err := group.appInfoMap[app].appClient.StateTransferApi.HandleEvent(nil, event) + if err != nil { + log.Error(err.Error()) + } + }() + + // Set flag indicating transfer has been started + elem.transferInProgress = true +} + +func completeStateTransfer(group *mgInfo, elem *netElemInfo, ue *ueInfo, app string) { + log.Info("Sending " + eventTypeStateTransferComplete + " Notification for " + ue.ue.Id + " to " + app) + + go func() { + var event mga.MobilityGroupEvent + event.Name = eventTypeStateTransferComplete + event.Type_ = eventTypeStateTransferComplete + event.UeId = ue.ue.Id + //lint:ignore SA1012 context.TODO not supported here + _, err := group.appInfoMap[app].appClient.StateTransferApi.HandleEvent(nil, event) + if err != nil { + log.Error(err.Error()) + } + }() + + // Set flag indicating transfer has been started + elem.transferInProgress = false +} + +func cancelStateTransfer(group *mgInfo, elem *netElemInfo, ue *ueInfo, app string) { + log.Info("Sending " + eventTypeStateTransferCancel + " Notification for " + ue.ue.Id + " to " + app) + + go func() { + var event mga.MobilityGroupEvent + event.Name = eventTypeStateTransferCancel + event.Type_ = eventTypeStateTransferCancel + event.UeId = ue.ue.Id + //lint:ignore SA1012 context.TODO not supported here + _, err := group.appInfoMap[app].appClient.StateTransferApi.HandleEvent(nil, event) + if err != nil { + log.Error(err.Error()) + } + }() + + // Set flag indicating transfer has been cancelled + elem.transferInProgress = false +} + +func applyMgSvcMapping() { + log.Debug("applyMgSvcMapping") + + // Create network element list from network element map + var netElemList mgModel.NetworkElementList + netElemList.NetworkElements = make([]mgModel.NetworkElement, 0, len(netElemInfoMap)) + + for _, netElemInfo := range netElemInfoMap { + var netElem mgModel.NetworkElement + netElem.Name = netElemInfo.name + netElem.ServiceMaps = make([]mgModel.MobilityGroupServiceMap, 0, len(netElemInfo.mgSvcMap)) + + for _, svcMap := range netElemInfo.mgSvcMap { + var mgSvcMap mgModel.MobilityGroupServiceMap + mgSvcMap.MgSvcName = svcMap.mgSvcName + mgSvcMap.LbSvcName = svcMap.lbSvcName + + // Add service maps to list + netElem.ServiceMaps = append(netElem.ServiceMaps, mgSvcMap) + } + + // Add network elements to list + netElemList.NetworkElements = append(netElemList.NetworkElements, netElem) + } + + // Marshal Net Elem list for storing + jsonNetElemList, err := json.Marshal(netElemList) + if err != nil { + log.Error(err.Error()) + return + } + err = DBJsonSetEntry(moduleMgManager+":"+typeLb, ".", string(jsonNetElemList)) + if err != nil { + log.Error(err.Error()) + return + } + + // Publish Edge LB rules update + _ = Publish(channelMgManagerLb, "") +} + +func mgCreate(mg *mgModel.MobilityGroup) error { + // Make sure group does not already exist + if mgInfoMap[mg.Name] != nil { + log.Warn("Mobility group already exists: ", mg.Name) + err := errors.New("Mobility group already exists") + return err + } + + // Create new Mobility Group & copy data + mgInfo := new(mgInfo) + mgInfo.mg = *mg + mgInfo.appInfoMap = make(map[string]*appInfo) + mgInfo.ueInfoMap = make(map[string]*ueInfo) + mgInfo.netLocAppMap = make(map[string]string) + mgInfo.defaultNetLocAppMap = make(map[string]string) + + // Add to MG map + mgInfoMap[mg.Name] = mgInfo + + log.Info("Created MG: ", mg.Name) + return nil +} + +func mgUpdate(mg *mgModel.MobilityGroup) error { + // Make sure group exists + mgInfo := mgInfoMap[mg.Name] + if mgInfo == nil { + log.Error("Mobility group does not exist: ", mg.Name) + err := errors.New("Mobility group does not exist") + return err + } + + // Update Mobility Group + mgInfo.mg = *mg + + log.Info("Updated MG: ", mg.Name) + return nil +} + +func mgDelete(mgName string) error { + // Make sure group exists + if mgInfoMap[mgName] == nil { + log.Error("Mobility group does not exist: ", mgName) + err := errors.New("Mobility group does not exist") + return err + } + + // Remove entry from map + delete(mgInfoMap, mgName) + + log.Info("Deleted MG: ", mgName) + return nil +} + +func mgAppCreate(mgName string, mgApp *mgModel.MobilityGroupApp) error { + // Make sure group exists + mgInfo := mgInfoMap[mgName] + if mgInfo == nil { + log.Error("Mobility group does not exist: ", mgName) + err := errors.New("Mobility group does not exist") + return err + } + // Make sure App does not already exist + if mgInfo.appInfoMap[mgApp.Id] != nil { + log.Error("Mobility group App already exists: ", mgApp.Id) + err := errors.New("Mobility group App already exists") + return err + } + + // Create new Mobility Group & copy data + mgAppInfo := new(appInfo) + mgAppInfo.app = *mgApp + + // Create & store client for MG App REST API + mgAppClientCfg := mga.NewConfiguration() + mgAppClientCfg.BasePath = mgApp.Url + mgAppInfo.appClient = mga.NewAPIClient(mgAppClientCfg) + if mgAppInfo.appClient == nil { + log.Error("Failed to create MG App REST API client: ", mgAppClientCfg.BasePath) + err := errors.New("Failed to create MG App REST API client") + return err + } + + // Add to MG App map & App client map + mgInfo.appInfoMap[mgApp.Id] = mgAppInfo + log.Info("Created new MG App: " + mgApp.Id + " in group: " + mgName) + refreshNetLocAppMap(mgInfo) + + // Re-evaluate MG Service mapping + refreshMgSvcMapping() + + // Store & Apply latest MG Service mappings + applyMgSvcMapping() + + return nil +} + +func mgAppUpdate(mgName string, mgApp *mgModel.MobilityGroupApp) error { + // Make sure group exists + mgInfo := mgInfoMap[mgName] + if mgInfo == nil { + log.Error("Mobility group does not exist: ", mgName) + err := errors.New("Mobility group does not exist") + return err + } + // Make sure App exists + mgAppInfo := mgInfo.appInfoMap[mgApp.Id] + if mgAppInfo == nil { + log.Error("Mobility group App does not exist: ", mgApp.Id) + err := errors.New("Mobility group App does not exist") + return err + } + + // Update Mobility Group App + mgAppInfo.app = *mgApp + + // Update & store client for MG App REST API + mgAppClientCfg := mga.NewConfiguration() + mgAppClientCfg.BasePath = mgApp.Url + mgAppInfo.appClient = mga.NewAPIClient(mgAppClientCfg) + if mgAppInfo.appClient == nil { + log.Error("Failed to create MG App REST API client: ", mgAppClientCfg.BasePath) + err := errors.New("Failed to create MG App REST API client") + return err + } + + log.Info("Updated MG App: " + mgApp.Id + " in group: " + mgName) + return nil +} + +func mgAppDelete(mgName string, appID string) error { + // Make sure group exists + mgInfo := mgInfoMap[mgName] + if mgInfo == nil { + log.Error("Mobility group does not exist: ", mgName) + err := errors.New("Mobility group does not exist") + return err + } + // Make sure App exists + if mgInfo.appInfoMap[appID] == nil { + log.Error("Mobility group App does not exist: ", appID) + err := errors.New("Mobility group App does not exist") + return err + } + + // Remove entry from App map & App Client map + delete(mgInfo.appInfoMap, appID) + log.Info("Deleted MG App: " + appID + " in group: " + mgName) + refreshNetLocAppMap(mgInfo) + + return nil +} + +func mgUeCreate(mgName string, appID string, mgUe *mgModel.MobilityGroupUe) error { + // Make sure group exists + mgInfo := mgInfoMap[mgName] + if mgInfo == nil { + log.Error("Mobility group does not exist: ", mgName) + err := errors.New("Mobility group does not exist") + return err + } + // Make sure App exists + if mgInfo.appInfoMap[appID] == nil { + log.Error("Mobility group App does not exist: ", appID) + err := errors.New("Mobility group App does not exist") + return err + } + + // Retrieve UE info or create new UE info it not present + UEInfo := mgInfo.ueInfoMap[mgUe.Id] + if UEInfo == nil { + log.Debug("Creating new UE Info: ", mgUe.Id) + UEInfo = new(ueInfo) + UEInfo.ue.Id = mgUe.Id + UEInfo.appsInRange = make(map[string]bool) + mgInfo.ueInfoMap[mgUe.Id] = UEInfo + + // Re-evaluate MG Service mapping + refreshMgSvcMapping() + + // Store & Apply latest MG Service mappings + applyMgSvcMapping() + } + return nil +} + +func processAppState(mgName string, appID string, mgAppState *mgModel.MobilityGroupAppState) error { + log.Info("Processing app state for UE: " + mgAppState.UeId + " from appID: " + appID + " in group: " + mgName) + + // Retrieve MG info + mgInfo := mgInfoMap[mgName] + if mgInfo == nil { + log.Error("Mobility group does not exist: ", mgName) + err := errors.New("Mobility group does not exist") + return err + } + // Retrieve App info + appInfo := mgInfo.appInfoMap[appID] + + if appInfo == nil { + log.Error("Mobility group App does not exist: ", appID) + err := errors.New("Mobility group App does not exist") + return err + } + // Retrieve UE Info + ueInfo := mgInfo.ueInfoMap[mgAppState.UeId] + if ueInfo == nil { + log.Error("Mobility group UE does not exist: ", mgAppState.UeId) + err := errors.New("Mobility group UE does not exist") + return err + } + + // Store UE-specific state + ueInfo.state = mgAppState.UeState + + // Send state to apps in range + appState := new(mga.MobilityGroupAppState) + appState.UeId = ueInfo.ue.Id + appState.UeState = ueInfo.state + + mutex.Lock() + for appName := range ueInfo.appsInRange { + appName = elemToSvcMap[appName] + + if appName != appID { + appInfo := mgInfo.appInfoMap[appName] + if appInfo == nil { + continue + } + // Start threads to process State update event for each app in range + log.Info("Sending " + eventTypeStateUpdate + " Notification for " + ueInfo.ue.Id + " to " + appName) + go func() { + var event mga.MobilityGroupEvent + event.Name = eventTypeStateUpdate + event.Type_ = eventTypeStateUpdate + event.UeId = ueInfo.ue.Id + event.AppState = appState + //lint:ignore SA1012 context.TODO not supported here + _, err := appInfo.appClient.StateTransferApi.HandleEvent(nil, event) + if err != nil { + log.Error(err.Error()) + } + }() + } + } + mutex.Unlock() + + return nil +} + +// GET Mobility Group List +func mgGetMobilityGroupList(w http.ResponseWriter, r *http.Request) { + log.Debug("mgGetMobilityGroupList") + + // Make list from MG map + mgList := make([]mgModel.MobilityGroup, 0, len(mgInfoMap)) + for _, value := range mgInfoMap { + mgList = append(mgList, value.mg) + } + + // Format response + jsonResponse, err := json.Marshal(mgList) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Send response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} + +// GET Mobility Group +func mgGetMobilityGroup(w http.ResponseWriter, r *http.Request) { + log.Debug("mgGetMobilityGroup") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + + // Retrieve MG from map + mgInfo := mgInfoMap[mgName] + if mgInfo == nil { + log.Error("Failed to find MG") + http.Error(w, "Failed to find MG", http.StatusNotFound) + return + } + + // Format response + jsonResponse, err := json.Marshal(mgInfo.mg) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // Send response + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} + +// POST Mobility Group +func mgCreateMobilityGroup(w http.ResponseWriter, r *http.Request) { + log.Debug("mgCreateMobilityGroup") + + // Retrieve MG parameters from request body + var mg mgModel.MobilityGroup + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&mg) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Create new Mobility Group + err = mgCreate(&mg) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// PUT Mobility Group +func mgSetMobilityGroup(w http.ResponseWriter, r *http.Request) { + log.Debug("mgSetMobilityGroup") + + // Retrieve MG parameters from request body + var mg mgModel.MobilityGroup + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&mg) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Create new Mobility Group + err = mgUpdate(&mg) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// DELETE Mobility Group +func mgDeleteMobilityGroup(w http.ResponseWriter, r *http.Request) { + log.Debug("mgDeleteMobilityGroup") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + + // Delete Mobility Group + err := mgDelete(mgName) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// GET Mobility Group App List +func mgGetMobilityGroupAppList(w http.ResponseWriter, r *http.Request) { + log.Debug("mgGetMobilityGroupAppList") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + + // Retrieve MG from map + mgInfo := mgInfoMap[mgName] + if mgInfo == nil { + log.Error("Failed to find MG") + http.Error(w, "Failed to find MG", http.StatusNotFound) + return + } + + // Make list from MG map + mgAppList := make([]mgModel.MobilityGroupApp, 0, len(mgInfo.appInfoMap)) + for _, value := range mgInfo.appInfoMap { + mgAppList = append(mgAppList, value.app) + } + + // Format response + jsonResponse, err := json.Marshal(mgAppList) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} + +// GET Mobility Group App +func mgGetMobilityGroupApp(w http.ResponseWriter, r *http.Request) { + log.Debug("mgGetMobilityGroupApp") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + appID := vars["appId"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + // Validate MG App name + if appID == "" { + log.Debug("Invalid MG App ID") + http.Error(w, "Invalid MG App ID", http.StatusBadRequest) + return + } + + // Retrieve MG from map + mgInfo := mgInfoMap[mgName] + if mgInfo == nil { + log.Error("Failed to find MG") + http.Error(w, "Failed to find MG", http.StatusNotFound) + return + } + // Retrieve MG App from map + mgAppInfo := mgInfo.appInfoMap[appID] + if mgAppInfo == nil { + log.Error("Failed to find MG App") + http.Error(w, "Failed to find MG App", http.StatusNotFound) + return + } + // Format response + jsonResponse, err := json.Marshal(mgAppInfo.app) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, string(jsonResponse)) +} + +// POST Mobility Group App +func mgCreateMobilityGroupApp(w http.ResponseWriter, r *http.Request) { + log.Debug("mgCreateMobilityGroupApp") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + + // Retrieve MG App parameters from request body + var mgApp mgModel.MobilityGroupApp + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&mgApp) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Create new Mobility Group App + err = mgAppCreate(mgName, &mgApp) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// PUT Mobility Group App +func mgSetMobilityGroupApp(w http.ResponseWriter, r *http.Request) { + log.Debug("mgSetMobilityGroupApp") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + + // Retrieve MG App parameters from request body + var mgApp mgModel.MobilityGroupApp + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&mgApp) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Update existing Mobility Group App + err = mgAppUpdate(mgName, &mgApp) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// DELETE Mobility Group App +func mgDeleteMobilityGroupApp(w http.ResponseWriter, r *http.Request) { + log.Debug("mgDeleteMobilityGroupApp") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + appID := vars["appId"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + // Validate MG App name + if appID == "" { + log.Debug("Invalid MG App ID") + http.Error(w, "Invalid MG App ID", http.StatusBadRequest) + return + } + + // Delete Mobility Group App + err := mgAppDelete(mgName, appID) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +// POST Mobility Group UE +func mgCreateMobilityGroupUe(w http.ResponseWriter, r *http.Request) { + log.Debug("mgCreateMobilityGroupUe") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + appID := vars["appId"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + // Validate MG App name + if appID == "" { + log.Debug("Invalid MG App ID") + http.Error(w, "Invalid MG App ID", http.StatusBadRequest) + return + } + + // Retrieve MG UE parameters from request body + var mgUe mgModel.MobilityGroupUe + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&mgUe) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Create new Mobility Group UE + err = mgUeCreate(mgName, appID, &mgUe) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func mgTransferAppState(w http.ResponseWriter, r *http.Request) { + log.Debug("mgTransferAppState") + + // Get MG name from request parameters + vars := mux.Vars(r) + mgName := vars["mgName"] + appID := vars["appId"] + + // Validate MG name + if mgName == "" { + log.Debug("Invalid MG name") + http.Error(w, "Invalid MG name", http.StatusBadRequest) + return + } + // Validate MG App name + if appID == "" { + log.Debug("Invalid MG App ID") + http.Error(w, "Invalid MG App ID", http.StatusBadRequest) + return + } + + // Retrieve MG App parameters from request body + var mgAppState mgModel.MobilityGroupAppState + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&mgAppState) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + // Process App State update + err = processAppState(mgName, appID, &mgAppState) + if err != nil { + log.Error(err.Error()) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} diff --git a/go-apps/meep-mg-manager/server/mobility_group.go b/go-apps/meep-mg-manager/server/mobility_group.go new file mode 100644 index 0000000000000000000000000000000000000000..d0db630a25af343adb18733e13caa75ce65c4114 --- /dev/null +++ b/go-apps/meep-mg-manager/server/mobility_group.go @@ -0,0 +1,29 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Mobility Group +type MobilityGroup struct { + + // Mobility Group name + Name string `json:"name,omitempty"` + + // State Transfer mode + StateTransferMode string `json:"stateTransferMode,omitempty"` + + // State Transfer trigger + StateTransferTrigger string `json:"stateTransferTrigger,omitempty"` + + // Session Transfer mode + SessionTransferMode string `json:"sessionTransferMode,omitempty"` + + // Load Balancing Algorithm + LoadBalancingAlgorithm string `json:"loadBalancingAlgorithm,omitempty"` +} diff --git a/go-apps/meep-mg-manager/server/mobility_group_app.go b/go-apps/meep-mg-manager/server/mobility_group_app.go new file mode 100644 index 0000000000000000000000000000000000000000..203792428810088ba2d279ba3b34e13c9e0acbb5 --- /dev/null +++ b/go-apps/meep-mg-manager/server/mobility_group_app.go @@ -0,0 +1,20 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Mobility Group Application instance +type MobilityGroupApp struct { + + // Mobility Group Application Identifier + Id string `json:"id,omitempty"` + + // Event handler url + Url string `json:"url,omitempty"` +} diff --git a/go-apps/meep-mg-manager/server/mobility_group_app_state.go b/go-apps/meep-mg-manager/server/mobility_group_app_state.go new file mode 100644 index 0000000000000000000000000000000000000000..144a308d51c77d0986e67b8a69b01b85c72e3175 --- /dev/null +++ b/go-apps/meep-mg-manager/server/mobility_group_app_state.go @@ -0,0 +1,20 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Mobility Group Application State +type MobilityGroupAppState struct { + + // Mobility Group UE Identifier + UeId string `json:"ueId,omitempty"` + + // Mobility Group Application State for provided UE + UeState string `json:"ueState,omitempty"` +} diff --git a/go-apps/meep-mg-manager/server/mobility_group_ue.go b/go-apps/meep-mg-manager/server/mobility_group_ue.go new file mode 100644 index 0000000000000000000000000000000000000000..9f9b1119a5edf7a8d32af7a3eadd73896e93f5b4 --- /dev/null +++ b/go-apps/meep-mg-manager/server/mobility_group_ue.go @@ -0,0 +1,17 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Mobility Group UE instance +type MobilityGroupUe struct { + + // Mobility Group UE Identifier + Id string `json:"id,omitempty"` +} diff --git a/go-apps/meep-mg-manager/server/routers.go b/go-apps/meep-mg-manager/server/routers.go new file mode 100644 index 0000000000000000000000000000000000000000..cf81f2aeb2a6efa95e0c1e4aea7ffe90be7ed928 --- /dev/null +++ b/go-apps/meep-mg-manager/server/routers.go @@ -0,0 +1,140 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "/v1/", + Index, + }, + + Route{ + "CreateMobilityGroup", + strings.ToUpper("Post"), + "/v1/mg/{mgName}", + CreateMobilityGroup, + }, + + Route{ + "CreateMobilityGroupApp", + strings.ToUpper("Post"), + "/v1/mg/{mgName}/app/{appId}", + CreateMobilityGroupApp, + }, + + Route{ + "CreateMobilityGroupUe", + strings.ToUpper("Post"), + "/v1/mg/{mgName}/app/{appId}/ue", + CreateMobilityGroupUe, + }, + + Route{ + "DeleteMobilityGroup", + strings.ToUpper("Delete"), + "/v1/mg/{mgName}", + DeleteMobilityGroup, + }, + + Route{ + "DeleteMobilityGroupApp", + strings.ToUpper("Delete"), + "/v1/mg/{mgName}/app/{appId}", + DeleteMobilityGroupApp, + }, + + Route{ + "GetMobilityGroup", + strings.ToUpper("Get"), + "/v1/mg/{mgName}", + GetMobilityGroup, + }, + + Route{ + "GetMobilityGroupApp", + strings.ToUpper("Get"), + "/v1/mg/{mgName}/app/{appId}", + GetMobilityGroupApp, + }, + + Route{ + "GetMobilityGroupAppList", + strings.ToUpper("Get"), + "/v1/mg/{mgName}/app", + GetMobilityGroupAppList, + }, + + Route{ + "GetMobilityGroupList", + strings.ToUpper("Get"), + "/v1/mg", + GetMobilityGroupList, + }, + + Route{ + "SetMobilityGroup", + strings.ToUpper("Put"), + "/v1/mg/{mgName}", + SetMobilityGroup, + }, + + Route{ + "SetMobilityGroupApp", + strings.ToUpper("Put"), + "/v1/mg/{mgName}/app/{appId}", + SetMobilityGroupApp, + }, + + Route{ + "TransferAppState", + strings.ToUpper("Post"), + "/v1/mg/{mgName}/app/{appId}/state", + TransferAppState, + }, +} diff --git a/go-apps/meep-mg-manager/server/state_transfer_api.go b/go-apps/meep-mg-manager/server/state_transfer_api.go new file mode 100644 index 0000000000000000000000000000000000000000..9dd3125d91a7abc9a88660e708609084772b34b8 --- /dev/null +++ b/go-apps/meep-mg-manager/server/state_transfer_api.go @@ -0,0 +1,18 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func TransferAppState(w http.ResponseWriter, r *http.Request) { + mgTransferAppState(w, r) +} diff --git a/go-apps/meep-mon-engine/Dockerfile b/go-apps/meep-mon-engine/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..5cd680555fddb09e40c22430203be95492d30477 --- /dev/null +++ b/go-apps/meep-mon-engine/Dockerfile @@ -0,0 +1,10 @@ +# Copyright (c) 2019 +# InterDigital Communications, Inc. +# All rights reserved. +# +# The information provided herein is the proprietary and confidential +# information of InterDigital Communications, Inc. + +FROM debian:9.6-slim +COPY ./meep-mon-engine /meep-mon-engine +ENTRYPOINT /meep-mon-engine diff --git a/go-apps/meep-mon-engine/db.go b/go-apps/meep-mon-engine/db.go new file mode 100755 index 0000000000000000000000000000000000000000..577fc487dd6967367f08914ae368935bb17d363c --- /dev/null +++ b/go-apps/meep-mon-engine/db.go @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mon-engine/log" + + "github.com/go-redis/redis" +) + +var dbClient *redis.Client +var dbClientStarted = false + +// DBConnect - Establish connection to DB +func DBConnect() error { + if !dbClientStarted { + err := openDB() + if err != nil { + return err + } + } + return nil +} + +func openDB() error { + db := redis.NewClient(&redis.Options{ + Addr: "meep-redis-master:6379", + Password: "", // no password set + DB: 0, // use default DB + }) + + pong, err := db.Ping().Result() + + if pong == "" { + log.Info("pong is null") + return err + } + + if err != nil { + log.Info("Redis DB not accessible") + return err + } + dbClientStarted = true + dbClient = db + + log.Info("Redis DB opened and well!") + return nil +} + +// DBFlush - Empty DB +func DBFlush(module string) error { + var cursor uint64 + var err error + log.Debug("DBFlush module: ", module) + + // Find all module keys + // Process in chunks of 50 matching entries to optimize processing speed & memory + keyMatchStr := module + ":*" + for { + var keys []string + keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() + if err != nil { + log.Debug("ERROR: ", err) + break + } + + // Delete all matching entries + if len(keys) > 0 { + _, err = dbClient.Del(keys...).Result() + if err != nil { + log.Debug("Failed to retrieve entry fields") + break + } + } + + // Stop searching if cursor is back at beginning + if cursor == 0 { + break + } + } + + return nil +} + +// DBSetEntry - Update existing entry or create new entry if it does not exist +func DBSetEntry(key string, fields map[string]interface{}) error { + // Update existing entry or create new entry if it does not exist + _, err := dbClient.HMSet(key, fields).Result() + if err != nil { + return err + } + return nil +} + +// DBRemoveEntry - Remove existing entries +func DBRemoveEntry(keys ...string) error { + _, err := dbClient.Del(keys...).Result() + if err != nil { + return err + } + return nil +} diff --git a/go-apps/meep-mon-engine/go.mod b/go-apps/meep-mon-engine/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..cb7a0e2d1f928b7c3a4ca76b7cada43ac68fdb26 --- /dev/null +++ b/go-apps/meep-mon-engine/go.mod @@ -0,0 +1,32 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mon-engine + +go 1.12 + +require ( + github.com/go-redis/redis v6.15.2+incompatible + github.com/gogo/protobuf v1.2.1 // indirect + github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect + github.com/google/btree v1.0.0 // indirect + github.com/google/gofuzz v1.0.0 // indirect + github.com/googleapis/gnostic v0.2.0 // indirect + github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect + github.com/hashicorp/golang-lru v0.5.1 // indirect + github.com/json-iterator/go v1.1.6 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/sirupsen/logrus v1.4.1 + github.com/spf13/pflag v1.0.3 // indirect + golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a // indirect + golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a // indirect + golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect + k8s.io/api v0.0.0-20181204000039-89a74a8d264d + k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 + k8s.io/client-go v10.0.0+incompatible + k8s.io/klog v0.0.0-20181108234604-8139d8cb77af // indirect + sigs.k8s.io/yaml v1.1.0 // indirect +) diff --git a/go-apps/meep-mon-engine/go.sum b/go-apps/meep-mon-engine/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..cb2ef6316ad4ccda64ba442fc93cd30f970474d2 --- /dev/null +++ b/go-apps/meep-mon-engine/go.sum @@ -0,0 +1,95 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef h1:veQD95Isof8w9/WXiA+pa3tz3fJXkt5B7QaRBrM62gk= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a h1:Igim7XhdOpBnWPuYJ70XcNpq8q3BCACtVgNfoJxOV7g= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +k8s.io/api v0.0.0-20181204000039-89a74a8d264d h1:HQoGWsWUe/FmRcX9BU440AAMnzBFEf+DBo4nbkQlNzs= +k8s.io/api v0.0.0-20181204000039-89a74a8d264d/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 h1:tT6oQBi0qwLbbZSfDkdIsb23EwaLY85hoAV4SpXfdao= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34= +k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/klog v0.0.0-20181108234604-8139d8cb77af h1:s6rm8OxBbyDNSRkpyAd5OL4icUdBICVw9+mFADa+t5E= +k8s.io/klog v0.0.0-20181108234604-8139d8cb77af/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/go-apps/meep-mon-engine/log/meeplog.go b/go-apps/meep-mon-engine/log/meeplog.go new file mode 100644 index 0000000000000000000000000000000000000000..0615d36d4ab8abff7a258875528d52235de41486 --- /dev/null +++ b/go-apps/meep-mon-engine/log/meeplog.go @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package logmain + +import ( + log "github.com/sirupsen/logrus" +) + +func MeepJSONLogInit() { + log.SetFormatter(&log.JSONFormatter{}) + log.SetLevel(log.DebugLevel) +} + +func Info(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "mon-engine", + }).Info(args...) +} + +func Debug(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "mon-engine", + }).Debug(args...) +} + +func Warn(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "mon-engine", + }).Warn(args...) +} +func Error(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "mon-engine", + }).Error(args...) +} +func Panic(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "mon-engine", + }).Panic(args...) +} + +func Fatal(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "mon-engine", + }).Fatal(args...) +} + +func WithFields(fields log.Fields) *log.Entry { + return log.WithFields(fields) +} diff --git a/go-apps/meep-mon-engine/main.go b/go-apps/meep-mon-engine/main.go new file mode 100644 index 0000000000000000000000000000000000000000..07cd29f417d4a094eaf14cfbd8b58b4fc428d79c --- /dev/null +++ b/go-apps/meep-mon-engine/main.go @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "os" + "os/signal" + "syscall" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mon-engine/log" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.MeepJSONLogInit() +} + +func main() { + log.Info(os.Args) + log.Info("Starting Monitoring Engine") + + run := true + go func() { + sigchan := make(chan os.Signal, 10) + signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) + <-sigchan + log.Info("Program killed !") + // do last actions and wait for all write operations to end + run = false + }() + + go func() { + // Initialize Mon Engine + err := Init() + if err != nil { + log.Error("Failed to initialize Mon Engine") + run = false + return + } + + // Run Mon Engine + err = Run() + if err != nil { + log.Error("Failed to run Mon Engine") + run = false + return + } + run = false + }() + + count := 0 + for { + if !run { + log.Info("Ran for", count, "seconds") + break + } + time.Sleep(time.Second) + count++ + } +} diff --git a/go-apps/meep-mon-engine/main_test.go b/go-apps/meep-mon-engine/main_test.go new file mode 100644 index 0000000000000000000000000000000000000000..f56b01f35eb03bc011f8dd08d4c90b12a6eae5be --- /dev/null +++ b/go-apps/meep-mon-engine/main_test.go @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "os" + "strings" + "testing" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mon-engine/log" +) + +// Build: +// $ go test -covermode=count -coverpkg=./... -c -o +// Run: +// $ ./ -test.coverprofile=cover.out __DEVEL--code-cov + +// TestMain is a hack that allows us to figure out what the coverage is during +// integration tests. I would not recommend that you use a binary built using +// this hack outside of a test suite. +func TestMain(t *testing.T) { + var ( + args []string + run bool + ) + + log.Info(os.Args) + for _, arg := range os.Args { + switch { + case arg == "__DEVEL--code-cov": + run = true + case strings.HasPrefix(arg, "-test"): + case strings.HasPrefix(arg, "__DEVEL"): + default: + args = append(args, arg) + } + } + os.Args = args + log.Info(os.Args) + + if run { + main() + } +} diff --git a/go-apps/meep-mon-engine/mon-engine.go b/go-apps/meep-mon-engine/mon-engine.go new file mode 100644 index 0000000000000000000000000000000000000000..02026e1073145ff6993ed4cb94b1d60ec571a9f8 --- /dev/null +++ b/go-apps/meep-mon-engine/mon-engine.go @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "fmt" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-mon-engine/log" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/apimachinery/pkg/fields" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" +) + +const moduleMonEngine string = "mon-engine" + +//index in array +const EVENT_POD_ADDED = 0 +const EVENT_POD_MODIFIED = 1 +const EVENT_POD_DELETED = 2 + +var pod_event_str = [3]string{"pod added", "pod modified", "pod deleted"} + +type MonEngineInfo struct { + PodName string + Namespace string + MeepApp string + MeepOrigin string + MeepScenario string + Phase string + PodInitialized string + PodReady string + PodScheduled string + PodUnschedulable string + PodConditionError string + ContainerStatusesMsg string + NbOkContainers int + NbTotalContainers int + NbPodRestart int + LogicalState string + StartTime string +} + +// Init - Mon Engine initialization +func Init() (err error) { + + // Connect to Redis DB + err = DBConnect() + if err != nil { + log.Error("Failed connection to Active DB. Error: ", err) + return err + } + log.Info("Connected to Active DB") + + // Empty DB + DBFlush(moduleMonEngine) + + return nil +} + +// Run - Mon Engine main loop +func Run() (err error) { + + // Watch k8s pods (main loop) + err = k8sConnect() + if err != nil { + log.Error("Failed to watch k8s pods") + return err + } + + return nil +} + +func connectToAPISvr() (*kubernetes.Clientset, error) { + + // Create the in-cluster config + config, err := rest.InClusterConfig() + if err != nil { + log.Error(err) + return nil, err + } + // Create the clientset + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + log.Error(err) + return nil, err + } + return clientset, nil +} + +func printfMonEngineInfo(monEngineInfo MonEngineInfo, reason int) { + + log.Debug("Monitoring Engine info *** ", pod_event_str[reason], " *** ", + "pod name : ", monEngineInfo.PodName, + "namespace : ", monEngineInfo.Namespace, + "meepApp : ", monEngineInfo.MeepApp, + "meepOrigin : ", monEngineInfo.MeepOrigin, + "meepScenario : ", monEngineInfo.MeepScenario, + "phase : ", monEngineInfo.Phase, + "podInitialized : ", monEngineInfo.PodInitialized, + "podUnschedulable : ", monEngineInfo.PodUnschedulable, + "podScheduled : ", monEngineInfo.PodScheduled, + "podReady : ", monEngineInfo.PodReady, + "podConditionError : ", monEngineInfo.PodConditionError, + "ContainerStatusesMsg : ", monEngineInfo.ContainerStatusesMsg, + "NbOkContainers : ", monEngineInfo.NbOkContainers, + "NbTotalContainers : ", monEngineInfo.NbTotalContainers, + "NbPodRestart : ", monEngineInfo.NbPodRestart, + "LogicalState : ", monEngineInfo.LogicalState, + "StartTime : ", monEngineInfo.StartTime) + +} + +func processEvent(obj interface{}, reason int) { + if pod, ok := obj.(*v1.Pod); ok { + + var monEngineInfo MonEngineInfo + + if reason != EVENT_POD_DELETED { + podConditionMsg := "" + podScheduled := "False" + podReady := "False" + podInitialized := "False" + podUnschedulable := "False" + nbConditions := len(pod.Status.Conditions) + for i := 0; i < nbConditions; i++ { + switch pod.Status.Conditions[i].Type { + case "PodScheduled": + podScheduled = string(pod.Status.Conditions[i].Status) + case "Ready": + podReady = string(pod.Status.Conditions[i].Status) + if podReady == "False" { + podConditionMsg = string(pod.Status.Conditions[i].Message) + } + case "Initialized": + podInitialized = string(pod.Status.Conditions[i].Status) + case "Unschedulable": + podUnschedulable = string(pod.Status.Conditions[i].Status) + } + } + + nbContainers := len(pod.Status.ContainerStatuses) + okContainers := 0 + restartCount := 0 + reasonFailureStr := "" + for i := 0; i < nbContainers; i++ { + if pod.Status.ContainerStatuses[i].Ready { + okContainers++ + } else { + if pod.Status.ContainerStatuses[i].State.Waiting != nil { + reasonFailureStr = pod.Status.ContainerStatuses[i].State.Waiting.Reason + } else if pod.Status.ContainerStatuses[i].State.Terminated != nil { + if reasonFailureStr != "" { + reasonFailureStr = pod.Status.ContainerStatuses[i].State.Terminated.Reason + } + } + } + //only update if the value is greater than 0, and we keep it + if restartCount == 0 { + restartCount = int(pod.Status.ContainerStatuses[i].RestartCount) + } + } + + monEngineInfo.PodInitialized = podInitialized + monEngineInfo.PodUnschedulable = podUnschedulable + monEngineInfo.PodScheduled = podScheduled + monEngineInfo.PodReady = podReady + monEngineInfo.PodConditionError = podConditionMsg + monEngineInfo.ContainerStatusesMsg = reasonFailureStr + monEngineInfo.NbOkContainers = okContainers + monEngineInfo.NbTotalContainers = nbContainers + monEngineInfo.NbPodRestart = restartCount + } + + //common for both the add, update and delete + monEngineInfo.Phase = string(pod.Status.Phase) + monEngineInfo.PodName = pod.Name + monEngineInfo.Namespace = pod.Namespace + monEngineInfo.MeepApp = pod.Labels["meepApp"] + monEngineInfo.MeepOrigin = pod.Labels["meepOrigin"] + monEngineInfo.MeepScenario = pod.Labels["meepScenario"] + if pod.Status.StartTime != nil { + monEngineInfo.StartTime = pod.Status.StartTime.String() + } + + monEngineInfo.LogicalState = monEngineInfo.Phase + + //Phase is Running but might not really be because of some other attributes + //start of override section of the LogicalState by specific conditions + + if pod.GetObjectMeta().GetDeletionTimestamp() != nil { + monEngineInfo.LogicalState = "Terminating" + } else { + if monEngineInfo.PodReady != "True" { + monEngineInfo.LogicalState = "Pending" + } else { + if monEngineInfo.NbOkContainers < monEngineInfo.NbTotalContainers { + monEngineInfo.LogicalState = "Failed" + } + } + } + //end of override section + + printfMonEngineInfo(monEngineInfo, reason) + + if reason == EVENT_POD_DELETED { + deleteEntryInDB(monEngineInfo) + } else { + addOrUpdateEntryInDB(monEngineInfo) + } + } +} + +func addOrUpdateEntryInDB(monEngineInfo MonEngineInfo) { + // Populate rule fields + fields := make(map[string]interface{}) + fields["name"] = monEngineInfo.PodName + fields["namespace"] = monEngineInfo.Namespace + fields["meepApp"] = monEngineInfo.MeepApp + fields["meepOrigin"] = monEngineInfo.MeepOrigin + fields["meepScenario"] = monEngineInfo.MeepScenario + fields["phase"] = monEngineInfo.Phase + fields["initialised"] = monEngineInfo.PodInitialized + fields["scheduled"] = monEngineInfo.PodScheduled + fields["ready"] = monEngineInfo.PodReady + fields["unschedulable"] = monEngineInfo.PodUnschedulable + fields["condition-error"] = monEngineInfo.PodConditionError + fields["nbOkContainers"] = monEngineInfo.NbOkContainers + fields["nbTotalContainers"] = monEngineInfo.NbTotalContainers + fields["nbPodRestart"] = monEngineInfo.NbPodRestart + fields["logicalState"] = monEngineInfo.LogicalState + fields["startTime"] = monEngineInfo.StartTime + + // Make unique key + key := moduleMonEngine + ":MO-" + monEngineInfo.MeepOrigin + ":MS-" + monEngineInfo.MeepScenario + ":MA-" + monEngineInfo.MeepApp + ":" + monEngineInfo.PodName + + // Set rule information in DB + _ = DBSetEntry(key, fields) +} + +func deleteEntryInDB(monEngineInfo MonEngineInfo) { + + // Make unique key + key := moduleMonEngine + ":MO-" + monEngineInfo.MeepOrigin + ":MS-" + monEngineInfo.MeepScenario + ":MA-" + monEngineInfo.MeepApp + ":" + monEngineInfo.PodName + + // Set rule information in DB + _ = DBRemoveEntry(key) +} + +func k8sConnect() (err error) { + + // Connect to K8s API Server + clientset, err := connectToAPISvr() + if err != nil { + log.Error("Failed to connect with k8s API Server. Error: ", err) + return err + } + + //scenarioName := "latency-demo" + meepOrigin := "core" + + // Retrieve pods from k8s api with scenario label + pods, err := clientset.CoreV1().Pods("").List( + metav1.ListOptions{LabelSelector: fmt.Sprintf("meepOrigin=%s", meepOrigin)}) + if err != nil { + log.Error("Failed to retrieve services from k8s API Server. Error: ", err) + return err + } + + // Store service IPs + for _, pod := range pods.Items { + podName := pod.ObjectMeta.Name + podPhase := pod.Status.Phase + log.Debug("podName: ", podName, " podPhase: ", podPhase) + } + + watchlist := cache.NewListWatchFromClient(clientset.CoreV1().RESTClient(), "pods", v1.NamespaceAll, fields.Everything()) + + _, controller := cache.NewInformer( // also take a look at NewSharedIndexInformer + watchlist, + &v1.Pod{}, + 0, //Duration is int64 + cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + processEvent(obj, EVENT_POD_ADDED) + }, + DeleteFunc: func(obj interface{}) { + processEvent(obj, EVENT_POD_DELETED) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + processEvent(newObj, EVENT_POD_MODIFIED) + }, + }, + ) + + stop := make(chan struct{}) + defer close(stop) + go controller.Run(stop) + for { + time.Sleep(time.Second) + } +} diff --git a/go-apps/meep-tc-engine/.swagger-codegen-ignore b/go-apps/meep-tc-engine/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/go-apps/meep-tc-engine/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/go-apps/meep-tc-engine/.swagger-codegen/VERSION b/go-apps/meep-tc-engine/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..a6254504e40175d135cea7feb34ad31fa0d0bca3 --- /dev/null +++ b/go-apps/meep-tc-engine/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.1 \ No newline at end of file diff --git a/go-apps/meep-tc-engine/Dockerfile b/go-apps/meep-tc-engine/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..8b56ec329b3cab9f8b96dd22dc3a362acbf2308e --- /dev/null +++ b/go-apps/meep-tc-engine/Dockerfile @@ -0,0 +1,10 @@ +# Copyright (c) 2019 +# InterDigital Communications, Inc. +# All rights reserved. +# +# The information provided herein is the proprietary and confidential +# information of InterDigital Communications, Inc. + +FROM debian:9.6-slim +COPY ./meep-tc-engine /meep-tc-engine +ENTRYPOINT /meep-tc-engine diff --git a/bin/meep-ctrl-engine/static/api/meep-tc-engine.yaml b/go-apps/meep-tc-engine/api/swagger.yaml similarity index 99% rename from bin/meep-ctrl-engine/static/api/meep-tc-engine.yaml rename to go-apps/meep-tc-engine/api/swagger.yaml index 681da77872e9367c6b6d2bd41c9b415c913d84d9..82a090bd5252e23cdd1a09f7564e1dac63f416df 100644 --- a/bin/meep-ctrl-engine/static/api/meep-tc-engine.yaml +++ b/go-apps/meep-tc-engine/api/swagger.yaml @@ -1,10 +1,11 @@ --- swagger: "2.0" info: - description: "This is the MEEP TC controller API" + description: "Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved.\ + \ The information provided herein is the proprietary and confidential information\ + \ of InterDigital Communications, Inc.\n" version: "1.0.0" title: "MEEP TC controller API" - termsOfService: "InterDigital Internal Only" basePath: "/v1" tags: - name: "Scenario Deployment" diff --git a/go-apps/meep-tc-engine/go.mod b/go-apps/meep-tc-engine/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..55463432807d413778a742769368760f780a70e8 --- /dev/null +++ b/go-apps/meep-tc-engine/go.mod @@ -0,0 +1,41 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-engine + +go 1.12 + +require ( + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model v0.0.0 + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-manager-model v0.0.0 + github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db // indirect + github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351 + github.com/go-redis/redis v6.15.2+incompatible + github.com/gogo/protobuf v1.2.1 // indirect + github.com/google/btree v1.0.0 // indirect + github.com/google/gofuzz v1.0.0 // indirect + github.com/googleapis/gnostic v0.2.0 // indirect + github.com/gorilla/handlers v1.4.0 + github.com/gorilla/mux v1.7.1 + github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect + github.com/json-iterator/go v1.1.6 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/sirupsen/logrus v1.4.1 + github.com/spf13/pflag v1.0.3 // indirect + golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a // indirect + golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a // indirect + golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.2.2 // indirect + k8s.io/api v0.0.0-20181204000039-89a74a8d264d // indirect + k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 + k8s.io/client-go v10.0.0+incompatible + k8s.io/klog v0.0.0-20181108234604-8139d8cb77af // indirect + sigs.k8s.io/yaml v1.1.0 // indirect +) + +replace ( + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model => ../../go-packages/meep-ctrl-engine-model + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-manager-model => ../../go-packages/meep-mg-manager-model +) diff --git a/go-apps/meep-tc-engine/go.sum b/go-apps/meep-tc-engine/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..4c27f3b70fae658a5dca022fd5aa2ca49ba86b27 --- /dev/null +++ b/go-apps/meep-tc-engine/go.sum @@ -0,0 +1,100 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db h1:Zkf5kwhxdW0xV7WM/crqIcOP5LCFGnAmumWSFAewJ74= +github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db/go.mod h1:RU+6d0CNIRSp6yo1mXLIIrnFa/3LHhvcDVLVJyovptM= +github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351 h1:1u1XrfCBnY+GijnyU6O1k4odp5TnqZQTsp5v7+n/E4Y= +github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351/go.mod h1:HxwfbuElTuGf+/uKZfjJrCnv0BmmpkPJDI7gBwj1KkM= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g= +github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= +github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= +github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q= +github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= +github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a h1:Igim7XhdOpBnWPuYJ70XcNpq8q3BCACtVgNfoJxOV7g= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +k8s.io/api v0.0.0-20181204000039-89a74a8d264d h1:HQoGWsWUe/FmRcX9BU440AAMnzBFEf+DBo4nbkQlNzs= +k8s.io/api v0.0.0-20181204000039-89a74a8d264d/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 h1:tT6oQBi0qwLbbZSfDkdIsb23EwaLY85hoAV4SpXfdao= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34= +k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/klog v0.0.0-20181108234604-8139d8cb77af h1:s6rm8OxBbyDNSRkpyAd5OL4icUdBICVw9+mFADa+t5E= +k8s.io/klog v0.0.0-20181108234604-8139d8cb77af/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/go-apps/meep-tc-engine/log/meeplog.go b/go-apps/meep-tc-engine/log/meeplog.go new file mode 100644 index 0000000000000000000000000000000000000000..030dd74bf1aab4a256a0fd6f33a943965f0f8e3a --- /dev/null +++ b/go-apps/meep-tc-engine/log/meeplog.go @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package logmain + +import ( + log "github.com/sirupsen/logrus" +) + +func MeepJSONLogInit() { + log.SetFormatter(&log.JSONFormatter{}) + log.SetLevel(log.DebugLevel) +} + +func Info(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "tc-engine", + }).Info(args...) +} + +func Debug(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "tc-engine", + }).Debug(args...) +} + +func Warn(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "tc-engine", + }).Warn(args...) +} +func Error(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "tc-engine", + }).Error(args...) +} +func Panic(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "tc-engine", + }).Panic(args...) +} + +func Fatal(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "tc-engine", + }).Fatal(args...) +} + +func WithFields(fields log.Fields) *log.Entry { + return log.WithFields(fields) +} diff --git a/go-apps/meep-tc-engine/main.go b/go-apps/meep-tc-engine/main.go new file mode 100644 index 0000000000000000000000000000000000000000..b69058f2a3a1ca32bf9c6a7f5f8e4fae519ee658 --- /dev/null +++ b/go-apps/meep-tc-engine/main.go @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "net/http" + "os" + "os/signal" + "syscall" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-engine/log" + server "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-engine/server" + + "github.com/gorilla/handlers" +) + +func init() { + // Log as JSON instead of the default ASCII formatter. + log.MeepJSONLogInit() +} + +func main() { + log.Info(os.Args) + + log.Info("Starting TC Engine") + + run := true + go func() { + sigchan := make(chan os.Signal, 10) + signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) + <-sigchan + log.Info("Program killed !") + // do last actions and wait for all write operations to end + run = false + }() + + go func() { + // Initialize TC Engine + err := server.Init() + if err != nil { + log.Error("Failed to initialize TC Engine") + run = false + return + } + + // Start TC Engine Event Handler thread + go server.Run() + + // Start TC Engine REST API Server + router := server.NewRouter() + methods := handlers.AllowedMethods([]string{"OPTIONS", "DELETE", "GET", "HEAD", "POST", "PUT"}) + header := handlers.AllowedHeaders([]string{"content-type"}) + log.Fatal(http.ListenAndServe(":80", handlers.CORS(methods, header)(router))) + run = false + }() + + count := 0 + for { + if !run { + log.Info("Ran for", count, "seconds") + break + } + time.Sleep(time.Second) + count++ + } + +} diff --git a/go-apps/meep-tc-engine/main_test.go b/go-apps/meep-tc-engine/main_test.go new file mode 100644 index 0000000000000000000000000000000000000000..db513069ba37e853bae673e75fb6a0141e93e1e6 --- /dev/null +++ b/go-apps/meep-tc-engine/main_test.go @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "os" + "strings" + "testing" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-engine/log" +) + +// Build: +// $ go test -covermode=count -coverpkg=./... -c -o +// Run: +// $ ./ -test.coverprofile=cover.out __DEVEL--code-cov + +// TestMain is a hack that allows us to figure out what the coverage is during +// integration tests. I would not recommend that you use a binary built using +// this hack outside of a test suite. +func TestMain(t *testing.T) { + var ( + args []string + run bool + ) + + log.Info(os.Args) + for _, arg := range os.Args { + switch { + case arg == "__DEVEL--code-cov": + run = true + case strings.HasPrefix(arg, "-test"): + case strings.HasPrefix(arg, "__DEVEL"): + default: + args = append(args, arg) + } + } + os.Args = args + log.Info(os.Args) + + if run { + main() + } +} diff --git a/go-apps/meep-tc-engine/server/README.md b/go-apps/meep-tc-engine/server/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ac8143fb41b4968ff0f9368f8fd5838d98ca4f9a --- /dev/null +++ b/go-apps/meep-tc-engine/server/README.md @@ -0,0 +1,25 @@ +# Go API Server for server + +Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + +## Overview +This server was generated by the [swagger-codegen] +(https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) + +- API version: 1.0.0 +- Build date: 2019-05-15T12:26:20.811-04:00 + + +### Running the server +To run the server, follow these simple steps: + +``` +go run main.go +``` + diff --git a/go-apps/meep-tc-engine/server/client_basic_info.go b/go-apps/meep-tc-engine/server/client_basic_info.go new file mode 100644 index 0000000000000000000000000000000000000000..09d07cee429a78a05d6f22efd18066af665dc426 --- /dev/null +++ b/go-apps/meep-tc-engine/server/client_basic_info.go @@ -0,0 +1,20 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Client basic information object +type ClientBasicInfo struct { + + // Unique pod identifier + PodId string `json:"podId,omitempty"` + + // IP address of the pod (client) + Ip string `json:"ip,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/db.go b/go-apps/meep-tc-engine/server/db.go new file mode 100755 index 0000000000000000000000000000000000000000..d75076711359e45b647b52d07d612eb4439998fe --- /dev/null +++ b/go-apps/meep-tc-engine/server/db.go @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package server + +import ( + "errors" + "net" + "reflect" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-engine/log" + + "github.com/KromDaniel/rejonson" + "github.com/go-redis/redis" +) + +var dbClient *rejonson.Client +var dbClientStarted = false + +var pubsub *redis.PubSub + +// DBConnect - Establish connection to DB +func DBConnect() error { + if !dbClientStarted { + err := openDB() + if err != nil { + return err + } + } + return nil +} + +func openDB() error { + redisClient := redis.NewClient(&redis.Options{ + Addr: "meep-redis-master:6379", + Password: "", // no password set + DB: 0, // use default DB + }) + rejonsonClient := rejonson.ExtendClient(redisClient) + + pong, err := rejonsonClient.Ping().Result() + if pong == "" { + log.Info("pong is null") + return err + } + if err != nil { + log.Info("Redis DB not accessible") + return err + } + + dbClientStarted = true + dbClient = rejonsonClient + + log.Info("Redis DB opened and well!") + return nil +} + +// DBFlush - Empty DB +func DBFlush(module string) error { + var cursor uint64 + var err error + log.Debug("DBFlush module: ", module) + + // Find all module keys + // Process in chunks of 50 matching entries to optimize processing speed & memory + keyMatchStr := module + ":*" + for { + var keys []string + keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() + if err != nil { + log.Debug("ERROR: ", err) + break + } + + // Delete all matching entries + if len(keys) > 0 { + _, err = dbClient.Del(keys...).Result() + if err != nil { + log.Debug("Failed to retrieve entry fields") + break + } + } + + // Stop searching if cursor is back at beginning + if cursor == 0 { + break + } + } + + return nil +} + +// DBSetEntry - Update existing entry or create new entry if it does not exist +func DBSetEntry(key string, fields map[string]interface{}) error { + // Update existing entry or create new entry if it does not exist + _, err := dbClient.HMSet(key, fields).Result() + if err != nil { + return err + } + return nil +} + +// DBRemoveEntry - Remove existing entries +func DBRemoveEntry(keys ...string) error { + _, err := dbClient.Del(keys...).Result() + if err != nil { + return err + } + return nil +} + +// DBForEachEntry - Search for matching keys and run handler for each entry +func DBForEachEntry(keyMatchStr string, entryHandler func(string, map[string]string, interface{}) error, userData interface{}) error { + var cursor uint64 + var err error + + // Process in chunks of 50 matching entries to optimize processing speed & memory + for { + var keys []string + keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() + if err != nil { + log.Debug("ERROR: ", err) + break + } + + if len(keys) > 0 { + for i := 0; i < len(keys); i++ { + fields, err := dbClient.HGetAll(keys[i]).Result() + if err != nil || fields == nil { + log.Debug("Failed to retrieve entry fields") + break + } + + // Invoke handler to process entry + err = entryHandler(keys[i], fields, userData) + if err != nil { + return err + } + } + } + + // Stop searching if cursor is back at beginning + if cursor == 0 { + break + } + } + return nil +} + +// DBJsonGetEntry - Retrieve entry from DB +func DBJsonGetEntry(key string, path string) (string, error) { + // Update existing entry or create new entry if it does not exist + json, err := dbClient.JsonGet(key, path).Result() + if err != nil { + return "", err + } + return json, nil +} + +// DBJsonSetEntry - Update existing entry or create new entry if it does not exist +func DBJsonSetEntry(key string, path string, json string) error { + // Update existing entry or create new entry if it does not exist + _, err := dbClient.JsonSet(key, path, json).Result() + if err != nil { + return err + } + return nil +} + +// DBJsonDelEntry - Remove existing entry +func DBJsonDelEntry(key string, path string) error { + _, err := dbClient.JsonDel(key, path).Result() + if err != nil { + return err + } + return nil +} + +// Subscribe - Register as a listener for provided channels +func Subscribe(channels ...string) error { + pubsub = dbClient.Subscribe(channels...) + return nil +} + +// Listen - Wait for subscribed events +func Listen(handler func(string, string)) error { + + // Make sure listener is subscribed to pubsub + if pubsub == nil { + return errors.New("Not subscribed to pubsub") + } + + // Main listening loop + for { + // Wait for subscribed channel events, or timeout + msg, err := pubsub.ReceiveTimeout(time.Second) + if err != nil { + if reflect.TypeOf(err) == reflect.TypeOf(&net.OpError{}) && + reflect.TypeOf(err.(*net.OpError).Err).String() == "*net.timeoutError" { + // Timeout, ignore and wait for next event + continue + } + } + + // Process published event + switch m := msg.(type) { + + // Process Subscription + case *redis.Subscription: + log.Info("Subscription Message: ", m.Kind, " to channel ", m.Channel, ". Total subscriptions: ", m.Count) + + // Process received Message + case *redis.Message: + log.Info("MSG on ", m.Channel, ": ", m.Payload) + handler(m.Channel, m.Payload) + } + } +} + +// Publish - Publish message to channel +func Publish(channel string, message string) error { + log.Info("Publish to channel: ", channel, " Message: ", message) + _, err := dbClient.Publish(channel, message).Result() + return err +} diff --git a/go-apps/meep-tc-engine/server/deployment.go b/go-apps/meep-tc-engine/server/deployment.go new file mode 100644 index 0000000000000000000000000000000000000000..a9b7dc7f30e433187447b620332e5ace0b7ed0a5 --- /dev/null +++ b/go-apps/meep-tc-engine/server/deployment.go @@ -0,0 +1,28 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Network deployment object +type Deployment struct { + + // Latency in ms between domains + InterDomainLatency int32 `json:"interDomainLatency,omitempty"` + + // Latency variation in ms between domains + InterDomainLatencyVariation int32 `json:"interDomainLatencyVariation,omitempty"` + + // The limit of the traffic supported between domains + InterDomainThroughput int32 `json:"interDomainThroughput,omitempty"` + + // Packet lost (in terms of percentage) between domains + InterDomainPacketLoss float64 `json:"interDomainPacketLoss,omitempty"` + + Domains []Domain `json:"domains,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/domain.go b/go-apps/meep-tc-engine/server/domain.go new file mode 100644 index 0000000000000000000000000000000000000000..d5df948cf31080e244fb8993ba9746cb804e16c6 --- /dev/null +++ b/go-apps/meep-tc-engine/server/domain.go @@ -0,0 +1,37 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Operator domain object +type Domain struct { + + // Unique domain ID + Id string `json:"id,omitempty"` + + // Domain name + Name string `json:"name,omitempty"` + + // Domain type + Type_ string `json:"type,omitempty"` + + // Latency in ms between zones within domain + InterZoneLatency int32 `json:"interZoneLatency,omitempty"` + + // Latency variation in ms between zones within domain + InterZoneLatencyVariation int32 `json:"interZoneLatencyVariation,omitempty"` + + // The limit of the traffic supported between zones within the domain + InterZoneThroughput int32 `json:"interZoneThroughput,omitempty"` + + // Packet lost (in terms of percentage) between zones within the domain + InterZonePacketLoss float64 `json:"interZonePacketLoss,omitempty"` + + Zones []Zone `json:"zones,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/external_config.go b/go-apps/meep-tc-engine/server/external_config.go new file mode 100644 index 0000000000000000000000000000000000000000..48bd657a45eb5e698ca9c8847e6fb788f71bb01a --- /dev/null +++ b/go-apps/meep-tc-engine/server/external_config.go @@ -0,0 +1,17 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// External Process configuration. NOTE: Only valid if 'isExternal' is set. +type ExternalConfig struct { + IngressServiceMap []ServiceMap `json:"ingressServiceMap,omitempty"` + + EgressServiceMap []ServiceMap `json:"egressServiceMap,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/logger.go b/go-apps/meep-tc-engine/server/logger.go new file mode 100644 index 0000000000000000000000000000000000000000..7136a35aa11bade1ab1d909f9de13d35a10e9eb7 --- /dev/null +++ b/go-apps/meep-tc-engine/server/logger.go @@ -0,0 +1,32 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/go-apps/meep-tc-engine/server/network_location.go b/go-apps/meep-tc-engine/server/network_location.go new file mode 100644 index 0000000000000000000000000000000000000000..e2eb07a909301ff767e951701fdabb0d7530f19a --- /dev/null +++ b/go-apps/meep-tc-engine/server/network_location.go @@ -0,0 +1,37 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Logical network location object +type NetworkLocation struct { + + // Unique network location ID + Id string `json:"id,omitempty"` + + // Network location name + Name string `json:"name,omitempty"` + + // Network location type + Type_ string `json:"type,omitempty"` + + // Latency in ms for all terminal links within network location + TerminalLinkLatency int32 `json:"terminalLinkLatency,omitempty"` + + // Latency variation in ms for all terminal links within network location + TerminalLinkLatencyVariation int32 `json:"terminalLinkLatencyVariation,omitempty"` + + // The limit of the traffic supported for all terminal links within the network location + TerminalLinkThroughput int32 `json:"terminalLinkThroughput,omitempty"` + + // Packet lost (in terms of percentage) for all terminal links within the network location + TerminalLinkPacketLoss float64 `json:"terminalLinkPacketLoss,omitempty"` + + PhysicalLocations []PhysicalLocation `json:"physicalLocations,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/new_client_sidecar_api.go b/go-apps/meep-tc-engine/server/new_client_sidecar_api.go new file mode 100644 index 0000000000000000000000000000000000000000..98684ce630b3f58c0085f7b08d4645d41e8fabb6 --- /dev/null +++ b/go-apps/meep-tc-engine/server/new_client_sidecar_api.go @@ -0,0 +1,19 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func NewClient(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} diff --git a/go-apps/meep-tc-engine/server/physical_location.go b/go-apps/meep-tc-engine/server/physical_location.go new file mode 100644 index 0000000000000000000000000000000000000000..41b01032eebb23857d326a66356be6963cd1d603 --- /dev/null +++ b/go-apps/meep-tc-engine/server/physical_location.go @@ -0,0 +1,30 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Physical location object +type PhysicalLocation struct { + + // Unique physical location ID + Id string `json:"id,omitempty"` + + // Physical location name + Name string `json:"name,omitempty"` + + // Physical location type + Type_ string `json:"type,omitempty"` + + // true: Physical location is external to MEEP false: Physical location is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + NetworkLocationsInRange []string `json:"networkLocationsInRange,omitempty"` + + Processes []Process `json:"processes,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/process.go b/go-apps/meep-tc-engine/server/process.go new file mode 100644 index 0000000000000000000000000000000000000000..6e79fecd765a4eb12e22e470e6ae6f3f72e804b7 --- /dev/null +++ b/go-apps/meep-tc-engine/server/process.go @@ -0,0 +1,54 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Application or service object +type Process struct { + + // Unique process ID + Id string `json:"id,omitempty"` + + // Process name + Name string `json:"name,omitempty"` + + // Process type + Type_ string `json:"type,omitempty"` + + // true: process is external to MEEP false: process is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + // Docker image to deploy inside MEEP + Image string `json:"image,omitempty"` + + // Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" + Environment string `json:"environment,omitempty"` + + // Arguments to command executable + CommandArguments string `json:"commandArguments,omitempty"` + + // Executable to invoke at container start up + CommandExe string `json:"commandExe,omitempty"` + + ServiceConfig *ServiceConfig `json:"serviceConfig,omitempty"` + + ExternalConfig *ExternalConfig `json:"externalConfig,omitempty"` + + // Process status + Status string `json:"status,omitempty"` + + // Chart location for the deployment of the chart provided by the user + UserChartLocation string `json:"userChartLocation,omitempty"` + + // Chart values.yaml file location for the deployment of the chart provided by the user + UserChartAlternateValues string `json:"userChartAlternateValues,omitempty"` + + // Chart supplemental information related to the group (service) + UserChartGroup string `json:"userChartGroup,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/routers.go b/go-apps/meep-tc-engine/server/routers.go new file mode 100644 index 0000000000000000000000000000000000000000..15e0171d0affa4bbf5ed88f1147ef25f0b9bdad9 --- /dev/null +++ b/go-apps/meep-tc-engine/server/routers.go @@ -0,0 +1,84 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "/v1/", + Index, + }, + + Route{ + "NewClient", + strings.ToUpper("Post"), + "/v1/clients", + NewClient, + }, + + Route{ + "ActivateScenario", + strings.ToUpper("Post"), + "/v1/scenarios/active", + ActivateScenario, + }, + + Route{ + "DeleteNetworkCharacteristicsTable", + strings.ToUpper("Delete"), + "/v1/scenarios/active", + DeleteNetworkCharacteristicsTable, + }, + + Route{ + "GetNetworkCharacteristicsTable", + strings.ToUpper("Get"), + "/v1/scenarios/active", + GetNetworkCharacteristicsTable, + }, +} diff --git a/go-apps/meep-tc-engine/server/scenario.go b/go-apps/meep-tc-engine/server/scenario.go new file mode 100644 index 0000000000000000000000000000000000000000..04ef204f5ecf56cb7c93c64cf9550a804650ffe5 --- /dev/null +++ b/go-apps/meep-tc-engine/server/scenario.go @@ -0,0 +1,21 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Scenario object +type Scenario struct { + + // Unique scenario name + Name string `json:"name,omitempty"` + + Config *ScenarioConfig `json:"config,omitempty"` + + Deployment *Deployment `json:"deployment,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/scenario_config.go b/go-apps/meep-tc-engine/server/scenario_config.go new file mode 100644 index 0000000000000000000000000000000000000000..6d1f9125cd5aa95f333abacafca005f25d62ff2f --- /dev/null +++ b/go-apps/meep-tc-engine/server/scenario_config.go @@ -0,0 +1,20 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Scenario configuration +type ScenarioConfig struct { + + // Visualization configuration + Visualization string `json:"visualization,omitempty"` + + // Other scenario configuration + Other string `json:"other,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/scenario_deployment_api.go b/go-apps/meep-tc-engine/server/scenario_deployment_api.go new file mode 100644 index 0000000000000000000000000000000000000000..0376bae02c74da8b6f18b9253782872a626027dd --- /dev/null +++ b/go-apps/meep-tc-engine/server/scenario_deployment_api.go @@ -0,0 +1,29 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func ActivateScenario(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func DeleteNetworkCharacteristicsTable(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func GetNetworkCharacteristicsTable(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} diff --git a/go-apps/meep-tc-engine/server/service_config.go b/go-apps/meep-tc-engine/server/service_config.go new file mode 100644 index 0000000000000000000000000000000000000000..41836c331fe9e898314d19d8cbedcfd27023a018 --- /dev/null +++ b/go-apps/meep-tc-engine/server/service_config.go @@ -0,0 +1,22 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Service object +type ServiceConfig struct { + + // Unique service name + Name string `json:"name,omitempty"` + + // Multi-Edge service name, if any + MeSvcName string `json:"meSvcName,omitempty"` + + Ports []ServicePort `json:"ports,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/service_map.go b/go-apps/meep-tc-engine/server/service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..5d1cb2ce846d415e7e8508d4af26e25a71844e90 --- /dev/null +++ b/go-apps/meep-tc-engine/server/service_map.go @@ -0,0 +1,29 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Mapping of exposed ports to internal or external services +type ServiceMap struct { + + // Service name + Name string `json:"name,omitempty"` + + // Service IP address for external service only (egress)
  • N/A for internal services + Ip string `json:"ip,omitempty"` + + // Service port number + Port int32 `json:"port,omitempty"` + + // Port used to expose internal service only (ingress)
  • Must be unique port in range (30000 - 32767)
  • N/A for external services + ExternalPort int32 `json:"externalPort,omitempty"` + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/service_port.go b/go-apps/meep-tc-engine/server/service_port.go new file mode 100644 index 0000000000000000000000000000000000000000..43014b22184493e9a75ced55fb78a2d42b713a3e --- /dev/null +++ b/go-apps/meep-tc-engine/server/service_port.go @@ -0,0 +1,23 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Service port object +type ServicePort struct { + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` + + // Port number that the service is listening on + Port int32 `json:"port,omitempty"` + + // External port number on which to expose the application (30000 - 32767)
  • Only one application allowed per external port
  • Scenario builder must configure to prevent conflicts + ExternalPort int32 `json:"externalPort,omitempty"` +} diff --git a/go-apps/meep-tc-engine/server/tc-engine.go b/go-apps/meep-tc-engine/server/tc-engine.go new file mode 100644 index 0000000000000000000000000000000000000000..e9e020218d0ac150a2c2c5f90feec3a8116e3f76 --- /dev/null +++ b/go-apps/meep-tc-engine/server/tc-engine.go @@ -0,0 +1,1209 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package server + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-engine/log" + ceModel "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model" + mgModel "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-manager-model" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" +) + +const moduleTcEngine string = "tc-engine" +const moduleCtrlEngine string = "ctrl-engine" +const moduleMgManager string = "mg-manager" + +const typeActive string = "active" +const typeNet string = "net" +const typeLb string = "lb" + +const channelCtrlActive string = moduleCtrlEngine + "-" + typeActive +const channelMgManagerLb string = moduleMgManager + "-" + typeLb +const channelTcNet string = moduleTcEngine + "-" + typeNet +const channelTcLb string = moduleTcEngine + "-" + typeLb + +const MAX_THROUGHPUT = 9999999999 //easy value to spot in the array +const COMMON_CORRELATION = 50 +const COMMON_PACKET_LOSS = 10 // 1000 -> 10.00% +const THROUGHPUT_UNIT = 1000000 //convert from Mbps to bps +//index in array +const LATENCY = 0 +const LATENCY_VARIATION = 1 +const THROUGHPUT = 2 +const PACKET_LOSS = 3 + +const ( + stateIdle = 0 + stateInitializing = 1 + stateReady = 2 +) + +type NetChar struct { + Latency int + LatencyVariation int + LatencyCorrelation int + Throughput int + PacketLoss int +} + +type NetElem struct { + Name string + Type string + ParentName string + ScenarioName string + DomainName string + ZoneName string + Poa NetChar + EdgeFog NetChar + InterDomain NetChar + InterZone NetChar + InterEdge NetChar + InterFog NetChar + Index int + FilterInfoList []FilterInfo + Ip string + NextUniqueNumber int +} + +type FilterInfo struct { + PodName string + SrcIp string + SrcSvcIp string + SrcName string + SrcNetmask string + SrcPort int + DstPort int + UniqueNumber int //number used to link the filter and the shaping information + Latency int + LatencyVariation int + LatencyCorrelation int + PacketLoss int + DataRate int +} + +type portInfo struct { + port int32 + expPort int32 + protocol string +} + +type serviceInfo struct { + name string + node string + ports map[int32]*portInfo + mgSvc *mgServiceInfo +} + +type mgServiceInfo struct { + name string + services map[string]*serviceInfo +} + +type expServiceMap struct { + nodePort int32 + svcName string + svcPort int32 + protocol string +} + +type podInfo struct { + name string + mgSvcMap map[string]*serviceInfo + expSvcMap map[int32]*expServiceMap +} + +const typeMgSvc string = "ME-SVC" +const typeExpSvc string = "EXP-SVC" + +// Scenario service mappings +var svcInfoMap = map[string]*serviceInfo{} +var mgSvcInfoMap = map[string]*mgServiceInfo{} + +// Pod Info mapping +var podInfoMap = map[string]*podInfo{} + +var elementDistantCloudArray []NetElem +var elementEdgeArray []NetElem +var elementFogArray []NetElem +var elementUEArray []NetElem +var curNetCharList []NetElem + +var indexToNetElemMap map[int]NetElem +var netElemNameToIndexMap = map[string]int{} + +var netCharTable [][][]int + +// Scenario Name +var scenarioName string + +// Service IP map +var podIPMap = map[string]string{} +var svcIPMap = map[string]string{} + +// Flag & Counters used to indicate when TC Engine is ready to +var tcEngineState = stateIdle +var podCountReq = 0 +var podCount = 0 +var svcCountReq = 0 +var svcCount = 0 + +// Init - TC Engine initialization +func Init() (err error) { + + // Connect to Redis DB + err = DBConnect() + if err != nil { + log.Error("Failed connection to Active DB. Error: ", err) + return err + } + log.Info("Connected to Active DB") + + // Subscribe to Pub-Sub events for MEEP Controller + // NOTE: Current implementation is RedisDB Pub-Sub + err = Subscribe(channelCtrlActive, channelMgManagerLb) + if err != nil { + log.Error("Failed to subscribe to Pub/Sub events. Error: ", err) + return err + } + + // Flush any remaining TC Engine rules + DBFlush(moduleTcEngine) + + // Initialize TC Engine with current active scenario & LB rules + processActiveScenarioUpdate() + processMgSvcMapUpdate() + + return nil +} + +// Run - MEEP TC Engine execution +func Run() { + + // Listen for subscribed events. Provide event handler method. + _ = Listen(eventHandler) +} + +func eventHandler(channel string, payload string) { + // Handle Message according to Rx Channel + switch channel { + + // MEEP Ctrl Engine active scenario update Channel + case channelCtrlActive: + log.Debug("Event received on channel: ", channelCtrlActive) + processActiveScenarioUpdate() + + case channelMgManagerLb: + log.Debug("Event received on channel: ", channelMgManagerLb) + processMgSvcMapUpdate() + + default: + log.Warn("Unsupported channel") + } +} + +func processActiveScenarioUpdate() { + // Retrieve active scenario from DB + jsonScenario, err := DBJsonGetEntry(moduleCtrlEngine+":"+typeActive, ".") + if err != nil { + log.Error(err.Error()) + stopScenario() + return + } + + // Unmarshal Active scenario + var scenario ceModel.Scenario + err = json.Unmarshal([]byte(jsonScenario), &scenario) + if err != nil { + log.Error(err.Error()) + stopScenario() + return + } + + // Parse scenario + parseScenario(scenario) + + switch tcEngineState { + case stateIdle: + // Retrieve platform information: Pod ID & Service IP + getPlatformInfo() + + case stateInitializing: + log.Debug("TC Engine already initializing") + + case stateReady: + // Update Network Characteristic matrix table + refreshNetCharTable() + + // Apply network characteristic rules + applyNetCharRules() + + // Publish update to TC Sidecars for enforcement + _ = Publish(channelTcNet, "") + } +} + +func processMgSvcMapUpdate() { + // Ignore update if TC Engine is not ready + if tcEngineState != stateReady { + log.Warn("Ignoring MG Svc Map update while TC Engine not in ready state") + return + } + + // Retrieve active scenario from DB + jsonNetElemList, err := DBJsonGetEntry(moduleMgManager+":"+typeLb, ".") + if err != nil { + log.Error(err.Error()) + return + } + + // Unmarshal MG Service Maps + var netElemList mgModel.NetworkElementList + err = json.Unmarshal([]byte(jsonNetElemList), &netElemList) + if err != nil { + log.Error(err.Error()) + return + } + + // Update pod MG service mappings + for _, netElem := range netElemList.NetworkElements { + podInfo := podInfoMap[netElem.Name] + if podInfo == nil { + log.Error("Failed to find network element") + continue + } + + // Set load balanced MG Service instance + for _, svcMap := range netElem.ServiceMaps { + podInfo.mgSvcMap[svcMap.MgSvcName] = svcInfoMap[svcMap.LbSvcName] + } + } + + // Apply new MG Service mapping rules + applyMgSvcMapping() + + // Publish update to TC Sidecars for enforcement + _ = Publish(channelTcLb, "") +} + +func addPod(name string) { + if _, found := podIPMap[name]; !found && tcEngineState != stateReady { + podIPMap[name] = "" + podCountReq++ + } +} + +func addSvc(name string) { + if _, found := svcIPMap[name]; !found && tcEngineState != stateReady { + svcIPMap[name] = "" + svcCountReq++ + } +} + +// Initialize Pod informatin for matching entry +func initPodInfo(name string, ip string) { + for i := range curNetCharList { + if name == curNetCharList[i].Name { + curNetCharList[i].Ip = ip + curNetCharList[i].NextUniqueNumber = 1 + break + } + } +} + +func stopScenario() { + log.Debug("stopScenario() -- Resetting all variables") + + elementDistantCloudArray = nil + elementEdgeArray = nil + elementFogArray = nil + elementUEArray = nil + + curNetCharList = nil + indexToNetElemMap = nil + netElemNameToIndexMap = nil + netCharTable = nil + + podIPMap = map[string]string{} + svcIPMap = map[string]string{} + + svcInfoMap = map[string]*serviceInfo{} + mgSvcInfoMap = map[string]*mgServiceInfo{} + podInfoMap = map[string]*podInfo{} + + tcEngineState = stateIdle + podCountReq = 0 + podCount = 0 + svcCountReq = 0 + svcCount = 0 + + scenarioName = "" + + DBFlush(moduleTcEngine) + _ = Publish(channelTcNet, "delAll") + _ = Publish(channelTcLb, "delAll") +} + +func validateLatencyVariation(value int) int { + + if value < 0 { + value = 0 + } + return value +} + +func parseScenario(scenario ceModel.Scenario) { + log.Debug("parseScenario") + + // Store scenario Name + scenarioName = scenario.Name + + // Scenario network characteristics + interDomainLatency := int(scenario.Deployment.InterDomainLatency) + interDomainLatencyVariation := int(scenario.Deployment.InterDomainLatencyVariation) + interDomainLatencyVariation = validateLatencyVariation(interDomainLatencyVariation) + interDomainLatencyCorrelation := COMMON_CORRELATION + interDomainThroughput := THROUGHPUT_UNIT * int(scenario.Deployment.InterDomainThroughput) + // Packet loss (float) converted to hundredth & truncated + interDomainPacketLoss := int(100 * scenario.Deployment.InterDomainPacketLoss) + + // Parse Domains + for _, domain := range scenario.Deployment.Domains { + interZoneLatency := int(domain.InterZoneLatency) + interZoneLatencyVariation := int(domain.InterZoneLatencyVariation) + interZoneLatencyVariation = validateLatencyVariation(interZoneLatencyVariation) + interZoneLatencyCorrelation := COMMON_CORRELATION + interZoneThroughput := THROUGHPUT_UNIT * int(domain.InterZoneThroughput) + // Packet loss (float) converted to hundredth & truncated + interZonePacketLoss := int(100 * domain.InterZonePacketLoss) + + // Parse Zones + for _, zone := range domain.Zones { + interFogLatency := int(zone.InterFogLatency) + interFogLatencyVariation := int(zone.InterFogLatencyVariation) + interFogLatencyVariation = validateLatencyVariation(interFogLatencyVariation) + interFogLatencyCorrelation := COMMON_CORRELATION + interFogThroughput := THROUGHPUT_UNIT * int(zone.InterFogThroughput) + // Packet loss (float) converted to hundredth & truncated + interFogPacketLoss := int(100 * zone.InterFogPacketLoss) + + interEdgeLatency := int(zone.InterEdgeLatency) + interEdgeLatencyVariation := int(zone.InterEdgeLatencyVariation) + interEdgeLatencyVariation = validateLatencyVariation(interEdgeLatencyVariation) + interEdgeLatencyCorrelation := COMMON_CORRELATION + interEdgeThroughput := THROUGHPUT_UNIT * int(zone.InterEdgeThroughput) + // Packet loss (float) converted to hundredth & truncated + interEdgePacketLoss := int(100 * zone.InterEdgePacketLoss) + + edgeFogLatency := int(zone.EdgeFogLatency) + edgeFogLatencyVariation := int(zone.EdgeFogLatencyVariation) + edgeFogLatencyVariation = validateLatencyVariation(edgeFogLatencyVariation) + edgeFogLatencyCorrelation := COMMON_CORRELATION + edgeFogThroughput := THROUGHPUT_UNIT * int(zone.EdgeFogThroughput) + // Packet loss (float) converted to hundredth & truncated + edgeFogPacketLoss := int(100 * zone.EdgeFogPacketLoss) + + parentEdge := "" + var revisitFogList []*NetElem + + // Parse Network Locations + for _, nl := range zone.NetworkLocations { + poaLatency := int(nl.TerminalLinkLatency) + poaLatencyVariation := int(nl.TerminalLinkLatencyVariation) + poaLatencyVariation = validateLatencyVariation(poaLatencyVariation) + poaLatencyCorrelation := COMMON_CORRELATION + poaThroughput := THROUGHPUT_UNIT * int(nl.TerminalLinkThroughput) + // Packet loss (float) converted to hundredth & truncated + poaPacketLoss := int(100 * nl.TerminalLinkPacketLoss) + + parentFog := "" + var revisitUEList []*NetElem + + // Parse Physical locations + for _, pl := range nl.PhysicalLocations { + + // Parse Processes + for _, proc := range pl.Processes { + addPod(proc.Name) + + // Retrieve existing element or create new net element if none found + element := getElement(proc.Name) + if element == nil { + element = new(NetElem) + element.ScenarioName = scenario.Name + element.Name = proc.Name + element.NextUniqueNumber = 1 + } + + // Update element information based on current location characteristics + element.DomainName = domain.Name + element.ZoneName = zone.Name + element.Type = pl.Type_ + populateNetChar(&element.Poa, poaLatency, poaLatencyVariation, poaLatencyCorrelation, poaThroughput, poaPacketLoss) + populateNetChar(&element.InterDomain, interDomainLatency, interDomainLatencyVariation, interDomainLatencyCorrelation, interDomainThroughput, interDomainPacketLoss) + populateNetChar(&element.InterZone, interZoneLatency, interZoneLatencyVariation, interZoneLatencyCorrelation, interZoneThroughput, interZonePacketLoss) + populateNetChar(&element.InterEdge, interEdgeLatency, interEdgeLatencyVariation, interEdgeLatencyCorrelation, interEdgeThroughput, interEdgePacketLoss) + populateNetChar(&element.InterFog, interFogLatency, interFogLatencyVariation, interFogLatencyCorrelation, interFogThroughput, interFogPacketLoss) + populateNetChar(&element.EdgeFog, edgeFogLatency, edgeFogLatencyVariation, edgeFogLatencyCorrelation, edgeFogThroughput, edgeFogPacketLoss) + + switch pl.Type_ { + case "EDGE": + //keep track of edge being the parent of fogs + parentEdge = proc.Name + addElementToList(element) + case "FOG": + //keep this fog as a parent for the UEs below + parentFog = proc.Name + revisitFogList = append(revisitFogList, element) + case "UE": + revisitUEList = append(revisitUEList, element) + case "DC": + addElementToList(element) + default: + } + + // Create pod information entry and add to map + podInfo := new(podInfo) + podInfo.name = proc.Name + podInfo.mgSvcMap = make(map[string]*serviceInfo) + podInfo.expSvcMap = make(map[int32]*expServiceMap) + podInfoMap[proc.Name] = podInfo + + // Store service information from service config + if proc.ServiceConfig != nil { + addServiceInfo(proc.ServiceConfig.Name, proc.ServiceConfig.Ports, proc.ServiceConfig.MeSvcName, proc.Name) + } + + // Store service information from user chart + // Format: :[group service name]:: + if proc.UserChartLocation != "" && proc.UserChartGroup != "" { + userChartGroup := strings.Split(proc.UserChartGroup, ":") + + // Retrieve service ports + var servicePorts []ceModel.ServicePort + port, err := strconv.ParseInt(userChartGroup[2], 10, 32) + if err == nil { + var servicePort ceModel.ServicePort + servicePort.Port = int32(port) + servicePort.Protocol = userChartGroup[3] + servicePorts = append(servicePorts, servicePort) + } + + addServiceInfo(userChartGroup[0], servicePorts, userChartGroup[1], proc.Name) + } + + // Add pod-specific external service mapping, if any + if proc.IsExternal { + for _, service := range proc.ExternalConfig.IngressServiceMap { + serviceMap := new(expServiceMap) + serviceMap.nodePort = service.ExternalPort + serviceMap.svcName = service.Name + serviceMap.svcPort = service.Port + serviceMap.protocol = service.Protocol + podInfo.expSvcMap[serviceMap.nodePort] = serviceMap + } + + // TODO -- Add support for Egress Service Mapping + } + } + } + + //revisit UEs based on parent fog info, create the parent fog if none + if parentFog == "" { + // Retrieve existing element or create new net element if none found + // Create a dummy virtual parent for table calculation purpose + name := "dummy-fog-" + nl.Name //this is unique within the zone + element := getElement(name) + if element == nil { + element = new(NetElem) + element.ScenarioName = scenario.Name + element.Name = name + element.NextUniqueNumber = 1 + } + + element.DomainName = domain.Name + element.ZoneName = zone.Name + element.Type = "FOG" + + populateNetChar(&element.Poa, 0, 0, 0, MAX_THROUGHPUT, 0) + populateNetChar(&element.InterDomain, interDomainLatency, interDomainLatencyVariation, interDomainLatencyCorrelation, interDomainThroughput, interDomainPacketLoss) + populateNetChar(&element.InterZone, interZoneLatency, interZoneLatencyVariation, interZoneLatencyCorrelation, interZoneThroughput, interZonePacketLoss) + populateNetChar(&element.InterEdge, interEdgeLatency, interEdgeLatencyVariation, interEdgeLatencyCorrelation, interEdgeThroughput, interEdgePacketLoss) + populateNetChar(&element.InterFog, interFogLatency, interFogLatencyVariation, interFogLatencyCorrelation, interFogThroughput, interFogPacketLoss) + populateNetChar(&element.EdgeFog, edgeFogLatency, edgeFogLatencyVariation, edgeFogLatencyCorrelation, edgeFogThroughput, edgeFogPacketLoss) + + revisitFogList = append(revisitFogList, element) + parentFog = element.Name + } + + for _, el := range revisitUEList { + el.ParentName = parentFog + addElementToList(el) + } + } + + //revisit Fogs based on parent edge info, create the parent edge if none + if parentEdge == "" { + // Retrieve existing element or create new net element if none found + // Create a dummy virtual parent for table calculation purpose + name := "dummy-edge-" + zone.Name //this is unique within the zone + element := getElement(name) + if element == nil { + element = new(NetElem) + element.ScenarioName = scenario.Name + element.Name = name + element.NextUniqueNumber = 1 + } + + element.DomainName = domain.Name + element.ZoneName = zone.Name + //element.ParentName = nl.Name + element.Type = "EDGE" + + populateNetChar(&element.Poa, 0, 0, 0, MAX_THROUGHPUT, 0) + populateNetChar(&element.InterDomain, interDomainLatency, interDomainLatencyVariation, interDomainLatencyCorrelation, interDomainThroughput, interDomainPacketLoss) + populateNetChar(&element.InterZone, interZoneLatency, interZoneLatencyVariation, interZoneLatencyCorrelation, interZoneThroughput, interZonePacketLoss) + populateNetChar(&element.InterEdge, interEdgeLatency, interEdgeLatencyVariation, interEdgeLatencyCorrelation, interEdgeThroughput, interEdgePacketLoss) + populateNetChar(&element.InterFog, interFogLatency, interFogLatencyVariation, interFogLatencyCorrelation, interFogThroughput, interFogPacketLoss) + populateNetChar(&element.EdgeFog, 0, 0, 0, MAX_THROUGHPUT, 0) + + parentEdge = element.Name + addElementToList(element) + } + + for _, el := range revisitFogList { + el.ParentName = parentEdge + addElementToList(el) + } + } + } + + if curNetCharList == nil { + curNetCharList = append(curNetCharList, elementDistantCloudArray...) + curNetCharList = append(curNetCharList, elementEdgeArray...) + curNetCharList = append(curNetCharList, elementFogArray...) + curNetCharList = append(curNetCharList, elementUEArray...) + } +} + +// Create & store new service & MG service information +func addServiceInfo(svcName string, svcPorts []ceModel.ServicePort, mgSvcName string, nodeName string) { + // Add service instance service map + addSvc(svcName) + + // Create new service info + svcInfo := new(serviceInfo) + svcInfo.name = svcName + svcInfo.node = nodeName + svcInfo.ports = make(map[int32]*portInfo) + + // Add ports to service information + for _, port := range svcPorts { + portInfo := new(portInfo) + portInfo.port = port.Port + portInfo.expPort = port.ExternalPort + portInfo.protocol = port.Protocol + svcInfo.ports[portInfo.port] = portInfo + } + + // Store MG Service info, if any + if mgSvcName != "" { + addSvc(mgSvcName) + + // Add MG service to MG service info map if it does not exist yet + mgSvcInfo, found := mgSvcInfoMap[mgSvcName] + if !found { + mgSvcInfo = new(mgServiceInfo) + mgSvcInfo.services = make(map[string]*serviceInfo) + mgSvcInfo.name = mgSvcName + mgSvcInfoMap[mgSvcInfo.name] = mgSvcInfo + } + + // Add service instance reference to MG service list + mgSvcInfo.services[svcInfo.name] = svcInfo + + // Add MG Service reference to service instance + svcInfo.mgSvc = mgSvcInfo + } + + // Add service instance to service info map + svcInfoMap[svcInfo.name] = svcInfo +} + +func getElement(name string) *NetElem { + // Make sure net char list exists + if curNetCharList == nil { + return nil + } + + // Return element reference if found + for index, elem := range curNetCharList { + if elem.Name == name { + return &curNetCharList[index] + } + } + return nil +} + +func addElementToList(element *NetElem) { + switch element.Type { + case "FOG": + elementFogArray = append(elementFogArray, *element) + case "EDGE": + elementEdgeArray = append(elementEdgeArray, *element) + case "UE": + elementUEArray = append(elementUEArray, *element) + case "DC": + elementDistantCloudArray = append(elementDistantCloudArray, *element) + default: + } +} + +func refreshNetCharTable() { + log.Debug("refreshNetCharTable") + + indexToNetElemMap = make(map[int]NetElem) + netElemNameToIndexMap = make(map[string]int) + + arraySize := 0 + for index, element := range curNetCharList /*elementList*/ { + //adding them in order of hierarchy in a table + //the table does not exist yet.. but we assigned then an index in that table to be + element.Index = index + netElemNameToIndexMap[element.Name] = index + indexToNetElemMap[index] = element + arraySize = index + 1 + } + + //allocate a square 3d array.... even if only symetrical latencies are currently supported + netCharTable = make([][][]int, arraySize) + for i := 0; i < arraySize; i++ { + netCharTable[i] = make([][]int, arraySize) + } + for i := 0; i < arraySize; i++ { + for j := 0; j < arraySize; j++ { + netCharTable[i][j] = make([]int, 4) + } + } + + //explicit initialisation + for i := 0; i < arraySize; i++ { + for j := 0; j < arraySize; j++ { + netCharTable[i][j][LATENCY] = 0 + netCharTable[i][j][LATENCY_VARIATION] = 0 + netCharTable[i][j][THROUGHPUT] = MAX_THROUGHPUT + netCharTable[i][j][PACKET_LOSS] = 0 + } + } + + for i := 1; i < arraySize; i++ { + srcElement := indexToNetElemMap[i] + + for j := 0; j < i; j++ { + dstElement := indexToNetElemMap[j] + + //always check the current level plus one level above only... + switch srcElement.Type { + case "DC": + //dst can only be DC + duplicateValueBasedOnSource(&srcElement.InterDomain, i, j) + + case "EDGE": + if dstElement.Type == "EDGE" { + if srcElement.DomainName != dstElement.DomainName { + duplicateValueBasedOnSource(&srcElement.InterDomain, i, j) + } else { + if srcElement.ZoneName != dstElement.ZoneName { + duplicateValueBasedOnSource(&srcElement.InterZone, i, j) + } else { + duplicateValueBasedOnSource(&srcElement.InterEdge, i, j) + } + } + } else { + duplicateValueBasedOnSource(&srcElement.InterDomain, i, j) + } + + case "FOG": + if dstElement.Type == "FOG" { + if srcElement.ZoneName == dstElement.ZoneName && srcElement.DomainName == dstElement.DomainName { + duplicateValueBasedOnSource(&srcElement.InterFog, i, j) + } else { + updateValueBasedOnParent(netElemNameToIndexMap[srcElement.ParentName], &srcElement.EdgeFog, i, j) + } + } else { + updateValueBasedOnParent(netElemNameToIndexMap[srcElement.ParentName], &srcElement.EdgeFog, i, j) + } + + case "UE": + updateValueBasedOnParent(netElemNameToIndexMap[srcElement.ParentName], &srcElement.Poa, i, j) + + default: + } + } + } +} + +func duplicateValueBasedOnSource(nc *NetChar, i int, j int) { + netCharTable[i][j][LATENCY] = nc.Latency + netCharTable[j][i][LATENCY] = netCharTable[i][j][LATENCY] + netCharTable[i][j][LATENCY_VARIATION] = nc.LatencyVariation + netCharTable[j][i][LATENCY_VARIATION] = netCharTable[i][j][LATENCY_VARIATION] + + netCharTable[i][j][THROUGHPUT] = nc.Throughput + netCharTable[j][i][THROUGHPUT] = netCharTable[i][j][THROUGHPUT] + netCharTable[i][j][PACKET_LOSS] = nc.PacketLoss + netCharTable[j][i][PACKET_LOSS] = netCharTable[i][j][PACKET_LOSS] +} + +func updateValueBasedOnParent(parentIndex int, nc *NetChar, i int, j int) { + netCharTable[i][j][LATENCY] = nc.Latency + netCharTable[parentIndex][j][LATENCY] + netCharTable[j][i][LATENCY] = netCharTable[i][j][LATENCY] + netCharTable[i][j][LATENCY_VARIATION] = nc.LatencyVariation + netCharTable[parentIndex][j][LATENCY_VARIATION] + netCharTable[j][i][LATENCY_VARIATION] = netCharTable[i][j][LATENCY_VARIATION] + + //taking the min value, no max functions in golang for integers, only for float64 + if nc.Throughput < netCharTable[parentIndex][j][THROUGHPUT] { + netCharTable[i][j][THROUGHPUT] = nc.Throughput + } else { + netCharTable[i][j][THROUGHPUT] = netCharTable[parentIndex][j][THROUGHPUT] + } + netCharTable[j][i][THROUGHPUT] = netCharTable[i][j][THROUGHPUT] + + valuef := float64(netCharTable[parentIndex][j][PACKET_LOSS]) / float64(10000) // 100.00 % == 1, 10.00% == 0.1 ... etc) + valuef = float64(10000-nc.PacketLoss) * valuef + netCharTable[i][j][PACKET_LOSS] = nc.PacketLoss + int(valuef) + netCharTable[j][i][PACKET_LOSS] = netCharTable[i][j][PACKET_LOSS] +} + +func populateNetChar(nc *NetChar, latency int, latencyVariation int, latencyCorrelation int, throughput int, packetLoss int) { + nc.Latency = latency + nc.LatencyVariation = latencyVariation + nc.LatencyCorrelation = latencyCorrelation + nc.Throughput = throughput + nc.PacketLoss = packetLoss +} + +func applyNetCharRules() { + log.Debug("applyNetCharRules") + + // Loop through + for j, dstElement := range indexToNetElemMap { + + // Ignore dummy + if strings.Contains(dstElement.Name, "dummy") { + continue + } + + for i, srcElement := range indexToNetElemMap { + + if i == j { + continue + } + + if strings.Contains(srcElement.Name, "dummy") { + continue + } + + var filterInfo FilterInfo + filterInfo.PodName = dstElement.Name + filterInfo.SrcIp = srcElement.Ip + filterInfo.SrcSvcIp = svcIPMap[srcElement.Name] + filterInfo.SrcName = srcElement.Name + filterInfo.SrcNetmask = "0" + filterInfo.SrcPort = 0 + filterInfo.DstPort = 0 + filterInfo.UniqueNumber = dstElement.NextUniqueNumber + value := netCharTable[i][j][LATENCY] + valueVar := netCharTable[i][j][LATENCY_VARIATION] + filterInfo.Latency = value + filterInfo.LatencyVariation = valueVar + filterInfo.LatencyCorrelation = COMMON_CORRELATION + value = netCharTable[i][j][PACKET_LOSS] + filterInfo.PacketLoss = value + value = netCharTable[i][j][THROUGHPUT] + filterInfo.DataRate = value + needUpdate := false + needCreate := false + if dstElement.FilterInfoList == nil { + dstElement.FilterInfoList = append(dstElement.FilterInfoList, filterInfo) + needCreate = true + } else { //check to see if it exists + index := 0 + for indx, storedFilterInfo := range dstElement.FilterInfoList { + if storedFilterInfo.SrcName == filterInfo.SrcName { + //it has to be unique so check the other values + needCreate = false + if storedFilterInfo.PodName == filterInfo.PodName && + storedFilterInfo.SrcIp == filterInfo.SrcIp && + storedFilterInfo.SrcSvcIp == filterInfo.SrcSvcIp && + storedFilterInfo.SrcNetmask == filterInfo.SrcNetmask && + storedFilterInfo.SrcPort == filterInfo.SrcPort && + storedFilterInfo.Latency == filterInfo.Latency && + storedFilterInfo.LatencyVariation == filterInfo.LatencyVariation && + storedFilterInfo.LatencyCorrelation == filterInfo.LatencyCorrelation && + storedFilterInfo.PacketLoss == filterInfo.PacketLoss && + storedFilterInfo.DataRate == filterInfo.DataRate { + needUpdate = false + } else { //there is a difference... replace the old one + needUpdate = true //store the index + index = indx + } + break + } else { + needCreate = true + } + } + if needCreate { + dstElement.FilterInfoList = append(dstElement.FilterInfoList, filterInfo) + } else { + if needUpdate { + list := dstElement.FilterInfoList + _ = deleteFilterRule(&list[index]) + list[index] = filterInfo //swap + } + } + } + + if needCreate || needUpdate { + dstElement.NextUniqueNumber++ + _ = updateFilterRule(&filterInfo) + } + + indexToNetElemMap[j] = dstElement + curNetCharList[j] = dstElement + } + } +} + +func deleteFilterRule(filterInfo *FilterInfo) error { + + // Retrieve unique IFB number for rules to delete + ifbNumber := strconv.FormatInt(int64(filterInfo.UniqueNumber), 10) + + // Delete shaping rule + keyName := moduleTcEngine + ":" + typeNet + ":" + filterInfo.PodName + ":shape:" + ifbNumber + err := DBRemoveEntry(keyName) + if err != nil { + return err + } + + // Delete filter rule + keyName = moduleTcEngine + ":" + typeNet + ":" + filterInfo.PodName + ":filter:" + ifbNumber + err = DBRemoveEntry(keyName) + if err != nil { + return err + } + return nil +} + +func updateFilterRule(filterInfo *FilterInfo) error { + var err error + var keyName string + ifbNumber := strconv.FormatInt(int64(filterInfo.UniqueNumber), 10) + + // SHAPING + var m_shape = make(map[string]interface{}) + m_shape["delay"] = strconv.FormatInt(int64(filterInfo.Latency), 10) + m_shape["delayVariation"] = strconv.FormatInt(int64(filterInfo.LatencyVariation), 10) + m_shape["delayCorrelation"] = strconv.FormatInt(int64(filterInfo.LatencyCorrelation), 10) + m_shape["packetLoss"] = strconv.FormatInt(int64(filterInfo.PacketLoss), 10) + m_shape["dataRate"] = strconv.FormatInt(int64(filterInfo.DataRate), 10) + m_shape["ifb_uniqueId"] = ifbNumber + + keyName = moduleTcEngine + ":" + typeNet + ":" + filterInfo.PodName + ":shape:" + ifbNumber + err = DBSetEntry(keyName, m_shape) + if err != nil { + return err + } + + // FILTER + var m_filter = make(map[string]interface{}) + m_filter["PodName"] = filterInfo.PodName + m_filter["srcIp"] = filterInfo.SrcIp + m_filter["srcSvcIp"] = filterInfo.SrcSvcIp + m_filter["srcName"] = filterInfo.SrcName + m_filter["srcNetmask"] = filterInfo.SrcNetmask + m_filter["srcPort"] = strconv.FormatInt(int64(filterInfo.SrcPort), 10) + m_filter["dstPort"] = strconv.FormatInt(int64(filterInfo.DstPort), 10) + m_filter["ifb_uniqueId"] = ifbNumber + + keyName = moduleTcEngine + ":" + typeNet + ":" + filterInfo.PodName + ":filter:" + ifbNumber + err = DBSetEntry(keyName, m_filter) + if err != nil { + return err + } + return nil +} + +// Generate & store rules based on mapping +func applyMgSvcMapping() { + log.Debug("applyMgSvcMapping") + + keys := map[string]bool{} + + // For each pod, add MG Service LB rules & exposed services rules + for _, podInfo := range podInfoMap { + + // MG Service LB rules + for _, svcInfo := range podInfo.mgSvcMap { + + // Add one rule per port + for _, portInfo := range svcInfo.ports { + + // Populate rule fields + fields := make(map[string]interface{}) + fields["svc-type"] = typeMgSvc + fields["svc-name"] = svcInfo.mgSvc.name + fields["svc-ip"] = svcIPMap[svcInfo.mgSvc.name] + fields["svc-protocol"] = portInfo.protocol + fields["svc-port"] = portInfo.port + fields["lb-svc-name"] = svcInfo.name + fields["lb-svc-ip"] = svcIPMap[svcInfo.name] + fields["lb-svc-port"] = portInfo.port + + // Make unique key + key := moduleTcEngine + ":" + typeLb + ":" + podInfo.name + ":" + + svcInfo.mgSvc.name + ":" + strconv.Itoa(int(portInfo.port)) + keys[key] = true + + // Set rule information in DB + _ = DBSetEntry(key, fields) + } + } + + // Exposed Service rules + for _, svcMap := range podInfo.expSvcMap { + + // Get Service info from exposed service name + // Check if MG Service first + svcInfo, found := podInfo.mgSvcMap[svcMap.svcName] + if !found { + // If not found, must be unique service + svcInfo = svcInfoMap[svcMap.svcName] + } + + // Populate rule fields + fields := make(map[string]interface{}) + fields["svc-type"] = typeExpSvc + fields["svc-name"] = svcMap.svcName + fields["svc-ip"] = "0.0.0.0/0" + fields["svc-protocol"] = svcMap.protocol + fields["svc-port"] = svcMap.nodePort + fields["lb-svc-name"] = svcInfo.name + fields["lb-svc-ip"] = svcIPMap[svcInfo.name] + fields["lb-svc-port"] = svcMap.svcPort + + // Make unique key + key := moduleTcEngine + ":" + typeLb + ":" + podInfo.name + ":" + + svcMap.svcName + ":" + strconv.Itoa(int(svcMap.nodePort)) + keys[key] = true + + // Set rule information in DB + _ = DBSetEntry(key, fields) + } + } + + // Remove old DB entries + keyName := moduleTcEngine + ":" + typeLb + ":*" + err := DBForEachEntry(keyName, removeEntryHandler, &keys) + if err != nil { + log.Error("Failed to remove old entries with err: ", err) + return + } +} + +func removeEntryHandler(key string, fields map[string]string, userData interface{}) error { + keys := userData.(*map[string]bool) + + if _, found := (*keys)[key]; !found { + _ = DBRemoveEntry(key) + } + return nil +} + +func getPlatformInfo() { + log.Debug("getPlatformInfo") + + // Set TC Engine state to Initializing + log.Info("TC Engine scenario received. Moving to Initializing state.") + tcEngineState = stateInitializing + + // Start polling thread to retrieve platform information + // When all information retrieved, stop thread and move to ready state + ticker := time.NewTicker(1000 * time.Millisecond) + go func() { + for range ticker.C { + + // Stop ticker if TC engine state is no longer initializing + if tcEngineState != stateInitializing { + log.Warn("Ticker stopped due to TC Engine state no longer initializing") + ticker.Stop() + return + } + + // Connect to K8s API Server + clientset, err := connectToAPISvr() + if err != nil { + log.Error("Failed to connect with k8s API Server. Error: ", err) + return + } + + // Retrieve Pod Information if required + if podCount < podCountReq { + log.Debug("Checking for Pod IPs. podCountReq: ", podCountReq, " podCount:", podCount) + log.Info("update on the mappings(pod): ", podIPMap) + // Retrieve all pods from k8s api with scenario label + pods, err := clientset.CoreV1().Pods("").List( + metav1.ListOptions{LabelSelector: fmt.Sprintf("meepScenario=%s", scenarioName)}) + if err != nil { + log.Error("Failed to retrieve pods from k8s API Server. Error: ", err) + return + } + + // Store pod IPs + for _, pod := range pods.Items { + podName := pod.ObjectMeta.Labels["meepApp"] + podIP := pod.Status.PodIP + + if ip, found := podIPMap[podName]; found && ip == "" && podIP != "" { + log.Debug("Setting podName: ", podName, " to IP: ", podIP) + podIPMap[podName] = podIP + podCount++ + + // Initialize Pod IP + initPodInfo(podName, podIP) + } + } + } + + // Retrieve Service Information if required + if svcCount < svcCountReq { + log.Debug("Checking for Service IPs. svcCountReq: ", svcCountReq, " svcCount:", svcCount) + log.Info("update on the mappings(svc): ", svcIPMap) + + // Retrieve all services from k8s api with scenario label + services, err := clientset.CoreV1().Services("").List( + metav1.ListOptions{}) + if err != nil { + log.Error("Failed to retrieve services from k8s API Server. Error: ", err) + return + } + + // Store service IPs + for _, svc := range services.Items { + svcName := svc.ObjectMeta.Name + svcIP := svc.Spec.ClusterIP + + if ip, found := svcIPMap[svcName]; found && ip == "" && svcIP != "" { + log.Debug("Setting svcName: ", svcName, " to IP: ", svcIP) + svcIPMap[svcName] = svcIP + svcCount++ + } + } + } + + // Stop thread if all platform information has been retrieved + if podCount == podCountReq && svcCount == svcCountReq { + if tcEngineState == stateInitializing { + log.Info("TC Engine scenario data retrieved. Moving to Ready state.") + tcEngineState = stateReady + + // Refresh & apply network characteristics rules + processActiveScenarioUpdate() + + // Refresh & apply LB rules + processMgSvcMapUpdate() + } else { + log.Warn("TC Engine thread completed while not in Initializing state") + } + + // stop timer/thread + ticker.Stop() + } + } + }() +} + +func connectToAPISvr() (*kubernetes.Clientset, error) { + + // Create the in-cluster config + config, err := rest.InClusterConfig() + if err != nil { + log.Error(err) + return nil, err + } + // Create the clientset + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + log.Error(err) + return nil, err + } + return clientset, nil +} + +// func printfNetChar(nc NetChar) { +// log.Debug("latency : ", nc.Latency, "~", nc.LatencyVariation, "|", nc.LatencyCorrelation) +// log.Debug("throughput : ", nc.Throughput) +// log.Debug("packet loss: ", nc.PacketLoss) +// } +// +// func printfElement(element NetElem) { +// log.Debug("element name : ", element.Name) +// log.Debug("element index : ", element.Index) +// log.Debug("element parent name : ", element.ParentName) +// log.Debug("element zone name : ", element.ZoneName) +// log.Debug("element domain name : ", element.DomainName) +// log.Debug("element type : ", element.Type) +// log.Debug("element scenario name : ", element.ScenarioName) +// log.Debug("element poa: ") +// printfNetChar(element.Poa) +// log.Debug("element poa-edge: ") +// printfNetChar(element.EdgeFog) +// log.Debug("element inter-fog: ") +// printfNetChar(element.InterFog) +// log.Debug("element inter-edge: ") +// printfNetChar(element.InterEdge) +// log.Debug("element inter-zone: ") +// printfNetChar(element.InterZone) +// log.Debug("element inter-domain: ") +// printfNetChar(element.InterDomain) +// log.Debug("element filter size: ", len(element.FilterInfoList)) +// log.Debug("element ip: ", element.Ip) +// log.Debug("element next unique nb: ", element.NextUniqueNumber) +// } +// +// func printfFilterInfoList(filterInfoList []FilterInfo) { +// for _, filterInfo := range filterInfoList { +// printfFilterInfo(filterInfo) +// } +// } +// +// func printfFilterInfo(filterInfo FilterInfo) { +// log.Debug("***") +// log.Debug("filterInfo PodName : ", filterInfo.PodName) +// log.Debug("filterInfo srcIp : ", filterInfo.SrcIp) +// log.Debug("filterInfo srcSvcIp : ", filterInfo.SrcSvcIp) +// log.Debug("filterInfo srcName : ", filterInfo.SrcName) +// log.Debug("filterInfo srcPort : ", filterInfo.SrcPort) +// log.Debug("filterInfo dstPort : ", filterInfo.DstPort) +// log.Debug("filterInfo uniqueNumber : ", filterInfo.UniqueNumber) +// log.Debug("filterInfo latency : ", filterInfo.Latency) +// log.Debug("filterInfo latencyVariation : ", filterInfo.LatencyVariation) +// log.Debug("filterInfo latencyCorrelation : ", filterInfo.LatencyCorrelation) +// log.Debug("filterInfo packetLoss : ", filterInfo.PacketLoss) +// log.Debug("filterInfo dataRate : ", filterInfo.DataRate) +// } diff --git a/go-apps/meep-tc-engine/server/zone.go b/go-apps/meep-tc-engine/server/zone.go new file mode 100644 index 0000000000000000000000000000000000000000..3d85c6d2b9b16e037ed1ab9fa2f05ab96ca3e98e --- /dev/null +++ b/go-apps/meep-tc-engine/server/zone.go @@ -0,0 +1,61 @@ +/* + * MEEP TC controller API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Logical zone (MEC network) object +type Zone struct { + + // Unique zone ID + Id string `json:"id,omitempty"` + + // Zone name + Name string `json:"name,omitempty"` + + // Zone type + Type_ string `json:"type,omitempty"` + + // Latency in ms between fog nodes (or PoAs) within zone + InterFogLatency int32 `json:"interFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) within zone + InterFogLatencyVariation int32 `json:"interFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) within the zone + InterFogThroughput int32 `json:"interFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone + InterFogPacketLoss float64 `json:"interFogPacketLoss,omitempty"` + + // Latency in ms between edge nodes within zone + InterEdgeLatency int32 `json:"interEdgeLatency,omitempty"` + + // Latency variation in ms between edge nodes within zone + InterEdgeLatencyVariation int32 `json:"interEdgeLatencyVariation,omitempty"` + + // The limit of the traffic supported between edge nodes within the zone + InterEdgeThroughput int32 `json:"interEdgeThroughput,omitempty"` + + // Packet lost (in terms of percentage) between edge nodes within the zone + InterEdgePacketLoss float64 `json:"interEdgePacketLoss,omitempty"` + + // Latency in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatency int32 `json:"edgeFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatencyVariation int32 `json:"edgeFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogThroughput int32 `json:"edgeFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogPacketLoss float64 `json:"edgeFogPacketLoss,omitempty"` + + NetworkLocations []NetworkLocation `json:"networkLocations,omitempty"` +} diff --git a/go-apps/meep-tc-sidecar/Dockerfile b/go-apps/meep-tc-sidecar/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..a045708787bb7aa795effc72e9f0d12c9a244828 --- /dev/null +++ b/go-apps/meep-tc-sidecar/Dockerfile @@ -0,0 +1,11 @@ +# Copyright (c) 2019 +# InterDigital Communications, Inc. +# All rights reserved. +# +# The information provided herein is the proprietary and confidential +# information of InterDigital Communications, Inc. + +FROM debian:9.6-slim +RUN apt-get update && apt-get install -y iputils-ping iproute2 iptables conntrack +COPY ./meep-tc-sidecar /meep-tc-sidecar +ENTRYPOINT /meep-tc-sidecar diff --git a/go-apps/meep-tc-sidecar/db.go b/go-apps/meep-tc-sidecar/db.go new file mode 100755 index 0000000000000000000000000000000000000000..7e9221532022850f1d70b80a06a9dffef0c9cc4f --- /dev/null +++ b/go-apps/meep-tc-sidecar/db.go @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "errors" + "net" + "reflect" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-sidecar/log" + + "github.com/go-redis/redis" +) + +var dbClient *redis.Client +var dbClientStarted = false + +var pubsub *redis.PubSub + +// DBConnect - Establish connection to DB +func DBConnect() error { + if !dbClientStarted { + err := openDB() + if err != nil { + return err + } + } + return nil +} + +func openDB() error { + + db := redis.NewClient(&redis.Options{ + Addr: "meep-redis-master:6379", + Password: "", // no password set + DB: 0, // use default DB + }) + + pong, err := db.Ping().Result() + + if pong == "" { + log.Info("pong is null") + return err + } + + if err != nil { + log.Info("Redis DB not accessible") + return err + } + dbClientStarted = true + dbClient = db + return nil +} + +// DBForEachEntry - Search for matching keys and run handler for each entry +func DBForEachEntry(keyMatchStr string, entryHandler func(string, map[string]string, interface{}) error, userData interface{}) error { + var cursor uint64 + var err error + + // Process in chunks of 50 matching entries to optimize processing speed & memory + for { + var keys []string + keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() + if err != nil { + log.Debug("ERROR: ", err) + break + } + + if len(keys) > 0 { + for i := 0; i < len(keys); i++ { + fields, err := dbClient.HGetAll(keys[i]).Result() + if err != nil || fields == nil { + log.Debug("Failed to retrieve entry fields") + break + } + + // Invoke handler to process entry + err = entryHandler(keys[i], fields, userData) + if err != nil { + return err + } + } + } + + // Stop searching if cursor is back at beginning + if cursor == 0 { + break + } + } + return nil +} + +// DBEntryExists - true if entry exists; false otherwise +func DBEntryExists(key string) bool { + value := dbClient.Exists(key).Val() + return value != 0 +} + +// // DBAddEntry - Add entry to DB +// func DBAddEntry(key string, fields map[string]string) error { +// m := convertMapStrStrToMapStrInt(fields) +// _, err := dbClient.HMSet(key, m).Result() +// if err != nil { +// return err +// } +// return nil +// } + +// func convertMapStrStrToMapStrInt(src map[string]string) (dst map[string]interface{}) { +// dst = make(map[string]interface{}) +// for key, value := range src { +// dst[key] = value +// } +// return dst +// } + +// // DBRemoveEntry - Remove entry from DB +// func DBRemoveEntry(key string) error { +// _, err := dbClient.Del(key).Result() +// if err != nil { +// return err +// } +// return nil +// } + +// Subscribe - Register as a listener for provided channels +func Subscribe(channels ...string) error { + pubsub = dbClient.Subscribe(channels...) + return nil +} + +// Listen - Wait for subscribed events +func Listen(handler func(string, string)) error { + + // Make sure listener is subscribed to pubsub + if pubsub == nil { + return errors.New("Not subscribed to pubsub") + } + + // Main listening loop + for { + // Wait for subscribed channel events, or timeout + msg, err := pubsub.ReceiveTimeout(time.Second) + if err != nil { + if reflect.TypeOf(err) == reflect.TypeOf(&net.OpError{}) && + reflect.TypeOf(err.(*net.OpError).Err).String() == "*net.timeoutError" { + // Timeout, ignore and wait for next event + continue + } + } + + // Process published event + switch m := msg.(type) { + + // Process Subscription + case *redis.Subscription: + log.Info("Subscription Message: ", m.Kind, " to channel ", m.Channel, ". Total subscriptions: ", m.Count) + + // Process received Message + case *redis.Message: + log.Info("MSG on ", m.Channel, ": ", m.Payload) + handler(m.Channel, m.Payload) + } + } +} diff --git a/go-apps/meep-tc-sidecar/destination.go b/go-apps/meep-tc-sidecar/destination.go new file mode 100644 index 0000000000000000000000000000000000000000..d0104837785fb53086461dda4c933f7701912858 --- /dev/null +++ b/go-apps/meep-tc-sidecar/destination.go @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "math" + "net" + "strconv" + "strings" + "sync" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-sidecar/log" + + logrus "github.com/sirupsen/logrus" +) + +type history struct { + received int + lost int + results []time.Duration // ring, start index = .received%len + mtx sync.RWMutex +} + +type historyRx struct { + time time.Time + rcvedBytes int +} + +type destination struct { + host string + remote *net.IPAddr + remoteName string + ifbNumber string + history *history + historyRx *historyRx +} + +type stat struct { + pktSent int + pktLoss float64 + last time.Duration + best time.Duration + worst time.Duration + mean time.Duration + stddev time.Duration +} + +func (u *destination) ping(pinger *Pinger) { + rtt, err := pinger.Ping(u.remote, opts.timeout) + if err != nil { + log.Info("Pinger error: ", u.host, " ", err) + } + u.addResult(rtt, err) +} + +func (u *destination) addResult(rtt time.Duration, err error) { + s := u.history + s.mtx.Lock() + if err == nil { + s.results[s.received%len(s.results)] = rtt + s.received++ + } else { + s.lost++ + } + s.mtx.Unlock() +} + +func (u *destination) compute() (st stat) { + s := u.history + s.mtx.RLock() + defer s.mtx.RUnlock() + + if s.received == 0 { + if s.lost > 0 { + st.pktLoss = 1.0 + } + return + } + + collection := s.results[:] + st.pktSent = s.received + s.lost + size := len(s.results) + st.last = collection[(s.received-1)%size] + + // we don't yet have filled the buffer + if s.received <= size { + collection = s.results[:s.received] + size = s.received + } + + if (s.received + s.lost) > 0 { + st.pktLoss = float64(s.lost) / float64(s.received+s.lost) + } else { + st.pktLoss = 0 + } + + st.best, st.worst = collection[0], collection[0] + + total := time.Duration(0) + for _, rtt := range collection { + if rtt < st.best { + st.best = rtt + } + if rtt > st.worst { + st.worst = rtt + } + total += rtt + } + + stddevNum := float64(0) + for _, rtt := range collection { + stddevNum += math.Pow(float64(rtt-st.mean), 2) + } + if size > 0 { + st.mean = time.Duration(float64(total) / float64(size)) + st.stddev = time.Duration(math.Sqrt(stddevNum / float64(size))) + } else { + st.mean = 0 + st.stddev = 0 + } + + // avg is only of last 50 measurements as only the last 50 durations are kept + // log.Info("Measurements log for ", u.remote, " : ", st.last, ", avg: ", st.mean) + log.WithFields(logrus.Fields{ + "meep.component": "sidecar", + "meep.sidecar.latency-latest": st.last / 1000000, + "meep.sidecar.latency-avg": st.mean / 1000000, + "meep.sidecar.latency-dest": u.remoteName, + }).Info("Measurements log") + + return +} + +func (u *destination) processRxTx() { + + str := "tc -s qdisc show dev ifb" + u.ifbNumber + out, err := cmdExec(str) + if err != nil { + log.Error("tc -s qdisc show dev ifb", u.ifbNumber) + log.Error(err) + return + } + //ex :qdisc netem 1: root refcnt 2 limit 1000 delay 100.0ms 10.0ms 50% loss 50% rate 2Mbit\n Sent 756 bytes 8 pkt (dropped 4, overlimits 0 requeues 0 + allStr := strings.Split(out, " ") + + //we have to read the allStr from the back since based on the results are always at the end but the characteristic may be different (no pkt loss, no normal distribution, etc) + var rcvedPkts int + var droppedPkts int + var rcvedBytes int + if len(allStr) > 20 { + rcvedPkts, _ = strconv.Atoi(allStr[len(allStr)-15]) + droppedPkts, _ = strconv.Atoi(allStr[len(allStr)-12][:len(allStr[len(allStr)-12])-1]) + rcvedBytes, _ = strconv.Atoi(allStr[len(allStr)-17]) + } else { + log.Error("Error in the ifb statistics output: ", allStr) + rcvedPkts = 0 + droppedPkts = 0 + rcvedBytes = 0 + } + + //dropped rate in % + var pktDroppedRate float64 + pktDroppedRateStr := "0" + + totalPkts := rcvedPkts + droppedPkts + if totalPkts > 0 { + top := droppedPkts * 100 + pktDroppedRate = (float64(top)) / float64(totalPkts) + pktDroppedRateStr = strconv.FormatFloat(pktDroppedRate, 'f', 3, 64) + } + + currentTime := time.Now() + + previousRcvedBytes := u.historyRx.rcvedBytes + + var throughput float64 + if previousRcvedBytes != 0 { + + previousTime := u.historyRx.time + + diff := currentTime.Sub(previousTime) + throughput = 8 * (float64(rcvedBytes) - float64(previousRcvedBytes)) / diff.Seconds() + } + + var throughputStr, throughputVal string + /* + if throughput > 1000 { + if throughput > 1000000 { + throughputVal = strconv.FormatFloat(throughput/1000000, 'f', 3, 64) + throughputStr = throughputVal + " Mbps" + } else { + throughputVal = strconv.FormatFloat(throughput/1000, 'f', 3, 64) + throughputStr = throughputVal + " Kbps" + } + } else { + throughputVal = strconv.FormatFloat(throughput, 'f', 3, 64) + throughputStr = throughputVal + " bps" + } + */ + //all the throughput in Mbps + throughputVal = strconv.FormatFloat(throughput/1000000, 'f', 3, 64) + throughputStr = throughputVal + " Mbps" + + u.historyRx.time = currentTime + u.historyRx.rcvedBytes = rcvedBytes + + log.WithFields(logrus.Fields{ + "meep.component": "sidecar", + "meep.sidecar.pod-dest": u.remoteName, + "meep.sidecar.rx": rcvedPkts, + "meep.sidecar.rxd": droppedPkts, + "meep.sidecar.rxBytes": rcvedBytes, + "meep.sidecar.throughput": throughput / 1000000, //converting bps to mbps for graph display + "meep.sidecar.throughputStr": throughputStr, + "meep.sidecar.packet-loss": pktDroppedRateStr, + }).Info("Measurements log") + +} diff --git a/go-apps/meep-tc-sidecar/error.go b/go-apps/meep-tc-sidecar/error.go new file mode 100644 index 0000000000000000000000000000000000000000..ed6227f0ab55e4d72fc803551814f5821696eedc --- /dev/null +++ b/go-apps/meep-tc-sidecar/error.go @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import "errors" + +var ( + errClosed = errors.New("pinger closed") + errNotBound = errors.New("need at least one bind address") +) + +// timeoutError implements the net.Error interface. Originally taken from +// https://github.com/golang/go/blob/release-branch.go1.8/src/net/net.go#L505-L509 +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } diff --git a/go-apps/meep-tc-sidecar/go.mod b/go-apps/meep-tc-sidecar/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..5b0b42c3c610f6bfa21a6ca8dc22f045835ccbfb --- /dev/null +++ b/go-apps/meep-tc-sidecar/go.mod @@ -0,0 +1,25 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-sidecar + +go 1.12 + +require ( + github.com/coreos/go-iptables v0.4.0 + github.com/go-redis/redis v6.15.2+incompatible + github.com/gogo/protobuf v1.2.1 // indirect + github.com/google/gofuzz v1.0.0 // indirect + github.com/json-iterator/go v1.1.6 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/onsi/ginkgo v1.8.0 // indirect + github.com/onsi/gomega v1.5.0 // indirect + github.com/sirupsen/logrus v1.4.1 + github.com/spf13/pflag v1.0.3 // indirect + golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 + gopkg.in/inf.v0 v0.9.1 // indirect + k8s.io/api v0.0.0-20181204000039-89a74a8d264d // indirect + k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 // indirect + k8s.io/klog v0.0.0-20181108234604-8139d8cb77af // indirect + k8s.io/kubernetes v1.13.4 + k8s.io/utils v0.0.0-20190221042446-c2654d5206da + sigs.k8s.io/yaml v1.1.0 // indirect +) diff --git a/go-apps/meep-tc-sidecar/go.sum b/go-apps/meep-tc-sidecar/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..f109f8b4ec513703419d7b90d6c2f46d0938e157 --- /dev/null +++ b/go-apps/meep-tc-sidecar/go.sum @@ -0,0 +1,75 @@ +github.com/coreos/go-iptables v0.4.0 h1:wh4UbVs8DhLUbpyq97GLJDKrQMjEDD63T1xE4CrsKzQ= +github.com/coreos/go-iptables v0.4.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +k8s.io/api v0.0.0-20181204000039-89a74a8d264d h1:HQoGWsWUe/FmRcX9BU440AAMnzBFEf+DBo4nbkQlNzs= +k8s.io/api v0.0.0-20181204000039-89a74a8d264d/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93 h1:tT6oQBi0qwLbbZSfDkdIsb23EwaLY85hoAV4SpXfdao= +k8s.io/apimachinery v0.0.0-20181127025237-2b1284ed4c93/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/klog v0.0.0-20181108234604-8139d8cb77af h1:s6rm8OxBbyDNSRkpyAd5OL4icUdBICVw9+mFADa+t5E= +k8s.io/klog v0.0.0-20181108234604-8139d8cb77af/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/kubernetes v1.13.4 h1:gQqFv/pH8hlbznLXQUsi8s5zqYnv0slmUDl/yVA0EWc= +k8s.io/kubernetes v1.13.4/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4= +k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/go-apps/meep-tc-sidecar/log/meeplog.go b/go-apps/meep-tc-sidecar/log/meeplog.go new file mode 100644 index 0000000000000000000000000000000000000000..257226e881240fc4dd0b911f52baf24b90e18aad --- /dev/null +++ b/go-apps/meep-tc-sidecar/log/meeplog.go @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package logmain + +import ( + log "github.com/sirupsen/logrus" +) + +func MeepJSONLogInit() { + log.SetFormatter(&log.JSONFormatter{}) + log.SetLevel(log.DebugLevel) +} + +func Info(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "sidecar", + }).Info(args...) +} + +func Debug(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "sidecar", + }).Debug(args...) +} + +func Warn(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "sidecar", + }).Warn(args...) +} + +func Error(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "sidecar", + }).Error(args...) +} + +func Panic(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "sidecar", + }).Panic(args...) +} + +func Fatal(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "sidecar", + }).Fatal(args...) +} + +func WithFields(fields log.Fields) *log.Entry { + return log.WithFields(fields) +} diff --git a/go-apps/meep-tc-sidecar/main.go b/go-apps/meep-tc-sidecar/main.go new file mode 100644 index 0000000000000000000000000000000000000000..e8c9251807c849525f65c817a77a0d8c3a727e06 --- /dev/null +++ b/go-apps/meep-tc-sidecar/main.go @@ -0,0 +1,781 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "bytes" + "errors" + "math/rand" + "os" + "os/exec" + "strings" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-sidecar/log" + + ipt "github.com/coreos/go-iptables/iptables" + k8s_ct "k8s.io/kubernetes/pkg/util/conntrack" + k8s_exec "k8s.io/utils/exec" +) + +const moduleTcEngine string = "tc-engine" +const typeNet string = "net" +const typeLb string = "lb" +const typeMeSvc string = "ME-SVC" +const typeExpSvc string = "EXP-SVC" + +const channelTcNet string = moduleTcEngine + "-" + typeNet +const channelTcLb string = moduleTcEngine + "-" + typeLb + +const meepPrefix string = "MEEP-" +const exposedPrefix string = "EXP-" +const mePrefix string = "ME-" +const svcPrefix string = "SVC-" +const meSvcChain string = meepPrefix + mePrefix + "SERVICES" +const expSvcChain string = meepPrefix + exposedPrefix + "SERVICES" +const maxChainLen int = 25 +const capLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +const dbMaxRetryCount = 5 + +type podShortElement struct { + name string + ipAddr string + IfbNumber string +} + +var sem = make(chan int, 1) + +var opts = struct { + timeout time.Duration + interval time.Duration + payloadSize uint + statBufferSize uint + bind4 string + bind6 string + dests []*destination + resolverTimeout time.Duration +}{ + timeout: 100000 * time.Millisecond, + interval: 1000 * time.Millisecond, + bind4: "0.0.0.0", + bind6: "::", + payloadSize: 56, + statBufferSize: 50, + resolverTimeout: 15000 * time.Millisecond, +} + +var pinger *Pinger +var podName string +var ipTbl *ipt.IPTables + +var letters = []rune(capLetters) +var serviceChains = map[string]string{} +var ifbs = map[string]string{} +var filters = map[string]string{} + +var measurementsRunning = false +var flushRequired = false + +// Run - MEEP Sidecar execution +func main() { + // Initialize MEEP Sidecar + err := initMeepSidecar() + if err != nil { + log.Error("Failed to initialize MEEP Sidecar") + return + } + log.Info("Successfully initialized MEEP Sidecar") + + // Refresh TC rules to match DB state + refreshNetCharRules() + + // Refresh LB IPtables rules to match DB state + refreshLbRules() + + // Listen for subscribed events. Provide event handler method. + _ = Listen(eventHandler) +} + +// initMeepSidecar - MEEP Sidecar initialization +func initMeepSidecar() error { + var err error + + // Log as JSON instead of the default ASCII formatter. + log.MeepJSONLogInit() + + // Seed random using current time + rand.Seed(time.Now().UnixNano()) + + // Initialize global variables + + // Retrieve Environment variables + podName = strings.TrimSpace(os.Getenv("MEEP_POD_NAME")) + if podName == "" { + log.Error("MEEP_POD_NAME not set. Exiting.") + return errors.New("MEEP_POD_NAME not set") + } + log.Info("MEEP_POD_NAME: ", podName) + + // Create IPtables client + ipTbl, err = ipt.New() + if err != nil { + log.Error("Failed to create new IPTables. Error: ", err) + return err + } + log.Info("Successfully created new IPTables client") + + // Connect to Redis DB + for retry := 0; retry <= dbMaxRetryCount; retry++ { + err = DBConnect() + if err != nil { + log.Warn("Failed to connect to DB. Retrying... Error: ", err) + continue + } + } + if err != nil { + log.Error("Failed to connect to DB. Error: ", err) + return err + } + log.Info("Successfully connected to DB") + + // Subscribe to Pub-Sub events for MEEP TC & LB + // NOTE: Current implementation is RedisDB Pub-Sub + err = Subscribe(channelTcNet, channelTcLb) + if err != nil { + log.Error("Failed to subscribe to Pub/Sub events. Error: ", err) + return err + } + log.Info("Successfully subscribed to Pub/Sub events") + + return nil +} + +func eventHandler(channel string, payload string) { + // Handle Message according to Rx Channel + switch channel { + + // MEEP TC Network Characteristic Channel + case channelTcNet: + processNetCharMsg(payload) + + // MEEP TC LB Channel + case channelTcLb: + processLbMsg(payload) + + default: + log.Warn("Unsupported channel") + } +} + +func processNetCharMsg(payload string) { + // NOTE: Payload contains no information yet. For now reevaluate Net Char rules on every received event. + refreshNetCharRules() +} + +func processLbMsg(payload string) { + // NOTE: Payload contains no information yet. For now reevaluate LB rules on every received event. + refreshLbRules() +} + +func refreshNetCharRules() { + // Create shape rules + _ = createIfbs() + + // Flush filters + flushFilters() + + // Create new filters (lower priority than the old one) + _ = createFilters() + + // // Delete unused filters + // deleteUnusedFilters() + + // Delete unused ifbs + deleteUnusedIfbs() + + // Start measurements + startMeasurementThreads() +} + +func refreshLbRules() { + // Get currently installed chains in NAT table + log.Debug("Fetching nat table chains") + chains, err := ipTbl.ListChains("nat") + if err != nil { + log.Error("Failed to retrieve iptables chains. Error: ", err) + return + } + + // Create MAP of currently installed MEEP iptables chains + chainMap := make(map[string]bool) + for _, chain := range chains { + if strings.Contains(chain, "MEEP-") { + chainMap[chain] = true + } + } + + // Reapply masquerading rule if not present + err = ipTbl.AppendUnique("nat", "POSTROUTING", "-o", "eth0", "-j", "MASQUERADE") + if err != nil { + log.Error("Failed to set rule [-A POSTROUTING -o eth0 -j MASQUERADE]. Error: ", err) + return + } + + // Create top-level MEEP service chains if not present + // MEEP-ME-SERVICES + _, exists := chainMap[meSvcChain] + if !exists { + log.Debug("Creating MEEP chain MEEP-ME-SERVICES") + err = ipTbl.NewChain("nat", meSvcChain) + if err != nil { + log.Error("Failed to create chain. Error: ", err) + return + } + } + delete(chainMap, meSvcChain) + + // MEEP-EXP-SERVICES + _, exists = chainMap[expSvcChain] + if !exists { + log.Debug("Creating MEEP chain MEEP-EXP-SERVICES") + err = ipTbl.NewChain("nat", expSvcChain) + if err != nil { + log.Error("Failed to create chain. Error: ", err) + return + } + } + delete(chainMap, expSvcChain) + + // Reapply top-level routing rules if not present + err = ipTbl.AppendUnique("nat", "OUTPUT", "-j", meSvcChain) + if err != nil { + log.Error("Failed to set rule [-A OUTPUT -j "+meSvcChain+"]. Error: ", err) + return + } + err = ipTbl.AppendUnique("nat", "PREROUTING", "-j", expSvcChain) + if err != nil { + log.Error("Failed to set rule [-A PREROUTING -j "+expSvcChain+"]. Error: ", err) + return + } + + // Apply pod-specific LB rules stored in DB + flushRequired = false + keyName := moduleTcEngine + ":" + typeLb + ":" + podName + ":*" + err = DBForEachEntry(keyName, refreshLbRulesHandler, &chainMap) + if err != nil { + log.Error("Failed to search and process pod-specific MEEP LB rules. Error: ", err) + return + } + + // Remove current chains that are no longer in LB DB + for chain := range chainMap { + // Remove reference to chain + var parentChain string + + if strings.Contains(chain, exposedPrefix) { + parentChain = expSvcChain + } else { + parentChain = meSvcChain + } + err = ipTbl.Delete("nat", parentChain, "-j", chain) + if err != nil { + log.Error("Failed to remove reference to chain ", chain, ". Error: ", err) + return + } + + // Empty chain + err = ipTbl.ClearChain("nat", chain) + if err != nil { + log.Error("Failed to remove rules from chain ", chain, ". Error: ", err) + return + } + + // Remove chain + err = ipTbl.DeleteChain("nat", chain) + if err != nil { + log.Error("Failed to remove chain ", chain, ". Error: ", err) + return + } + } + + // Flush tracked connections to make sure new LB rules are hit + if flushRequired { + flushTrackedConnections() + } +} + +func flushTrackedConnections() { + exec := k8s_exec.New() + if k8s_ct.Exists(exec) { + _ = k8s_ct.Exec(exec, "-F") + } + flushRequired = false +} + +func refreshLbRulesHandler(key string, fields map[string]string, userData interface{}) error { + var err error + var parentChain string + var serviceChain string + var servicePrefix string + var service string + var args []string + + // Retrieve currently installed chain map fron user data + chainMap := userData.(*map[string]bool) + + // Set parent chain and service chain prefix based on service exposure and type + switch fields["svc-type"] { + case typeExpSvc: + parentChain = expSvcChain + servicePrefix = meepPrefix + exposedPrefix + svcPrefix + case typeMeSvc: + parentChain = meSvcChain + servicePrefix = meepPrefix + mePrefix + svcPrefix + default: + log.Error("Unsupported service type: ", fields["svc-type"]) + return errors.New("Unsupported service type") + } + + service = servicePrefix + strings.ToUpper(fields["svc-name"]) + "-" + fields["svc-port"] + args = append(args, "-p", fields["svc-protocol"], "-d", fields["svc-ip"], "--dport", fields["svc-port"], + "-j", "DNAT", "--to-destination", fields["lb-svc-ip"]+":"+fields["lb-svc-port"], + "-m", "comment", "--comment", service) + + // Retrieve service chain name if service exists + serviceChain, exists := serviceChains[service] + if exists { + + // Check if chain exists + _, exists = (*chainMap)[serviceChain] + if exists { + + // Check if rule requires update + exists, err = ipTbl.Exists("nat", serviceChain, args...) + if err != nil { + log.Error("Failed to check if rule exists. Error: ", err) + return err + } + + // No update required. Remove chain from chain map and return. + if exists { + delete(*chainMap, serviceChain) + return nil + } + } + } + + // Create new service chain name + // NOTE: Required to guarantee chain names less than 30 characters (iptables limit) + log.Debug("Creating new service chain mapping for service: ", service) + serviceChain = servicePrefix + randSeq(maxChainLen-len(servicePrefix)) + serviceChains[service] = serviceChain + + // Create MEEP service chain + log.Debug("Creating MEEP chain ", serviceChain) + err = ipTbl.NewChain("nat", serviceChain) + if err != nil { + log.Error("Failed to create chain. Error: ", err) + return err + } + + // Create service routing rules + err = ipTbl.AppendUnique("nat", parentChain, "-j", serviceChain) + if err != nil { + log.Error("Failed to set rule [-A ", parentChain, " -j ", serviceChain, "]. Error: ", err) + return err + } + err = ipTbl.AppendUnique("nat", serviceChain, args...) + if err != nil { + log.Error("Failed to set rule [-A ", parentChain, " -j ", serviceChain, " ", args, "]. Error: ", err) + return err + } + + flushRequired = true + return nil +} + +func startMeasurementThreads() { + // Only start measurements if not already running + if len(ifbs) != 0 && !measurementsRunning { + // Populate opts.dests used by all + callPing() + go workLatency() + go workRxTxPackets() + measurementsRunning = true + } +} + +func callPing() { + podsToPing, _ := createPing() + + for _, pod := range podsToPing { + remotes, err := resolve(pod.ipAddr, opts.resolverTimeout) + if err != nil { + log.Debug("error resolving host ", pod.name, "(", pod.ipAddr, ") err: ", err) + continue + } + + for _, remote := range remotes { + if v4 := remote.IP.To4() != nil; v4 && opts.bind4 == "" || !v4 && opts.bind6 == "" { + continue + } + + ipaddr := remote // need to create a copy + name := pod.name + dst := destination{ + host: pod.ipAddr, + remote: &ipaddr, + remoteName: name, + ifbNumber: pod.IfbNumber, + history: &history{ + results: make([]time.Duration, opts.statBufferSize), + }, + historyRx: &historyRx{ + rcvedBytes: 0, + }, + } + + opts.dests = append(opts.dests, &dst) + } + } + + //get a pinger instance + if instance, err := New(opts.bind4, opts.bind6); err == nil { + if instance.PayloadSize() != uint16(opts.payloadSize) { + instance.SetPayloadSize(uint16(opts.payloadSize)) + } + pinger = instance + //defer pinger.Close() + } else { + panic(err) + } +} + +func workLatency() { + for { + for i, u := range opts.dests { + //starting 2 threads, one for the pings, one for the computing part + go func(u *destination, i int) { + u.ping(pinger) + }(u, i) + go func(u *destination, i int) { + u.compute() + }(u, i) + } + + time.Sleep(opts.interval) + } +} + +func workRxTxPackets() { + for { + //only this one affects the destinations based on info in the DB + + sem <- 1 + + for i, u := range opts.dests { + //starting 1 thread for getting the rx-tx info and computing the appropriate metrics + go func(u *destination, i int) { + u.processRxTx() + }(u, i) + } + <-sem + + time.Sleep(opts.interval) + } +} + +func createPing() ([]podShortElement, error) { + var podsToPing []podShortElement + keyName := moduleTcEngine + ":" + typeNet + ":" + podName + ":filter*" + err := DBForEachEntry(keyName, createPingHandler, &podsToPing) + if err != nil { + return nil, err + } + return podsToPing, nil +} + +func createPingHandler(key string, fields map[string]string, userData interface{}) error { + podsToPing := userData.(*[]podShortElement) + var pod podShortElement + pod.name = fields["srcName"] + pod.ipAddr = fields["srcIp"] + pod.IfbNumber = fields["ifb_uniqueId"] + + *podsToPing = append(*podsToPing, pod) + + return nil +} + +func createIfbs() error { + keyName := moduleTcEngine + ":" + typeNet + ":" + podName + ":shape*" + err := DBForEachEntry(keyName, createIfbsHandler, nil) + if err != nil { + return err + } + return nil +} + +func createIfbsHandler(key string, fields map[string]string, userData interface{}) error { + ifbNumber := fields["ifb_uniqueId"] + + if ifbs[ifbNumber] == "" { + // Update the rule + err := cmdCreateIfb(fields) + if err != nil { + return err + } + + err = cmdSetIfb(fields) + if err != nil { + return err + } + ifbs[ifbNumber] = ifbNumber + } + + return nil +} + +func flushFilters() { + + // NOTE: Flush does not work on kernel version 4.4 + // Workaround is to manually remove all installed filters + + // err := cmdDeleteAllFilters() + // if err != nil { + // return err + // } + // return nil + + for _, ifbNumber := range filters { + _ = cmdDeleteFilter(ifbNumber) + } + filters = map[string]string{} +} + +func createFilters() error { + keyName := moduleTcEngine + ":" + typeNet + ":" + podName + ":filter*" + err := DBForEachEntry(keyName, createFiltersHandler, nil) + if err != nil { + return err + } + return nil +} + +func createFiltersHandler(key string, fields map[string]string, userData interface{}) error { + ifbNumber := fields["ifb_uniqueId"] + + // if filters[ifbNumber] == "" { + ipSrc := fields["srcIp"] + ipSvcSrc := fields["srcSvcIp"] + srcName := fields["srcName"] + + err := cmdCreateFilter(ifbNumber, ipSrc) + if err != nil { + return err + } + + if ipSvcSrc != "" { + err := cmdCreateFilter(ifbNumber, ipSvcSrc) + if err != nil { + return err + } + } + + filters[ifbNumber] = ifbNumber + + // Loop through dests to update them + for _, u := range opts.dests { + if u.remoteName == srcName { + sem <- 1 + u.ifbNumber = ifbNumber + <-sem + break + } + } + // } + + return nil +} + +// func deleteUnusedFilters() error { +// for index, ifbNumber := range filters { +// keyName := moduleTcEngine + ":" + typeNet + ":" + podName + ":filter:" + ifbNumber +// if DBEntryExists(keyName) == false { +// log.Debug("filter removed: ", ifbNumber) +// // Remove old filter +// cmdDeleteFilter(ifbNumber) +// delete(filters, index) +// } +// } +// return nil +// } + +func deleteUnusedIfbs() { + for index, ifbNumber := range ifbs { + keyName := moduleTcEngine + ":" + typeNet + ":" + podName + ":shape:" + ifbNumber + if !DBEntryExists(keyName) { + log.Debug("ifb removed: ", ifbNumber) + // Remove associated Ifb + _ = cmdDeleteIfb(ifbNumber) + delete(ifbs, index) + } + } +} + +func cmdExec(cli string) (string, error) { + parts := strings.Fields(cli) + head := parts[0] + parts = parts[1:] + + cmd := exec.Command(head, parts...) + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() // will wait for command to return + if err != nil { + log.Info("ignoring error in exec command: ", err, " for command: ", cli) + //we do not return an error, otherwise it will reset the pod + //an error occur if you try to crete over something that is pre-existing, which should not be an error as it is possible + // return err + } + + return out.String(), nil +} + +func cmdCreateIfb(shape map[string]string) error { + ifbNumber := shape["ifb_uniqueId"] + _, err := cmdExec("tc qdisc replace dev eth0 root handle 1: netem") + if err != nil { + return err + } + + //"ip link add $ifb$ifbnumber type ifb" + str := "ip link add ifb" + ifbNumber + " type ifb" + _, err = cmdExec(str) + if err != nil { + log.Info("ERROR ifb" + ifbNumber + " already exist in sidecar") + return err + } + + //"ip link set $ifb$ifbnumber up" + str = "ip link set ifb" + ifbNumber + " up" + _, err = cmdExec(str) + if err != nil { + return err + } + + //"tc qdisc replace dev $ifb$ifbnumber handle 1:0 root netem" + str = "tc qdisc replace dev ifb" + ifbNumber + " handle 1:0 root netem" + _, err = cmdExec(str) + if err != nil { + return err + } + + return nil +} + +func cmdSetIfb(shape map[string]string) error { + ifbNumber := shape["ifb_uniqueId"] + delay := shape["delay"] + delayVariation := shape["delayVariation"] + delayCorrelation := shape["delayCorrelation"] + loss := shape["packetLoss"] + var lossInteger string + var lossFraction string + + if len(loss) > 2 { + lossInteger = loss[0 : len(loss)-2] + lossFraction = loss[len(loss)-2:] + } else if len(loss) > 0 { + // length is 1 or 2 + lossInteger = "0" + lossFraction = loss + } else { + lossInteger = "0" + lossFraction = "00" + } + + dataRate := shape["dataRate"] + + //tc qdisc change dev $ifb$ifbnumber handle 1:0 root netem delay $delay$ms loss $loss$prcent + normalDistributionStr := "" + if delayVariation != "0" { + normalDistributionStr = "distribution normal" + } + str := "tc qdisc change dev ifb" + ifbNumber + " handle 1:0 root netem delay " + delay + "ms " + delayVariation + "ms " + delayCorrelation + "% " + normalDistributionStr + " loss " + lossInteger + "." + lossFraction + "% rate " + dataRate + "bit" + _, err := cmdExec(str) + if err != nil { + return err + } + + return nil +} + +func cmdDeleteIfb(ifbNumber string) error { + //"ip link delete ifb$ifbNumber" + str := "ip link delete ifb" + ifbNumber + _, err := cmdExec(str) + if err != nil { + return err + } + return nil +} + +// func cmdDeleteAllFilters() error { +// str := "tc filter del dev eth0 parent ffff:" +// _, err := cmdExec(str) +// if err != nil { +// return err +// } +// return nil +// } + +func cmdDeleteFilter(ifbNumber string) error { + //tc filter del dev eth0 parent ffff: pref $ifbNumber + str := "tc filter del dev eth0 parent ffff: pref " + ifbNumber + _, err := cmdExec(str) + if err != nil { + return err + } + return nil +} + +func cmdCreateFilter(ifbNumber string, ipSrc string) error { + + _, err := cmdExec("tc qdisc replace dev eth0 root handle 1: netem") + if err != nil { + return err + } + + _, err = cmdExec("tc qdisc replace dev eth0 handle ffff: ingress") + if err != nil { + return err + } + + //"tc filter add dev eth0 parent ffff: protocol ip prio $ifbNumber u32 match ip src $ipsrc match u32 0 0 action mirred egress redirect dev $ifb$ifbnumber" + str := "tc filter add dev eth0 parent ffff: protocol ip prio " + ifbNumber + " u32 match ip src " + ipSrc + " match u32 0 0 action mirred egress redirect dev ifb" + ifbNumber + + //fonction must be a replace... a replace Adds if not there or replace if existing + //"tc filter replace dev eth0 parent ffff: protocol ip prio $ifbNumber u32 match ip src $ipsrc match u32 0 0 action mirred egress redirect dev $ifb$ifbnumber" + //str := "tc filter replace dev eth0 parent ffff: protocol ip prio " + ifbNumber + " handle 800::800 u32 match u32 0 0 action mirred egress redirect dev ifb" + ifbNumber + _, err = cmdExec(str) + if err != nil { + return err + } + + return nil +} + +func randSeq(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/go-apps/meep-tc-sidecar/payload.go b/go-apps/meep-tc-sidecar/payload.go new file mode 100644 index 0000000000000000000000000000000000000000..ec066613404100e2098a0dda1d965606e620c30a --- /dev/null +++ b/go-apps/meep-tc-sidecar/payload.go @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "math/rand" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-sidecar/log" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// Payload represents additional data appended to outgoing ICMP Echo +// Requests. +type Payload []byte + +// Resize will assign a new payload of the given size to p. +func (p *Payload) Resize(size uint16) { + buf := make([]byte, size) + if _, err := rand.Read(buf); err != nil { + log.Error("error resizing payload: ", err) + return + } + *p = Payload(buf) +} diff --git a/go-apps/meep-tc-sidecar/pinger.go b/go-apps/meep-tc-sidecar/pinger.go new file mode 100644 index 0000000000000000000000000000000000000000..5546d856c789e133941b7e9c92f604cea8895135 --- /dev/null +++ b/go-apps/meep-tc-sidecar/pinger.go @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "os" + "sync" + + "golang.org/x/net/icmp" +) + +const ( + // ProtocolICMP is the number of the Internet Control Message Protocol + // (see golang.org/x/net/internal/iana.ProtocolICMP) + ProtocolICMP = 1 + + // ProtocolICMPv6 is the IPv6 Next Header value for ICMPv6 + // see golang.org/x/net/internal/iana.ProtocolIPv6ICMP + ProtocolICMPv6 = 58 +) + +// sequence number for this process +var sequence uint32 + +// Pinger is a instance for ICMP echo requests +type Pinger struct { + LogUnexpectedPackets bool // increases log verbosity + + payload Payload + payloadMu sync.RWMutex + + requests map[uint16]request // currently running requests + mtx sync.RWMutex // lock for the requests map + id uint16 + conn4 *icmp.PacketConn + conn6 *icmp.PacketConn + write4 sync.Mutex // lock for conn4.WriteTo + write6 sync.Mutex // lock for conn6.WriteTo + wg sync.WaitGroup +} + +// New creates a new Pinger. This will open the raw socket and start the +// receiving logic. You'll need to call Close() to cleanup. +func New(bind4, bind6 string) (*Pinger, error) { + // open sockets + conn4, err := connectICMP("ip4:icmp", bind4) + if err != nil { + return nil, err + } + + conn6, err := connectICMP("ip6:ipv6-icmp", bind6) + if err != nil { + if conn4 != nil { + conn4.Close() + } + return nil, err + } + + if conn4 == nil && conn6 == nil { + return nil, errNotBound + } + pinger := Pinger{ + conn4: conn4, + conn6: conn6, + id: uint16(os.Getpid()), + requests: make(map[uint16]request), + } + pinger.SetPayloadSize(56) + + if conn4 != nil { + pinger.wg.Add(1) + go pinger.receiver(ProtocolICMP, pinger.conn4) + } + if conn6 != nil { + pinger.wg.Add(1) + go pinger.receiver(ProtocolICMPv6, pinger.conn6) + } + + return &pinger, nil +} + +// Close will close the ICMP socket. +func (pinger *Pinger) Close() { + pinger.close(pinger.conn4) + pinger.close(pinger.conn6) + pinger.wg.Wait() +} + +// connectICMP opens a new ICMP connection, if network and address are not empty. +func connectICMP(network, address string) (*icmp.PacketConn, error) { + if network == "" || address == "" { + return nil, nil + } + return icmp.ListenPacket(network, address) +} + +func (pinger *Pinger) close(conn *icmp.PacketConn) { + if conn != nil { + conn.Close() + } +} + +func (pinger *Pinger) removeRequest(seq uint16) { + pinger.mtx.Lock() + delete(pinger.requests, seq) + pinger.mtx.Unlock() +} + +// SetPayloadSize resizes additional payload data to the given size. The +// payload will subsequently be appended to outgoing ICMP Echo Requests. +// +// The default payload size is 56, resulting in 64 bytes for the ICMP packet. +func (pinger *Pinger) SetPayloadSize(size uint16) { + pinger.payloadMu.Lock() + pinger.payload.Resize(size) + pinger.payloadMu.Unlock() +} + +// SetPayload allows you to overwrite the current payload with your own data. +func (pinger *Pinger) SetPayload(data []byte) { + pinger.payloadMu.Lock() + pinger.payload = Payload(data) + pinger.payloadMu.Unlock() +} + +// PayloadSize retrieves the current payload size. +func (pinger *Pinger) PayloadSize() uint16 { + pinger.payloadMu.RLock() + defer pinger.payloadMu.RUnlock() + return uint16(len(pinger.payload)) +} diff --git a/go-apps/meep-tc-sidecar/receiving.go b/go-apps/meep-tc-sidecar/receiving.go new file mode 100644 index 0000000000000000000000000000000000000000..fa7fad7eaeb363fc5e21a6975a1d5b71a074d1cf --- /dev/null +++ b/go-apps/meep-tc-sidecar/receiving.go @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "fmt" + "net" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-tc-sidecar/log" + + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" + "golang.org/x/net/ipv6" +) + +// receiver listens on the raw socket and correlates ICMP Echo Replys with +// currently running requests. +func (pinger *Pinger) receiver(proto int, conn *icmp.PacketConn) { + rb := make([]byte, 1500) + + // read incoming packets + for { + if n, source, err := conn.ReadFrom(rb); err != nil { + if netErr, ok := err.(net.Error); !ok || !netErr.Temporary() { + break // socket gone + } + } else { + pinger.receive(proto, rb[:n], source.(*net.IPAddr).IP, time.Now()) + } + } + + // close running requests + pinger.mtx.RLock() + for _, req := range pinger.requests { + req.handleReply(errClosed, nil, nil) + } + pinger.mtx.RUnlock() + + // Close() waits for us + pinger.wg.Done() +} + +// receive takes the raw message and tries to evaluate an ICMP response. +// If that succeeds, the body will given to process() for further processing. +func (pinger *Pinger) receive(proto int, bytes []byte, addr net.IP, t time.Time) { + // parse message + m, err := icmp.ParseMessage(proto, bytes) + if err != nil { + return + } + + // evaluate message + switch m.Type { + case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply: + pinger.process(m.Body, nil, addr, &t) + + case ipv4.ICMPTypeDestinationUnreachable, ipv6.ICMPTypeDestinationUnreachable: + body := m.Body.(*icmp.DstUnreach) + if body == nil { + return + } + + var bodyData []byte + switch proto { + case ProtocolICMP: + // parse header of original IPv4 packet + hdr, err := ipv4.ParseHeader(body.Data) + if err != nil { + return + } + bodyData = body.Data[hdr.Len:] + case ProtocolICMPv6: + // parse header of original IPv6 packet (we don't need the actual + // header, but want to detect parsing errors) + _, err := ipv6.ParseHeader(body.Data) + if err != nil { + return + } + bodyData = body.Data[ipv6.HeaderLen:] + default: + return + } + + // parse ICMP message after the IP header + msg, err := icmp.ParseMessage(proto, bodyData) + if err != nil { + return + } + pinger.process(msg.Body, fmt.Errorf("%s", m.Type), nil, nil) + } +} + +// process will finish a currently running Echo Request, if the body is +// an ICMP Echo reply to a request from us. +func (pinger *Pinger) process(body icmp.MessageBody, result error, addr net.IP, tRecv *time.Time) { + echo, ok := body.(*icmp.Echo) + if !ok || echo == nil { + if pinger.LogUnexpectedPackets { + log.Info("expected *icmp.Echo, got ", body) + } + return + } + + // check if we sent this + if uint16(echo.ID) != pinger.id { + return + } + + // search for existing running echo request + pinger.mtx.Lock() + req := pinger.requests[uint16(echo.Seq)] + if _, ok := req.(*simpleRequest); ok { + // a simpleRequest is finished on the first reply + delete(pinger.requests, uint16(echo.Seq)) + } + pinger.mtx.Unlock() + + if req != nil { + req.handleReply(result, addr, tRecv) + } +} diff --git a/go-apps/meep-tc-sidecar/request.go b/go-apps/meep-tc-sidecar/request.go new file mode 100644 index 0000000000000000000000000000000000000000..5e1ea544fcd6f9c08a65fa03ab691640a09ecd00 --- /dev/null +++ b/go-apps/meep-tc-sidecar/request.go @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "net" + "sync" + "time" +) + +type request interface { + init() + close() + handleReply(error, net.IP, *time.Time) +} + +// A multiRequest is a currently running ICMP echo request waiting for multple answers. +type multiRequest struct { + tStart time.Time // when was the request packet sent? + replies chan Reply + closed bool + mtx sync.RWMutex +} + +// Reply is a reply to a multicast echo request +type Reply struct { + Address net.IP + Duration time.Duration +} + +// A simpleRequest is a currently running ICMP echo request waiting for a single answer. +type simpleRequest struct { + wait chan struct{} + result error + tStart time.Time // when was this packet sent? + tFinish *time.Time // if and when was the reply received? +} + +// handleReply is responsible for finishing this request. +// It takes an error as failure reason. +func (req *simpleRequest) handleReply(err error, _ net.IP, tRecv *time.Time) { + req.result = err + + // update tFinish only if no error present and value wasn't previously set + if err == nil && tRecv != nil && req.tFinish == nil { + req.tFinish = tRecv + } + close(req.wait) +} + +func (req *simpleRequest) init() { + req.wait = make(chan struct{}) + req.tStart = time.Now() +} + +func (req *simpleRequest) close() { + close(req.wait) +} + +func (req *simpleRequest) roundTripTime() (time.Duration, error) { + if req.result != nil { + return 0, req.result + } + if req.tFinish == nil { + return 0, nil + } + return req.tFinish.Sub(req.tStart), nil +} + +func (req *multiRequest) init() { + req.replies = make(chan Reply) + req.tStart = time.Now() +} + +func (req *multiRequest) close() { + req.mtx.Lock() + req.closed = true + close(req.replies) + req.mtx.Unlock() +} + +// handleReply is responsible for adding a result to the result set +func (req *multiRequest) handleReply(_ error, addr net.IP, tRecv *time.Time) { + // avoid blocking + go func() { + req.mtx.RLock() + defer req.mtx.RUnlock() + + if !req.closed { + req.replies <- Reply{ + Address: addr, + Duration: tRecv.Sub(req.tStart), + } + } + }() +} diff --git a/go-apps/meep-tc-sidecar/resolve.go b/go-apps/meep-tc-sidecar/resolve.go new file mode 100644 index 0000000000000000000000000000000000000000..95bdf0177b3e9b04e927fc59ceffe39be8767b96 --- /dev/null +++ b/go-apps/meep-tc-sidecar/resolve.go @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "context" + "net" + "strings" + "time" +) + +func resolve(addr string, timeout time.Duration) ([]net.IPAddr, error) { + if strings.ContainsRune(addr, '%') { + ipaddr, err := net.ResolveIPAddr("ip", addr) + if err != nil { + return nil, err + } + return []net.IPAddr{*ipaddr}, nil + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + return net.DefaultResolver.LookupIPAddr(ctx, addr) +} diff --git a/go-apps/meep-tc-sidecar/sending.go b/go-apps/meep-tc-sidecar/sending.go new file mode 100644 index 0000000000000000000000000000000000000000..1f96960cd76441024181547c4dd8ce7f3c292315 --- /dev/null +++ b/go-apps/meep-tc-sidecar/sending.go @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "context" + "errors" + "net" + "sync" + "sync/atomic" + "time" + + "golang.org/x/net/icmp" + "golang.org/x/net/ipv4" + "golang.org/x/net/ipv6" +) + +// PingAttempts sends ICMP echo requests with a timeout per request, retrying upto `attempt` times . +// Will finish early on success and return the round trip time of the last ping. +func (pinger *Pinger) PingAttempts(destination *net.IPAddr, timeout time.Duration, attempts int) (rtt time.Duration, err error) { + if attempts < 1 { + err = errors.New("zero attempts") + } else { + for i := 0; i < attempts; i++ { + rtt, err = pinger.Ping(destination, timeout) + if err == nil { + break // success + } + } + } + return +} + +// Ping sends a single Echo Request and waits for an answer. It returns +// the round trip time (RTT) if a reply is received in time. +func (pinger *Pinger) Ping(destination *net.IPAddr, timeout time.Duration) (time.Duration, error) { + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(timeout)) + defer cancel() + return pinger.PingContext(ctx, destination) +} + +// PingContext sends a single Echo Request and waits for an answer. It returns +// the round trip time (RTT) if a reply is received before cancellation of the context. +func (pinger *Pinger) PingContext(ctx context.Context, destination *net.IPAddr) (time.Duration, error) { + req := simpleRequest{} + seq, err := pinger.sendRequest(destination, &req) + if err != nil { + return 0, err + } + // wait for answer + select { + case <-req.wait: + // already dequeued + err = req.result + case <-ctx.Done(): + // dequeue request + pinger.removeRequest(seq) + err = &timeoutError{} + } + + if err != nil { + return 0, err + } + return req.roundTripTime() +} + +// PingMulticast sends a single echo request and returns a channel for the responses. +// The channel will be closed on termination of the context. +// An error is returned if the sending of the echo request fails. +func (pinger *Pinger) PingMulticast(destination *net.IPAddr, wait time.Duration) (<-chan Reply, error) { + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(wait)) + defer cancel() + return pinger.PingMulticastContext(ctx, destination) +} + +// PingMulticastContext does the same as PingMulticast but receives a context +func (pinger *Pinger) PingMulticastContext(ctx context.Context, destination *net.IPAddr) (<-chan Reply, error) { + req := multiRequest{} + + seq, err := pinger.sendRequest(destination, &req) + if err != nil { + return nil, err + } + + go func() { + <-ctx.Done() + + // dequeue request + pinger.removeRequest(seq) + + req.close() + }() + + return req.replies, nil +} + +// sendRequest marshals the payload and sends the packet. +// It returns the sequence number and an error if the sending failed. +func (pinger *Pinger) sendRequest(destination *net.IPAddr, req request) (uint16, error) { + seq := uint16(atomic.AddUint32(&sequence, 1)) + + pinger.payloadMu.RLock() + defer pinger.payloadMu.RUnlock() + + // build packet + wm := icmp.Message{ + Code: 0, + Body: &icmp.Echo{ + ID: int(pinger.id), + Seq: int(seq), + Data: pinger.payload, + }, + } + + // Protocol specifics + var conn *icmp.PacketConn + var lock *sync.Mutex + if destination.IP.To4() != nil { + wm.Type = ipv4.ICMPTypeEcho + conn = pinger.conn4 + lock = &pinger.write4 + } else { + wm.Type = ipv6.ICMPTypeEchoRequest + conn = pinger.conn6 + lock = &pinger.write6 + } + + // serialize packet + wb, err := wm.Marshal(nil) + if err != nil { + return seq, err + } + + // enqueue in currently running requests + pinger.mtx.Lock() + pinger.requests[seq] = req + pinger.mtx.Unlock() + + // start measurement (tStop is set in the receiving end) + lock.Lock() + req.init() + // send request + _, err = conn.WriteTo(wb, destination) + lock.Unlock() + // send failed, need to remove request from list + if err != nil { + req.close() + pinger.removeRequest(seq) + + return 0, err + } + return seq, nil +} diff --git a/go-apps/meep-virt-engine/.swagger-codegen-ignore b/go-apps/meep-virt-engine/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/go-apps/meep-virt-engine/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/go-apps/meep-virt-engine/.swagger-codegen/VERSION b/go-apps/meep-virt-engine/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..a6254504e40175d135cea7feb34ad31fa0d0bca3 --- /dev/null +++ b/go-apps/meep-virt-engine/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.1 \ No newline at end of file diff --git a/go-apps/meep-virt-engine/.vscode/launch.json b/go-apps/meep-virt-engine/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..47d453d9b4b2eb75ab298801b4bd956676dc4c97 --- /dev/null +++ b/go-apps/meep-virt-engine/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "name": "Launch", + "type": "go", + "request": "launch", + "mode": "debug", + "remotePath": "", + "port": 2345, + "host": "127.0.0.1", + "program": "${fileDirname}", + "env": {}, + "args": [], + "showLog": true + } + ] +} \ No newline at end of file diff --git a/go-apps/meep-virt-engine/Dockerfile b/go-apps/meep-virt-engine/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..4fac2541cb76ee173d60b441ae160a18f12dca11 --- /dev/null +++ b/go-apps/meep-virt-engine/Dockerfile @@ -0,0 +1,10 @@ +# Copyright (c) 2019 +# InterDigital Communications, Inc. +# All rights reserved. +# +# The information provided herein is the proprietary and confidential +# information of InterDigital Communications, Inc. + +FROM debian +COPY ./meep-virt-engine /meep-virt-engine +ENTRYPOINT /meep-virt-engine diff --git a/bin/meep-ctrl-engine/static/api/meep-virt-engine.yaml b/go-apps/meep-virt-engine/api/swagger.yaml similarity index 99% rename from bin/meep-ctrl-engine/static/api/meep-virt-engine.yaml rename to go-apps/meep-virt-engine/api/swagger.yaml index cb2c4d70b2618b98b8f1807ff267d4321b702781..fbc42cf1d5cc22e7c0b81548e4ca80ed61d6afa6 100644 --- a/bin/meep-ctrl-engine/static/api/meep-virt-engine.yaml +++ b/go-apps/meep-virt-engine/api/swagger.yaml @@ -1,7 +1,9 @@ --- swagger: "2.0" info: - description: "MEEP Virtualization Engine REST API" + description: "Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved.\ + \ The information provided herein is the proprietary and confidential information\ + \ of InterDigital Communications, Inc.\n" version: "1.0.0" title: "MEEP Virtualization Engine REST API" host: "meep-virt-engine" diff --git a/go-apps/meep-virt-engine/go.mod b/go-apps/meep-virt-engine/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..47b39c0bd1e3c9fb89ac835ce096fec20cf9c7d9 --- /dev/null +++ b/go-apps/meep-virt-engine/go.mod @@ -0,0 +1,9 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine + +go 1.12 + +require ( + github.com/gorilla/handlers v1.4.0 + github.com/gorilla/mux v1.7.1 + github.com/sirupsen/logrus v1.4.1 +) diff --git a/go-apps/meep-virt-engine/go.sum b/go-apps/meep-virt-engine/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..7653889480be6e8d08d65faf8cb41bf1e843ad97 --- /dev/null +++ b/go-apps/meep-virt-engine/go.sum @@ -0,0 +1,17 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= +github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.1 h1:Dw4jY2nghMMRsh1ol8dv1axHkDwMQK2DHerMNJsIpJU= +github.com/gorilla/mux v1.7.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/go-apps/meep-virt-engine/helm/delete.go b/go-apps/meep-virt-engine/helm/delete.go new file mode 100644 index 0000000000000000000000000000000000000000..d591960db7139207c8788c72db0605b034c05230 --- /dev/null +++ b/go-apps/meep-virt-engine/helm/delete.go @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package helm + +import ( + "os/exec" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +func deleteReleases(charts []Chart) error { + for _, c := range charts { + var cmd = exec.Command("helm", "delete", c.ReleaseName, "--purge") + _, err := cmd.CombinedOutput() + if err != nil { + log.Error(err) + return err + } + } + + return nil +} diff --git a/go-apps/meep-virt-engine/helm/helm.go b/go-apps/meep-virt-engine/helm/helm.go new file mode 100644 index 0000000000000000000000000000000000000000..947ebaff6b69422554c4609964a7270174c75643 --- /dev/null +++ b/go-apps/meep-virt-engine/helm/helm.go @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package helm + +import ( + "fmt" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +const ( + StateIdle = "IDLE" + StateInstalling = "INSTALLING" + StateDeleting = "DELETING" +) + +var state string = StateIdle + +func GetReleasesName() ([]Release, error) { + return getReleasesName() +} + +func GetReleases() ([]Release, error) { + return getReleases() +} + +func InstallCharts(charts []Chart) error { + if state == StateIdle { + state = StateInstalling + go func() { + log.Debug("Installing ", len(charts), " Charts...") + _ = installCharts(charts) + log.Debug("Charts installed (", len(charts), ")") + state = StateIdle + }() + return nil + } + err := fmt.Errorf("Service busy [%s]", state) + return err +} + +func DeleteReleases(charts []Chart) error { + if state == StateIdle { + state = StateDeleting + go func() { + log.Debug("Deleting ", len(charts), " Releases...") + _ = deleteReleases(charts) + log.Debug("Releases deleted (", len(charts), ")") + state = StateIdle + }() + return nil + } + err := fmt.Errorf("Service busy [%s]", state) + return err +} diff --git a/go-apps/meep-virt-engine/helm/install.go b/go-apps/meep-virt-engine/helm/install.go new file mode 100644 index 0000000000000000000000000000000000000000..af21ffd0407a9c0625f4c24568f80e7d4aa9e529 --- /dev/null +++ b/go-apps/meep-virt-engine/helm/install.go @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package helm + +import ( + "errors" + "os/exec" + "strings" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +func installCharts(charts []Chart) error { + + err := ensureReleases(charts) + if err != nil { + return err + } + + err = install(charts) + if err != nil { + // Cleanup release + cleanReleases(charts) + } + return err +} + +func ensureReleases(charts []Chart) error { + // ensure that releases do not already exist + releases, _ := GetReleasesName() + for _, c := range charts { + for _, r := range releases { + if c.ReleaseName == r.Name { + err := errors.New("Release [" + c.ReleaseName + "] already exists") + log.Error(err) + return err + } + } + } + return nil +} + +func install(charts []Chart) error { + for _, c := range charts { + var cmd *exec.Cmd + if strings.Trim(c.ValuesFile, " ") == "" { + cmd = exec.Command("helm", "install", "--name", c.ReleaseName, "--set", + "fullnameOverride="+c.ReleaseName, c.Location, "--replace") + } else { + cmd = exec.Command("helm", "install", "--name", c.ReleaseName, "--set", + "fullnameOverride="+c.ReleaseName, c.Location, "-f", c.ValuesFile, "--replace") + } + out, err := cmd.CombinedOutput() + if err != nil { + log.Error("Failed to install Release [" + c.ReleaseName + "] at " + c.Location) + log.Error("Error(", err.Error(), "): ", string(out)) + return err + } + } + return nil +} + +func cleanReleases(charts []Chart) { + var toClean []Chart + var cnt int + releases, _ := GetReleasesName() + // ensure that releases do not exist + + for _, c := range charts { + for _, r := range releases { + if c.ReleaseName == r.Name { + toClean = append(toClean, c) + cnt++ + } + } + } + + if cnt > 0 { + _ = DeleteReleases(toClean) + } +} diff --git a/go-apps/meep-virt-engine/helm/list.go b/go-apps/meep-virt-engine/helm/list.go new file mode 100644 index 0000000000000000000000000000000000000000..61d42399f5fb27e5c738f1f48780e2457e1fc346 --- /dev/null +++ b/go-apps/meep-virt-engine/helm/list.go @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package helm + +import ( + "bufio" + "errors" + "os/exec" + "strings" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +func getReleasesName() ([]Release, error) { + out, err := getList() + if err != nil { + return nil, err + } + + release, err := parseList(out, true) + if err != nil { + return nil, err + } + return release, nil +} + +func getReleases() ([]Release, error) { + out, err := getList() + if err != nil { + return nil, err + } + + release, err := parseList(out, false) + if err != nil { + return nil, err + } + return release, nil +} + +func getList() ([]byte, error) { + var cmd = exec.Command("helm", "ls") + out, err := cmd.Output() + if err != nil { + err = errors.New("Unable to list Releases") + log.Error(err) + return nil, err + } + return out, nil +} + +func parseList(buf []byte, nameOnly bool) ([]Release, error) { + /* Example of what needs to be parsed + NAME REVISION UPDATED STATUS CHART NAMESPACE + osvc1 1 Tue Jun 12 13:02:55 2018 DEPLOYED orientation-svc-0.1.0 default + osvc2 1 Tue Jun 12 13:04:54 2018 DEPLOYED orientation-svc-0.1.0 default + uss 1 Wed Jun 13 19:42:29 2018 DEPLOYED uss-0.1.0 default + uss-db 1 Wed Jun 13 19:41:34 2018 DEPLOYED mysql-0.5.0 default + */ + var releases []Release + + s := string(buf) + scanLines := bufio.NewScanner(strings.NewReader(s)) + scanLines.Split(bufio.ScanLines) + for i := 0; scanLines.Scan(); i++ { + if i == 0 { + continue + } + scanWords := bufio.NewScanner(strings.NewReader(scanLines.Text())) + scanWords.Split(bufio.ScanWords) + scanWords.Scan() + var r Release + // Name + r.Name = scanWords.Text() + if !nameOnly { + // Status + sp, err := GetReleaseStatus(r.Name) + r.Status = *sp + if err != nil { + log.Error(err) + continue + } + } + releases = append(releases, r) + } + + return releases, nil +} diff --git a/go-apps/meep-virt-engine/helm/status.go b/go-apps/meep-virt-engine/helm/status.go new file mode 100644 index 0000000000000000000000000000000000000000..06d5f1bcecb3386bffc315ae7d384599020dc45a --- /dev/null +++ b/go-apps/meep-virt-engine/helm/status.go @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package helm + +import ( + "bufio" + "errors" + "os/exec" + "strings" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +const NAMESPACE string = "NAMESPACE:" +const STATUS string = "STATUS:" +const RESOURCE string = "==>" + +// Returns the status of a release +func GetReleaseStatus(name string) (*Status, error) { + out, err := getStatus(name) + if err != nil { + return nil, err + } + + status, err := parseStatus(out) + if err != nil { + return nil, err + } + return status, nil +} + +func getStatus(name string) ([]byte, error) { + var cmd = exec.Command("helm", "status", name) + out, err := cmd.Output() + if err != nil { + err = errors.New("Error getting status for Release [" + name + "]") + log.Error(err) + return nil, err + } + return out, nil +} + +func parseStatus(buf []byte) (*Status, error) { + var status Status + + s := string(buf) + scanLines := bufio.NewScanner(strings.NewReader(s)) + scanLines.Split(bufio.ScanLines) + for i := 0; scanLines.Scan(); i++ { + scanWords := bufio.NewScanner(strings.NewReader(scanLines.Text())) + scanWords.Split(bufio.ScanWords) + scanWords.Scan() + word := scanWords.Text() + + if word == NAMESPACE { + scanWords.Scan() + status.Namespace = scanWords.Text() + } else if word == STATUS { + scanWords.Scan() + status.State = scanWords.Text() + } else if word == "==>" { + var r Resource + // Scan Type + scanWords.Scan() + t := strings.Split(scanWords.Text(), "/") + r.Type = t[1] + + // Skip a line + scanLines.Scan() + + // Scan Name + scanLines.Scan() + scanRes := bufio.NewScanner(strings.NewReader(scanLines.Text())) + scanRes.Split(bufio.ScanWords) + scanRes.Scan() + r.Name = scanRes.Text() + for scanRes.Scan() { + r.Age = scanRes.Text() + } + status.Resources = append(status.Resources, r) + } + } + return &status, nil +} diff --git a/go-apps/meep-virt-engine/helm/util.go b/go-apps/meep-virt-engine/helm/util.go new file mode 100644 index 0000000000000000000000000000000000000000..f39a5f31a006ee92e859cea74083aee41b22f1d9 --- /dev/null +++ b/go-apps/meep-virt-engine/helm/util.go @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package helm + +import ( + "strconv" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +type Chart struct { + ChartName string + ReleaseName string + Location string + ValuesFile string +} + +type Release struct { + Name string + Status Status +} + +type Status struct { + State string + Namespace string + Resources []Resource +} + +type Resource struct { + Name string + Type string + Age string +} + +func PrettyReleasesPrint(releases []Release) { + var lines []string + + l := "# NAME\tSTATE\t\tNAMESP.\t[RESOURCES]" + lines = append(lines, l) + for i, r := range releases { + l = strconv.Itoa(i) + "- " + r.Name + if r.Status.State != "" { + l += "\t" + r.Status.State + "\t" + r.Status.Namespace + "\t(" + for j, res := range r.Status.Resources { + if j != 0 { + l += "/" + } + l += res.Type + } + l += ")" + } + lines = append(lines, l) + } + + for _, l = range lines { + log.Info(l) + } +} diff --git a/go-apps/meep-virt-engine/log/meeplog.go b/go-apps/meep-virt-engine/log/meeplog.go new file mode 100644 index 0000000000000000000000000000000000000000..7f66ad4b4b81734d7143d4486955f79a9ee06fcf --- /dev/null +++ b/go-apps/meep-virt-engine/log/meeplog.go @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package logmain + +import ( + "os" + + log "github.com/sirupsen/logrus" +) + +func MeepJSONLogInit() { + log.SetFormatter(&log.JSONFormatter{}) + log.SetLevel(log.DebugLevel) + //force output to stdout rather than default stderr + log.SetOutput(os.Stdout) +} + +func Info(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "virt-engine", + }).Info(args...) +} + +func Debug(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "virt-engine", + }).Debug(args...) +} + +func Warn(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "virt-engine", + }).Warn(args...) +} +func Error(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "virt-engine", + }).Error(args...) +} +func Panic(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "virt-engine", + }).Panic(args...) +} + +func Fatal(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": "virt-engine", + }).Fatal(args...) +} + +func WithFields(fields log.Fields) *log.Entry { + return log.WithFields(fields) +} diff --git a/go-apps/meep-virt-engine/main.go b/go-apps/meep-virt-engine/main.go new file mode 100644 index 0000000000000000000000000000000000000000..cdb5e21b5ccfca5508f6560c5788e559a0b2f1ab --- /dev/null +++ b/go-apps/meep-virt-engine/main.go @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "github.com/gorilla/handlers" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" + server "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/server" +) + +func init() { + log.MeepJSONLogInit() +} + +func main() { + log.Info(os.Args) + + log.Info("Server started") + + run := true + go func() { + sigchan := make(chan os.Signal, 10) + signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM) + <-sigchan + log.Info("Program killed !") + // do last actions and wait for all write operations to end + run = false + }() + + go func() { + server.VirtEngineInit() + + router := server.NewRouter() + + methods := handlers.AllowedMethods([]string{"OPTIONS", "DELETE", "GET", "HEAD", "POST", "PUT"}) + header := handlers.AllowedHeaders([]string{"content-type"}) + + log.Fatal(http.ListenAndServe(":30219", handlers.CORS(methods, header)(router))) + run = false + }() + + count := 0 + for { + if !run { + log.Info("Ran for", count, "seconds") + break + } + time.Sleep(time.Second) + count++ + } +} diff --git a/go-apps/meep-virt-engine/main_test.go b/go-apps/meep-virt-engine/main_test.go new file mode 100644 index 0000000000000000000000000000000000000000..fa4aa8904e596bb69638c75eb6523b35304b0909 --- /dev/null +++ b/go-apps/meep-virt-engine/main_test.go @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package main + +import ( + "os" + "strings" + "testing" + + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +// Build: +// $ go test -covermode=count -coverpkg=./... -c -o +// Run: +// $ ./ -test.coverprofile=cover.out __DEVEL--code-cov + +// TestMain is a hack that allows us to figure out what the coverage is during +// integration tests. I would not recommend that you use a binary built using +// this hack outside of a test suite. +func TestMain(t *testing.T) { + var ( + args []string + run bool + ) + + log.Info(os.Args) + for _, arg := range os.Args { + switch { + case arg == "__DEVEL--code-cov": + run = true + case strings.HasPrefix(arg, "-test"): + case strings.HasPrefix(arg, "__DEVEL"): + default: + args = append(args, arg) + } + } + os.Args = args + log.Info(os.Args) + + if run { + main() + } +} diff --git a/go-apps/meep-virt-engine/meep-virt.code-workspace b/go-apps/meep-virt-engine/meep-virt.code-workspace new file mode 100644 index 0000000000000000000000000000000000000000..876a1499c09dc083612f43c53c0ae71b9c30c5b1 --- /dev/null +++ b/go-apps/meep-virt-engine/meep-virt.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/go-apps/meep-virt-engine/server/README.md b/go-apps/meep-virt-engine/server/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a16af20b8ea7619f34b449aede85393e03202378 --- /dev/null +++ b/go-apps/meep-virt-engine/server/README.md @@ -0,0 +1,25 @@ +# Go API Server for server + +Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + +## Overview +This server was generated by the [swagger-codegen] +(https://github.com/swagger-api/swagger-codegen) project. +By using the [OpenAPI-Spec](https://github.com/OAI/OpenAPI-Specification) from a remote server, you can easily generate a server stub. +- + +To see how to make this your own, look here: + +[README](https://github.com/swagger-api/swagger-codegen/blob/master/README.md) + +- API version: 1.0.0 +- Build date: 2019-05-15T12:26:07.901-04:00 + + +### Running the server +To run the server, follow these simple steps: + +``` +go run main.go +``` + diff --git a/go-apps/meep-virt-engine/server/chart_template.go b/go-apps/meep-virt-engine/server/chart_template.go new file mode 100644 index 0000000000000000000000000000000000000000..e4b879d523976ae352542dffe756049bbe233172 --- /dev/null +++ b/go-apps/meep-virt-engine/server/chart_template.go @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package server + +import ( + "os" + "os/user" + "path/filepath" + "strconv" + "strings" + "text/template" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/helm" + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +const SERVICE_PORT_MIN = 1 +const SERVICE_PORT_MAX = 65535 +const SERVICE_NODE_PORT_MIN = 30000 +const SERVICE_NODE_PORT_MAX = 32767 +const DEFAULT_DUMMY_CONTAINER_IMAGE = "nginx" + +type DeploymentTemplate struct { + Enabled string + Name string + ReplicaCount string + ApiVersion string + MatchLabels []string + TemplateLabels []string + ContainerName string + ContainerImageRepository string + ContainerImagePullPolicy string + ContainerEnvEnabled string + ContainerEnv []string + ContainerCommandEnabled string + ContainerCommand []string + ContainerCommandArg []string + ContainerPort string + ContainerProtocol string +} + +type ServiceTemplate struct { + Enabled string + Name string + Namespace string + Labels []string + Selector []string + Type string + Ports []ServicePortTemplate + MeServiceEnabled string + MeServiceName string +} + +type ServicePortTemplate struct { + Port string + TargetPort string + Protocol string + NodePort string +} + +type ExternalTemplate struct { + Enabled string + Selector []string + IngressServiceMap []ServiceMapTemplate + EgressServiceMap []ServiceMapTemplate +} + +type ServiceMapTemplate struct { + Name string + IP string + Port string + NodePort string + Protocol string +} + +// helm values.yaml template +type ScenarioTemplate struct { + Deployment DeploymentTemplate + Service ServiceTemplate + External ExternalTemplate + NamespaceName string +} + +// Service map +var serviceMap map[string]string + +func addTemplateLabel(deploymentTemplate *DeploymentTemplate, label string) { + deploymentTemplate.TemplateLabels = append(deploymentTemplate.TemplateLabels, label) +} + +func addMatchLabel(deploymentTemplate *DeploymentTemplate, label string) { + deploymentTemplate.MatchLabels = append(deploymentTemplate.MatchLabels, label) +} + +func addServiceLabel(serviceTemplate *ServiceTemplate, label string) { + serviceTemplate.Labels = append(serviceTemplate.Labels, label) +} + +func addSelector(serviceTemplate *ServiceTemplate, selector string) { + serviceTemplate.Selector = append(serviceTemplate.Selector, selector) +} + +func addExtSelector(externalTemplate *ExternalTemplate, selector string) { + externalTemplate.Selector = append(externalTemplate.Selector, selector) +} + +func populateScenarioTemplate(scenario Scenario) ([]helm.Chart, error) { + + var charts []helm.Chart + serviceMap = map[string]string{} + + // Parse domains + for _, domain := range scenario.Deployment.Domains { + // Parse zones + for _, zone := range domain.Zones { + // Parse Network Locations + for _, nl := range zone.NetworkLocations { + // Parse Physical locations + for _, pl := range nl.PhysicalLocations { + // Parse Processes + for _, proc := range pl.Processes { + + // Create default scenario template + var scenarioTemplate ScenarioTemplate + deploymentTemplate := &scenarioTemplate.Deployment + serviceTemplate := &scenarioTemplate.Service + externalTemplate := &scenarioTemplate.External + setScenarioDefaults(&scenarioTemplate) + + // Fill general scenario template information + scenarioTemplate.NamespaceName = scenario.Name + deploymentTemplate.Name = proc.Name + + // Create charts + if proc.UserChartLocation != "" { + log.Debug("Processing user-defined chart for element[", proc.Name, "]") + + // Add user-defined chart + newChart := createChart(scenario.Name+"-"+proc.Name, getFullPath(proc.UserChartLocation), + getFullPath(proc.UserChartAlternateValues)) + charts = append(charts, newChart) + log.Debug("user chart added ", len(charts)) + + // Parse User Chart Group to find new group services + // Create charts only for group services that do not exist yet + // Format: :[group service name]:: + userChartGroup := strings.Split(proc.UserChartGroup, ":") + meSvcName := userChartGroup[1] + if meSvcName != "" { + if _, found := serviceMap[meSvcName]; !found { + serviceMap[meSvcName] = "meepMeSvc: " + meSvcName + serviceTemplate.MeServiceEnabled = "true" + serviceTemplate.MeServiceName = meSvcName + addServiceLabel(serviceTemplate, "meepMeSvc: "+meSvcName) + + serviceTemplate.Namespace = scenario.Name + addServiceLabel(serviceTemplate, "meepScenario: "+scenario.Name) + + // NOTE: Every service within a group must expose the same port & protocol + var portTemplate ServicePortTemplate + portTemplate.Port = userChartGroup[2] + portTemplate.Protocol = userChartGroup[3] + serviceTemplate.Ports = append(serviceTemplate.Ports, portTemplate) + + // Create chart files + chartLocation, err := createYamlScenarioFiles(scenarioTemplate) + if err != nil { + log.Debug("yaml creation file process: ", err) + return nil, err + } + + // Create virt-engine chart for new group service + newChart := createChart(scenario.Name+"-"+proc.Name+"-svc", chartLocation, "") + charts = append(charts, newChart) + log.Debug("chart added for user chart group service ", len(charts)) + } + } + } else { + log.Debug("Processing virt-engine chart for element[", proc.Name, "]") + + // Fill deployment template information + deploymentTemplate.Enabled = "true" + deploymentTemplate.ContainerName = proc.Name + deploymentTemplate.ContainerImageRepository = proc.Image + deploymentTemplate.ContainerImagePullPolicy = "IfNotPresent" + setEnv(deploymentTemplate, proc.Environment) + setCommand(deploymentTemplate, proc.CommandExe, proc.CommandArguments) + addMatchLabel(deploymentTemplate, "meepAppId: "+proc.Id) + addTemplateLabel(deploymentTemplate, "meepAppId: "+proc.Id) + + // Enable Service template if present + if proc.ServiceConfig != nil { + + // Add app name associated to service + svcName := proc.ServiceConfig.Name + serviceTemplate.Enabled = "true" + serviceTemplate.Name = svcName + serviceTemplate.Namespace = scenario.Name + addSelector(serviceTemplate, "meepSvc: "+svcName) + addServiceLabel(serviceTemplate, "meepScenario: "+scenario.Name) + addTemplateLabel(deploymentTemplate, "meepSvc: "+svcName) + + // Create and store ME Service template only with first occurrence. + // If it already exists then add the matching pod label but don't create the service again. + meSvcName := proc.ServiceConfig.MeSvcName + if meSvcName != "" { + if _, found := serviceMap[meSvcName]; !found { + serviceMap[meSvcName] = "meepMeSvc: " + meSvcName + serviceTemplate.MeServiceEnabled = "true" + serviceTemplate.MeServiceName = meSvcName + } + addServiceLabel(serviceTemplate, "meepMeSvc: "+meSvcName) + addTemplateLabel(deploymentTemplate, "meepMeSvc: "+meSvcName) + } + + for _, ports := range proc.ServiceConfig.Ports { + var portTemplate ServicePortTemplate + portTemplate.Port = strconv.Itoa(int(ports.Port)) + portTemplate.TargetPort = strconv.Itoa(int(ports.Port)) + portTemplate.Protocol = ports.Protocol + + // Add NodePort if service is exposed externally + if ports.ExternalPort >= SERVICE_NODE_PORT_MIN && ports.ExternalPort <= SERVICE_NODE_PORT_MAX { + portTemplate.NodePort = strconv.Itoa(int(ports.ExternalPort)) + serviceTemplate.Type = "NodePort" + } else { + serviceTemplate.Type = "ClusterIP" + } + + serviceTemplate.Ports = append(serviceTemplate.Ports, portTemplate) + } + } + + // Enable External template if set + if proc.IsExternal { + externalTemplate.Enabled = "true" + addExtSelector(externalTemplate, "meepAppId: "+proc.Id) + + // Add ingress Service Maps, if any + for _, serviceMap := range proc.ExternalConfig.IngressServiceMap { + var ingressSvcMapTemplate ServiceMapTemplate + ingressSvcMapTemplate.Name = "ingress-" + proc.Id + "-" + serviceMap.Name + ingressSvcMapTemplate.NodePort = strconv.Itoa(int(serviceMap.ExternalPort)) + ingressSvcMapTemplate.Port = strconv.Itoa(int(serviceMap.Port)) + ingressSvcMapTemplate.Protocol = serviceMap.Protocol + + externalTemplate.IngressServiceMap = append(externalTemplate.IngressServiceMap, ingressSvcMapTemplate) + } + + // Add egress Service Maps, if any + for _, serviceMap := range proc.ExternalConfig.EgressServiceMap { + var egressSvcMapTemplate ServiceMapTemplate + egressSvcMapTemplate.Name = serviceMap.Name + egressSvcMapTemplate.IP = serviceMap.Ip + egressSvcMapTemplate.Port = strconv.Itoa(int(serviceMap.Port)) + egressSvcMapTemplate.Protocol = serviceMap.Protocol + + externalTemplate.EgressServiceMap = append(externalTemplate.EgressServiceMap, egressSvcMapTemplate) + } + } + + // Create chart files + chartLocation, err := createYamlScenarioFiles(scenarioTemplate) + if err != nil { + log.Debug("yaml creation file process: ", err) + return nil, err + } + + // Create virt-engine chart + newChart := createChart(scenario.Name+"-"+proc.Name, chartLocation, "") + charts = append(charts, newChart) + log.Debug("chart added ", len(charts)) + } + } + } + } + } + } + + return charts, nil +} + +func createChart(name string, chartLocation string, valuesFile string) helm.Chart { + var chart helm.Chart + chart.ChartName = name + chart.ReleaseName = "meep-" + name + chart.Location = chartLocation + chart.ValuesFile = valuesFile + return chart +} + +func getFullPath(path string) string { + fullPath := path + + // Get home directory + usr, err := user.Current() + if err != nil { + return fullPath + } + homeDir := usr.HomeDir + + // Replace ~ with home directory + if path == "~" { + fullPath = homeDir + } else if strings.HasPrefix(path, "~/") { + fullPath = filepath.Join(homeDir, path[2:]) + } + return fullPath +} + +func setScenarioDefaults(scenarioTemplate *ScenarioTemplate) { + setDeploymentDefaults(&scenarioTemplate.Deployment) + setServiceDefaults(&scenarioTemplate.Service) + setExternalDefaults(&scenarioTemplate.External) +} + +func setDeploymentDefaults(deploymentTemplate *DeploymentTemplate) { + deploymentTemplate.Enabled = "false" + deploymentTemplate.ReplicaCount = "1" + deploymentTemplate.ApiVersion = "v1" + deploymentTemplate.ContainerEnvEnabled = "false" + deploymentTemplate.ContainerCommandEnabled = "false" +} + +func setServiceDefaults(serviceTemplate *ServiceTemplate) { + serviceTemplate.Enabled = "false" + serviceTemplate.MeServiceEnabled = "false" +} + +func setExternalDefaults(externalTemplate *ExternalTemplate) { + externalTemplate.Enabled = "false" +} + +func setEnv(deployment *DeploymentTemplate, envString string) { + if envString != "" { + deployment.ContainerEnvEnabled = "true" + allVar := strings.Split(envString, ",") + + for _, oneVar := range allVar { + nameValue := strings.Split(oneVar, "=") + deployment.ContainerEnv = append(deployment.ContainerEnv, + strings.TrimSpace(nameValue[0])+": "+strings.TrimSpace(nameValue[1])) + } + } +} + +func setCommand(deployment *DeploymentTemplate, command string, commandArgs string) { + if command != "" { + log.Debug("command ", command) + deployment.ContainerCommandEnabled = "true" + + // Retrieve command list + allCmd := strings.Split(command, ",") + for _, cmd := range allCmd { + deployment.ContainerCommand = append(deployment.ContainerCommand, strings.TrimSpace(cmd)) + } + + // Retrieve arguments list + allArgs := strings.Split(commandArgs, ",") + for _, arg := range allArgs { + deployment.ContainerCommandArg = append(deployment.ContainerCommandArg, strings.TrimSpace(arg)) + } + } +} + +func CreateYamlScenarioFile(scenario Scenario) error { + + //var charts []helm.Chart + charts, err := populateScenarioTemplate(scenario) + + if err != nil { + log.Debug("populate template : ", err) + return err + } + + err = deployCharts(charts) + if err != nil { + log.Error("charts error : ", err) + return err + } + + return nil +} + +func createYamlScenarioFiles(scenarioTemplate ScenarioTemplate) (string, error) { + + homePath := os.Getenv("HOME") + + templateFilePath := homePath + "/.meep/template/values-template.yaml" + templateDefaultDir := homePath + "/.meep/template/defaultDir" + + t, err := template.ParseFiles(templateFilePath) + if err != nil { + log.Error(err) + return "", err + } + + outputDirPath := homePath + "/.meep/active/" + scenarioTemplate.NamespaceName + "/" + scenarioTemplate.Deployment.Name + log.Debug("Creation of the output path ", outputDirPath) + + _ = CopyDir(templateDefaultDir, outputDirPath) + + outputFilePath := outputDirPath + "/values.yaml" + + //creation of output file + f, err := os.Create(outputFilePath) + if err != nil { + log.Debug("create file: ", err) + return "", err + } + + //filling the template output file + err = t.Execute(f, scenarioTemplate) + if err != nil { + log.Debug("execute: ", err) + return "", err + } + + f.Close() + return outputDirPath, nil +} + +func deployCharts(charts []helm.Chart) error { + + err := helm.InstallCharts(charts) + if err != nil { + return err + } + return nil +} diff --git a/go-apps/meep-virt-engine/server/copy.go b/go-apps/meep-virt-engine/server/copy.go new file mode 100644 index 0000000000000000000000000000000000000000..bb842dee27bd892e1c38a275c195c119575ac910 --- /dev/null +++ b/go-apps/meep-virt-engine/server/copy.go @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package server + +import ( + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" +) + +// CopyFile copies the contents of the file named src to the file named +// by dst. The file will be created if it does not already exist. If the +// destination file exists, all it's contents will be replaced by the contents +// of the source file. The file mode will be copied from the source and +// the copied data is synced/flushed to stable storage. +func CopyFile(src, dst string) (err error) { + in, err := os.Open(src) + if err != nil { + return + } + defer in.Close() + + out, err := os.Create(dst) + if err != nil { + return + } + defer func() { + if e := out.Close(); e != nil { + err = e + } + }() + + _, err = io.Copy(out, in) + if err != nil { + return + } + + err = out.Sync() + if err != nil { + return + } + + si, err := os.Stat(src) + if err != nil { + return + } + err = os.Chmod(dst, si.Mode()) + if err != nil { + return + } + + return +} + +// CopyDir recursively copies a directory tree, attempting to preserve permissions. +// Source directory must exist, destination directory must *not* exist. +// Symlinks are ignored and skipped. +func CopyDir(src string, dst string) (err error) { + src = filepath.Clean(src) + dst = filepath.Clean(dst) + + si, err := os.Stat(src) + if err != nil { + return err + } + if !si.IsDir() { + return fmt.Errorf("source is not a directory") + } + + _, err = os.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return + } + if err == nil { + return fmt.Errorf("destination already exists") + } + + err = os.MkdirAll(dst, si.Mode()) + if err != nil { + return + } + + entries, err := ioutil.ReadDir(src) + if err != nil { + return + } + + for _, entry := range entries { + srcPath := filepath.Join(src, entry.Name()) + dstPath := filepath.Join(dst, entry.Name()) + + if entry.IsDir() { + err = CopyDir(srcPath, dstPath) + if err != nil { + return + } + } else { + // Skip symlinks. + if entry.Mode()&os.ModeSymlink != 0 { + continue + } + + err = CopyFile(srcPath, dstPath) + if err != nil { + return + } + } + } + + return +} diff --git a/go-apps/meep-virt-engine/server/deployment.go b/go-apps/meep-virt-engine/server/deployment.go new file mode 100644 index 0000000000000000000000000000000000000000..28a5ad95260035b667de9d944850b0c3abbb8ac9 --- /dev/null +++ b/go-apps/meep-virt-engine/server/deployment.go @@ -0,0 +1,28 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Network deployment object +type Deployment struct { + + // Latency in ms between domains + InterDomainLatency int32 `json:"interDomainLatency,omitempty"` + + // Latency variation in ms between domains + InterDomainLatencyVariation int32 `json:"interDomainLatencyVariation,omitempty"` + + // The limit of the traffic supported between domains + InterDomainThroughput int32 `json:"interDomainThroughput,omitempty"` + + // Packet lost (in terms of percentage) between domains + InterDomainPacketLoss float64 `json:"interDomainPacketLoss,omitempty"` + + Domains []Domain `json:"domains,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/domain.go b/go-apps/meep-virt-engine/server/domain.go new file mode 100644 index 0000000000000000000000000000000000000000..ca6897f8ee73a3191df2a0a073888238d2a25b12 --- /dev/null +++ b/go-apps/meep-virt-engine/server/domain.go @@ -0,0 +1,37 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Operator domain object +type Domain struct { + + // Unique domain ID + Id string `json:"id,omitempty"` + + // Domain name + Name string `json:"name,omitempty"` + + // Domain type + Type_ string `json:"type,omitempty"` + + // Latency in ms between zones within domain + InterZoneLatency int32 `json:"interZoneLatency,omitempty"` + + // Latency variation in ms between zones within domain + InterZoneLatencyVariation int32 `json:"interZoneLatencyVariation,omitempty"` + + // The limit of the traffic supported between zones within the domain + InterZoneThroughput int32 `json:"interZoneThroughput,omitempty"` + + // Packet lost (in terms of percentage) between zones within the domain + InterZonePacketLoss float64 `json:"interZonePacketLoss,omitempty"` + + Zones []Zone `json:"zones,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/event.go b/go-apps/meep-virt-engine/server/event.go new file mode 100644 index 0000000000000000000000000000000000000000..a3cb540906fcfcd4490992694818e87dc2826c0f --- /dev/null +++ b/go-apps/meep-virt-engine/server/event.go @@ -0,0 +1,28 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Event object +type Event struct { + + // Event name + Name string `json:"name,omitempty"` + + // Event type + Type_ string `json:"type,omitempty"` + + EventNetworkCharacteristicsUpdate *EventNetworkCharacteristicsUpdate `json:"eventNetworkCharacteristicsUpdate,omitempty"` + + EventUeMobility *EventUeMobility `json:"eventUeMobility,omitempty"` + + EventPoasInRange *EventPoasInRange `json:"eventPoasInRange,omitempty"` + + EventOther *EventOther `json:"eventOther,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/event_network_characteristics_update.go b/go-apps/meep-virt-engine/server/event_network_characteristics_update.go new file mode 100644 index 0000000000000000000000000000000000000000..f71642658eb313438a4fdc00dd0d1ac3ae37bfb6 --- /dev/null +++ b/go-apps/meep-virt-engine/server/event_network_characteristics_update.go @@ -0,0 +1,32 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Network Characteristics update Event object +type EventNetworkCharacteristicsUpdate struct { + + // Name of the network element to be updated + ElementName string `json:"elementName,omitempty"` + + // Type of the network element to be updated + ElementType string `json:"elementType,omitempty"` + + // Latency in ms + Latency int32 `json:"latency,omitempty"` + + // Latency variation in ms + LatencyVariation int32 `json:"latencyVariation,omitempty"` + + // Throughput limit + Throughput int32 `json:"throughput,omitempty"` + + // Packet loss percentage + PacketLoss float64 `json:"packetLoss,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/event_other.go b/go-apps/meep-virt-engine/server/event_other.go new file mode 100644 index 0000000000000000000000000000000000000000..50e4317485f8fc9438ceee5adc6cb0dffe24e019 --- /dev/null +++ b/go-apps/meep-virt-engine/server/event_other.go @@ -0,0 +1,17 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Other Event object +type EventOther struct { + + // Other event string + Event string `json:"event,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/event_poas_in_range.go b/go-apps/meep-virt-engine/server/event_poas_in_range.go new file mode 100644 index 0000000000000000000000000000000000000000..d19d683d270bdfa2c192ca221e6ca3b4a0d162f2 --- /dev/null +++ b/go-apps/meep-virt-engine/server/event_poas_in_range.go @@ -0,0 +1,19 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// POAs In Range Event object +type EventPoasInRange struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + PoasInRange []string `json:"poasInRange,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/event_ue_mobility.go b/go-apps/meep-virt-engine/server/event_ue_mobility.go new file mode 100644 index 0000000000000000000000000000000000000000..61ec4ee92b7ee18f43141caa425a7f855c6dbbe1 --- /dev/null +++ b/go-apps/meep-virt-engine/server/event_ue_mobility.go @@ -0,0 +1,20 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// UE Mobility Event object +type EventUeMobility struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + // Destination identifier + Dest string `json:"dest,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/external_config.go b/go-apps/meep-virt-engine/server/external_config.go new file mode 100644 index 0000000000000000000000000000000000000000..bd5a9e979da304324fa5d6b197e70356a840f95f --- /dev/null +++ b/go-apps/meep-virt-engine/server/external_config.go @@ -0,0 +1,17 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// External Process configuration. NOTE: Only valid if 'isExternal' is set. +type ExternalConfig struct { + IngressServiceMap []ServiceMap `json:"ingressServiceMap,omitempty"` + + EgressServiceMap []ServiceMap `json:"egressServiceMap,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/logger.go b/go-apps/meep-virt-engine/server/logger.go new file mode 100644 index 0000000000000000000000000000000000000000..f1d0b5d8536d42ce4d4829629511841e4273c606 --- /dev/null +++ b/go-apps/meep-virt-engine/server/logger.go @@ -0,0 +1,32 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + log.Printf( + "%s %s %s %s", + r.Method, + r.RequestURI, + name, + time.Since(start), + ) + }) +} diff --git a/go-apps/meep-virt-engine/server/network_location.go b/go-apps/meep-virt-engine/server/network_location.go new file mode 100644 index 0000000000000000000000000000000000000000..41aa67dbc47646e471535f0f7092571b87fe5320 --- /dev/null +++ b/go-apps/meep-virt-engine/server/network_location.go @@ -0,0 +1,37 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Logical network location object +type NetworkLocation struct { + + // Unique network location ID + Id string `json:"id,omitempty"` + + // Network location name + Name string `json:"name,omitempty"` + + // Network location type + Type_ string `json:"type,omitempty"` + + // Latency in ms for all terminal links within network location + TerminalLinkLatency int32 `json:"terminalLinkLatency,omitempty"` + + // Latency variation in ms for all terminal links within network location + TerminalLinkLatencyVariation int32 `json:"terminalLinkLatencyVariation,omitempty"` + + // The limit of the traffic supported for all terminal links within the network location + TerminalLinkThroughput int32 `json:"terminalLinkThroughput,omitempty"` + + // Packet lost (in terms of percentage) for all terminal links within the network location + TerminalLinkPacketLoss float64 `json:"terminalLinkPacketLoss,omitempty"` + + PhysicalLocations []PhysicalLocation `json:"physicalLocations,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/physical_location.go b/go-apps/meep-virt-engine/server/physical_location.go new file mode 100644 index 0000000000000000000000000000000000000000..a9ff78d9bd8e10870cefa334f8816bde9b22eb68 --- /dev/null +++ b/go-apps/meep-virt-engine/server/physical_location.go @@ -0,0 +1,30 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Physical location object +type PhysicalLocation struct { + + // Unique physical location ID + Id string `json:"id,omitempty"` + + // Physical location name + Name string `json:"name,omitempty"` + + // Physical location type + Type_ string `json:"type,omitempty"` + + // true: Physical location is external to MEEP false: Physical location is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + NetworkLocationsInRange []string `json:"networkLocationsInRange,omitempty"` + + Processes []Process `json:"processes,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/process.go b/go-apps/meep-virt-engine/server/process.go new file mode 100644 index 0000000000000000000000000000000000000000..d0c7aa7d83f3bc99dd151a2fa240c6efbb4e7619 --- /dev/null +++ b/go-apps/meep-virt-engine/server/process.go @@ -0,0 +1,54 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Application or service object +type Process struct { + + // Unique process ID + Id string `json:"id,omitempty"` + + // Process name + Name string `json:"name,omitempty"` + + // Process type + Type_ string `json:"type,omitempty"` + + // true: process is external to MEEP false: process is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + // Docker image to deploy inside MEEP + Image string `json:"image,omitempty"` + + // Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" + Environment string `json:"environment,omitempty"` + + // Arguments to command executable + CommandArguments string `json:"commandArguments,omitempty"` + + // Executable to invoke at container start up + CommandExe string `json:"commandExe,omitempty"` + + ServiceConfig *ServiceConfig `json:"serviceConfig,omitempty"` + + ExternalConfig *ExternalConfig `json:"externalConfig,omitempty"` + + // Process status + Status string `json:"status,omitempty"` + + // Chart location for the deployment of the chart provided by the user + UserChartLocation string `json:"userChartLocation,omitempty"` + + // Chart values.yaml file location for the deployment of the chart provided by the user + UserChartAlternateValues string `json:"userChartAlternateValues,omitempty"` + + // Chart supplemental information related to the group (service) + UserChartGroup string `json:"userChartGroup,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/release.go b/go-apps/meep-virt-engine/server/release.go new file mode 100644 index 0000000000000000000000000000000000000000..f07d9037f6e8ecce13b735223d34b1ac29beb1ca --- /dev/null +++ b/go-apps/meep-virt-engine/server/release.go @@ -0,0 +1,19 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +type Release struct { + + // Release name + Name string `json:"name,omitempty"` + + // Current release state + State string `json:"state,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/routers.go b/go-apps/meep-virt-engine/server/routers.go new file mode 100644 index 0000000000000000000000000000000000000000..88a786ff18d9e4e3f2d0cdc33d26c9adb9d011fc --- /dev/null +++ b/go-apps/meep-virt-engine/server/routers.go @@ -0,0 +1,84 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler = route.HandlerFunc + // handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "/v1/", + Index, + }, + + Route{ + "ActivateScenario", + strings.ToUpper("Post"), + "/v1/scenarios/active", + ActivateScenario, + }, + + Route{ + "GetActiveScenario", + strings.ToUpper("Get"), + "/v1/scenarios/active/{name}", + GetActiveScenario, + }, + + Route{ + "TerminateScenario", + strings.ToUpper("Delete"), + "/v1/scenarios/active/{name}", + TerminateScenario, + }, + + Route{ + "SendEvent", + strings.ToUpper("Post"), + "/v1/scenarios/active/events/{type}", + SendEvent, + }, +} diff --git a/go-apps/meep-virt-engine/server/scenario.go b/go-apps/meep-virt-engine/server/scenario.go new file mode 100644 index 0000000000000000000000000000000000000000..f9690d36ad0a762215272c27723a1f6752976e18 --- /dev/null +++ b/go-apps/meep-virt-engine/server/scenario.go @@ -0,0 +1,21 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Scenario object +type Scenario struct { + + // Unique scenario name + Name string `json:"name,omitempty"` + + Config *ScenarioConfig `json:"config,omitempty"` + + Deployment *Deployment `json:"deployment,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/scenario_config.go b/go-apps/meep-virt-engine/server/scenario_config.go new file mode 100644 index 0000000000000000000000000000000000000000..5553fee979b7e52497beb228d6f8d90639d7bfae --- /dev/null +++ b/go-apps/meep-virt-engine/server/scenario_config.go @@ -0,0 +1,20 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Scenario configuration +type ScenarioConfig struct { + + // Visualization configuration + Visualization string `json:"visualization,omitempty"` + + // Other scenario configuration + Other string `json:"other,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/scenario_deployment_api.go b/go-apps/meep-virt-engine/server/scenario_deployment_api.go new file mode 100644 index 0000000000000000000000000000000000000000..c1b111fc48d052ecafe1ee9e67f7bb9121c6f759 --- /dev/null +++ b/go-apps/meep-virt-engine/server/scenario_deployment_api.go @@ -0,0 +1,26 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func ActivateScenario(w http.ResponseWriter, r *http.Request) { + veActivateScenario(w, r) +} + +func GetActiveScenario(w http.ResponseWriter, r *http.Request) { + veGetActiveScenario(w, r) +} + +func TerminateScenario(w http.ResponseWriter, r *http.Request) { + veTerminateScenario(w, r) +} diff --git a/go-apps/meep-virt-engine/server/scenario_execution_api.go b/go-apps/meep-virt-engine/server/scenario_execution_api.go new file mode 100644 index 0000000000000000000000000000000000000000..7449cff73c68da41b49159097245bb227aff5712 --- /dev/null +++ b/go-apps/meep-virt-engine/server/scenario_execution_api.go @@ -0,0 +1,18 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +import ( + "net/http" +) + +func SendEvent(w http.ResponseWriter, r *http.Request) { + veSendEvent(w, r) +} diff --git a/go-apps/meep-virt-engine/server/service_config.go b/go-apps/meep-virt-engine/server/service_config.go new file mode 100644 index 0000000000000000000000000000000000000000..04ad83941be7af9076784566af5ca2c5c0f18875 --- /dev/null +++ b/go-apps/meep-virt-engine/server/service_config.go @@ -0,0 +1,22 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Service object +type ServiceConfig struct { + + // Unique service name + Name string `json:"name,omitempty"` + + // Multi-Edge service name, if any + MeSvcName string `json:"meSvcName,omitempty"` + + Ports []ServicePort `json:"ports,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/service_map.go b/go-apps/meep-virt-engine/server/service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..9219f1d69dec97694b29f17eb2deb8baf3dca80e --- /dev/null +++ b/go-apps/meep-virt-engine/server/service_map.go @@ -0,0 +1,29 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Mapping of exposed ports to internal or external services +type ServiceMap struct { + + // Service name + Name string `json:"name,omitempty"` + + // Service IP address for external service only (egress)
  • N/A for internal services + Ip string `json:"ip,omitempty"` + + // Service port number + Port int32 `json:"port,omitempty"` + + // Port used to expose internal service only (ingress)
  • Must be unique port in range (30000 - 32767)
  • N/A for external services + ExternalPort int32 `json:"externalPort,omitempty"` + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/service_port.go b/go-apps/meep-virt-engine/server/service_port.go new file mode 100644 index 0000000000000000000000000000000000000000..63f04d929b010822ea406e610abea345eadf6d9b --- /dev/null +++ b/go-apps/meep-virt-engine/server/service_port.go @@ -0,0 +1,23 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Service port object +type ServicePort struct { + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` + + // Port number that the service is listening on + Port int32 `json:"port,omitempty"` + + // External port number on which to expose the application (30000 - 32767)
  • Only one application allowed per external port
  • Scenario builder must configure to prevent conflicts + ExternalPort int32 `json:"externalPort,omitempty"` +} diff --git a/go-apps/meep-virt-engine/server/virt-engine.go b/go-apps/meep-virt-engine/server/virt-engine.go new file mode 100644 index 0000000000000000000000000000000000000000..2451db8d076a7a52b60389f26cb239d1217c8e88 --- /dev/null +++ b/go-apps/meep-virt-engine/server/virt-engine.go @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +package server + +import ( + "encoding/json" + "net/http" + "os" + "strings" + + "github.com/gorilla/mux" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/helm" + log "github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-virt-engine/log" +) + +func VirtEngineInit() { + log.Debug("Initializing MEEP Virtualization Engine") +} + +// func readAndPrintRequest(r *http.Request) { +// +// // Read the Body content +// var bodyBytes []byte +// bodyBytes, _ = ioutil.ReadAll(r.Body) +// log.Info(bodyBytes) +// +// // Restore the io.ReadCloser to its original state +// r.Body = ioutil.NopCloser(bytes.NewBuffer(bodyBytes)) +// +// } + +func populateScenario(r *http.Request) (Scenario, error) { + + log.Debug("populateScenario") + + var scenario Scenario + + //readAndPrintRequest(r) + + decoder := json.NewDecoder(r.Body) + err := decoder.Decode(&scenario) + + if err != nil { + log.Error(err.Error()) + return scenario, err + } + + return scenario, nil +} + +func veActivateScenario(w http.ResponseWriter, r *http.Request) { + scenario, err := populateScenario(r) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + err = CreateYamlScenarioFile(scenario) + if err == nil { + w.WriteHeader(http.StatusOK) + } else { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} + +func veGetActiveScenario(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func veSendEvent(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) +} + +func veTerminateScenario(w http.ResponseWriter, r *http.Request) { + // Read Parameters + vars := mux.Vars(r) + name := vars["name"] + + // Retrieve list of releases + rels, _ := helm.GetReleasesName() + var toDelete []helm.Chart + for _, rel := range rels { + if strings.Contains(rel.Name, name) { + // just keep releases related to the current scenario + var c helm.Chart + c.ReleaseName = rel.Name + toDelete = append(toDelete, c) + } + } + + // Delete releases + if len(toDelete) > 0 { + err := helm.DeleteReleases(toDelete) + log.Debug(err) + } + + // Then delete charts + homePath := os.Getenv("HOME") + path := homePath + "/.meep/active/" + name + if _, err := os.Stat(path); err == nil { + log.Debug("Removing charts ", path) + os.RemoveAll(path) + } + + w.WriteHeader(http.StatusOK) +} diff --git a/go-apps/meep-virt-engine/server/zone.go b/go-apps/meep-virt-engine/server/zone.go new file mode 100644 index 0000000000000000000000000000000000000000..ad9809ae3fbbf23652e962eb388404e05befff50 --- /dev/null +++ b/go-apps/meep-virt-engine/server/zone.go @@ -0,0 +1,61 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package server + +// Logical zone (MEC network) object +type Zone struct { + + // Unique zone ID + Id string `json:"id,omitempty"` + + // Zone name + Name string `json:"name,omitempty"` + + // Zone type + Type_ string `json:"type,omitempty"` + + // Latency in ms between fog nodes (or PoAs) within zone + InterFogLatency int32 `json:"interFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) within zone + InterFogLatencyVariation int32 `json:"interFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) within the zone + InterFogThroughput int32 `json:"interFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone + InterFogPacketLoss float64 `json:"interFogPacketLoss,omitempty"` + + // Latency in ms between edge nodes within zone + InterEdgeLatency int32 `json:"interEdgeLatency,omitempty"` + + // Latency variation in ms between edge nodes within zone + InterEdgeLatencyVariation int32 `json:"interEdgeLatencyVariation,omitempty"` + + // The limit of the traffic supported between edge nodes within the zone + InterEdgeThroughput int32 `json:"interEdgeThroughput,omitempty"` + + // Packet lost (in terms of percentage) between edge nodes within the zone + InterEdgePacketLoss float64 `json:"interEdgePacketLoss,omitempty"` + + // Latency in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatency int32 `json:"edgeFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatencyVariation int32 `json:"edgeFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogThroughput int32 `json:"edgeFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogPacketLoss float64 `json:"edgeFogPacketLoss,omitempty"` + + NetworkLocations []NetworkLocation `json:"networkLocations,omitempty"` +} diff --git a/go-apps/meep-webhook/Dockerfile b/go-apps/meep-webhook/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..eb7ed25466353fe2609aec0b65d34fcce6ebecf5 --- /dev/null +++ b/go-apps/meep-webhook/Dockerfile @@ -0,0 +1,10 @@ +# Copyright (c) 2019 +# InterDigital Communications, Inc. +# All rights reserved. +# +# The information provided herein is the proprietary and confidential +# information of InterDigital Communications, Inc. + +FROM debian:9.6-slim +ADD meep-webhook /meep-webhook +ENTRYPOINT /meep-webhook diff --git a/go-apps/meep-webhook/db.go b/go-apps/meep-webhook/db.go new file mode 100755 index 0000000000000000000000000000000000000000..08627ad2c19568d9deb908f6f94cf03916208201 --- /dev/null +++ b/go-apps/meep-webhook/db.go @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "errors" + "net" + "reflect" + "time" + + log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger" + + "github.com/KromDaniel/rejonson" + "github.com/go-redis/redis" +) + +var dbClient *rejonson.Client +var dbClientStarted = false + +var pubsub *redis.PubSub + +// DBConnect - Establish connection to DB +func DBConnect() error { + if !dbClientStarted { + err := openDB() + if err != nil { + return err + } + } + return nil +} + +func openDB() error { + + redisClient := redis.NewClient(&redis.Options{ + Addr: "meep-redis-master:6379", + Password: "", // no password set + DB: 0, // use default DB + }) + rejonsonClient := rejonson.ExtendClient(redisClient) + + pong, err := rejonsonClient.Ping().Result() + + if pong == "" { + log.Info("pong is null") + return err + } + + if err != nil { + log.Info("Redis DB not accessible") + return err + } + dbClientStarted = true + dbClient = rejonsonClient + log.Info("Redis DB opened and well!") + return nil +} + +// // DBFlush - Empty DB +// func DBFlush(module string) error { +// var cursor uint64 +// var err error +// log.Debug("DBFlush module: ", module) + +// // Find all module keys +// // Process in chunks of 50 matching entries to optimize processing speed & memory +// keyMatchStr := module + ":*" +// for { +// var keys []string +// keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() +// if err != nil { +// log.Debug("ERROR: ", err) +// break +// } + +// // Delete all matching entries +// if len(keys) > 0 { +// _, err = dbClient.Del(keys...).Result() +// if err != nil { +// log.Debug("Failed to retrieve entry fields") +// break +// } +// } + +// // Stop searching if cursor is back at beginning +// if cursor == 0 { +// break +// } +// } + +// return nil +// } + +// // DBForEachEntry - Search for matching keys and run handler for each entry +// func DBForEachEntry(keyMatchStr string, entryHandler func(string, map[string]string, interface{}) error, userData interface{}) error { +// var cursor uint64 +// var err error + +// // Process in chunks of 50 matching entries to optimize processing speed & memory +// for { +// var keys []string +// keys, cursor, err = dbClient.Scan(cursor, keyMatchStr, 50).Result() +// if err != nil { +// log.Debug("ERROR: ", err) +// break +// } + +// if len(keys) > 0 { +// for i := 0; i < len(keys); i++ { +// fields, err := dbClient.HGetAll(keys[i]).Result() +// if err != nil || fields == nil { +// log.Debug("Failed to retrieve entry fields") +// break +// } + +// // Invoke handler to process entry +// err = entryHandler(keys[i], fields, userData) +// if err != nil { +// return err +// } +// } +// } + +// // Stop searching if cursor is back at beginning +// if cursor == 0 { +// break +// } +// } +// return nil +// } + +// // DBSetEntry - Update existing entry or create new entry if it does not exist +// func DBSetEntry(key string, fields map[string]interface{}) error { +// // Update existing entry or create new entry if it does not exist +// _, err := dbClient.HMSet(key, fields).Result() +// if err != nil { +// return err +// } +// return nil +// } + +// // DBRemoveEntry - Remove entry from DB +// func DBRemoveEntry(key string) error { +// _, err := dbClient.Del(key).Result() +// if err != nil { +// return err +// } +// return nil +// } + +// DBJsonGetEntry - Retrieve entry from DB +func DBJsonGetEntry(key string, path string) (string, error) { + // Update existing entry or create new entry if it does not exist + json, err := dbClient.JsonGet(key, path).Result() + if err != nil { + return "", err + } + return json, nil +} + +// // DBJsonSetEntry - Update existing entry or create new entry if it does not exist +// func DBJsonSetEntry(key string, path string, json string) error { +// // Update existing entry or create new entry if it does not exist +// _, err := dbClient.JsonSet(key, path, json).Result() +// if err != nil { +// return err +// } +// return nil +// } + +// // DBJsonDelEntry - Remove existing entry +// func DBJsonDelEntry(key string, path string) error { +// _, err := dbClient.JsonDel(key, path).Result() +// if err != nil { +// return err +// } +// return nil +// } + +// Subscribe - Register as a listener for provided channels +func Subscribe(channels ...string) error { + pubsub = dbClient.Subscribe(channels...) + return nil +} + +// Listen - Wait for subscribed events +func Listen(handler func(string, string)) error { + + // Make sure listener is subscribed to pubsub + if pubsub == nil { + return errors.New("Not subscribed to pubsub") + } + + // Main listening loop + for { + // Wait for subscribed channel events, or timeout + msg, err := pubsub.ReceiveTimeout(time.Second) + if err != nil { + if reflect.TypeOf(err) == reflect.TypeOf(&net.OpError{}) && + reflect.TypeOf(err.(*net.OpError).Err).String() == "*net.timeoutError" { + // Timeout, ignore and wait for next event + continue + } + } + + // Process published event + switch m := msg.(type) { + + // Process Subscription + case *redis.Subscription: + log.Info("Subscription Message: ", m.Kind, " to channel ", m.Channel, ". Total subscriptions: ", m.Count) + + // Process received Message + case *redis.Message: + log.Info("MSG on ", m.Channel, ": ", m.Payload) + handler(m.Channel, m.Payload) + } + } +} + +// // Publish - Publish message to channel +// func Publish(channel string, message string) error { +// log.Info("Publish to channel: ", channel, " Message: ", message) +// _, err := dbClient.Publish(channel, message).Result() +// return err +// } diff --git a/go-apps/meep-webhook/go.mod b/go-apps/meep-webhook/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..b8887374c3ea26a7067e2487569de1248c6e4f3f --- /dev/null +++ b/go-apps/meep-webhook/go.mod @@ -0,0 +1,18 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-apps/meep-webhook + +go 1.12 + +require ( + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model v0.0.0 + github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger v0.0.0 + github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db // indirect + github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351 + github.com/ghodss/yaml v1.0.0 + github.com/go-redis/redis v6.15.2+incompatible + k8s.io/api v0.0.0-20190430012547-97d6bb8ea5f4 + k8s.io/apimachinery v0.0.0-20190430211124-5bae42371a56 +) + +replace github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model => ../../go-packages/meep-ctrl-engine-model + +replace github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger => ../../go-packages/meep-logger diff --git a/go-apps/meep-webhook/go.sum b/go-apps/meep-webhook/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..29696f916c8650815a005e5859dc10450f552538 --- /dev/null +++ b/go-apps/meep-webhook/go.sum @@ -0,0 +1,83 @@ +github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db h1:Zkf5kwhxdW0xV7WM/crqIcOP5LCFGnAmumWSFAewJ74= +github.com/KromDaniel/jonson v0.0.0-20180630143114-d2f9c3c389db/go.mod h1:RU+6d0CNIRSp6yo1mXLIIrnFa/3LHhvcDVLVJyovptM= +github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351 h1:1u1XrfCBnY+GijnyU6O1k4odp5TnqZQTsp5v7+n/E4Y= +github.com/KromDaniel/rejonson v0.0.0-20180822072824-00b5bcf2b351/go.mod h1:HxwfbuElTuGf+/uKZfjJrCnv0BmmpkPJDI7gBwj1KkM= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= +github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= +github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415 h1:WSBJMqJbLxsn+bTCPyPYZfqHdJmc8MK4wrBjMft6BAM= +github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be h1:AHimNtVIpiBjPUhEF5KNCkrUyqTSA5zWUl8sQ2bfGBE= +github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3 h1:EooPXg51Tn+xmWPXJUGCnJhJSpeuMlBmfJVcqIRmmv8= +github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 h1:bfLnR+k0tq5Lqt6dflRLcZiz6UaXCMt3vhYJ1l4FQ80= +golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU= +golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o= +gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +k8s.io/api v0.0.0-20190430012547-97d6bb8ea5f4 h1:dvZWnvi47rbTIOzJp6btN9yqGVDTzYBjwSO7ZIGSUW0= +k8s.io/api v0.0.0-20190430012547-97d6bb8ea5f4/go.mod h1:a8In9/nr3+MCLEah7ICqKQl+2hN7XkJx64ugf8c+hws= +k8s.io/apimachinery v0.0.0-20190425132440-17f84483f500/go.mod h1:5CBnzrKYGHzv9ZsSKmQ8wHt4XI4/TUBPDwYM9FlZMyw= +k8s.io/apimachinery v0.0.0-20190430211124-5bae42371a56 h1:r8v9jEdT17CYfGFo+ZgV/sEnPtC1MrTaCQMSqwYq3zo= +k8s.io/apimachinery v0.0.0-20190430211124-5bae42371a56/go.mod h1:5CBnzrKYGHzv9ZsSKmQ8wHt4XI4/TUBPDwYM9FlZMyw= +k8s.io/klog v0.3.0 h1:0VPpR+sizsiivjIfIAQH/rl8tan6jvWkS7lU+0di3lE= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/go-apps/meep-webhook/main.go b/go-apps/meep-webhook/main.go new file mode 100644 index 0000000000000000000000000000000000000000..f53060490739a58bd43633a84e8feb91f19166bf --- /dev/null +++ b/go-apps/meep-webhook/main.go @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + * + * NOTICE: File content based on https://github.com/morvencao/kube-mutating-webhook-tutorial (Apache 2.0) + */ + +package main + +import ( + "context" + "crypto/tls" + "flag" + "fmt" + "net/http" + "os" + "os/signal" + "syscall" + + log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger" +) + +func main() { + var parameters WhSvrParameters + + // Initialize logging + log.MeepJSONLogInit("meep-webhook") + + // Connect to Active DB + err := activeDBConnect() + if err != nil { + log.Error("Failed to connect to Active DB: ", err.Error()) + return + } + + // get command line parameters + flag.IntVar(¶meters.port, "port", 443, "Webhook server port.") + flag.StringVar(¶meters.certFile, "tlsCertFile", "/etc/webhook/certs/cert.pem", "File containing the x509 Certificate for HTTPS.") + flag.StringVar(¶meters.keyFile, "tlsKeyFile", "/etc/webhook/certs/key.pem", "File containing the x509 private key to --tlsCertFile.") + flag.StringVar(¶meters.sidecarCfgFile, "sidecarCfgFile", "/etc/webhook/config/sidecarconfig.yaml", "File containing the mutation configuration.") + flag.Parse() + + // Load Sidecar config + sidecarConfig, err := loadConfig(parameters.sidecarCfgFile) + if err != nil { + log.Error("Failed to load configuration: ", err.Error()) + } + + // Load & configure certificates + pair, err := tls.LoadX509KeyPair(parameters.certFile, parameters.keyFile) + if err != nil { + log.Error("Failed to load key pair: ", err.Error()) + return + } + + whsvr := &WebhookServer{ + sidecarConfig: sidecarConfig, + server: &http.Server{ + Addr: fmt.Sprintf(":%v", parameters.port), + TLSConfig: &tls.Config{Certificates: []tls.Certificate{pair}}, + }, + } + + // Define http server and server handler + mux := http.NewServeMux() + mux.HandleFunc("/mutate", whsvr.serve) + whsvr.server.Handler = mux + + // Start DB listener in new routine + go activeDBListen() + + // Start webhook server in new routine + go func() { + if err := whsvr.server.ListenAndServeTLS("", ""); err != nil { + log.Error("Failed to listen and serve webhook server: ", err.Error()) + } + }() + + // Listen for OS shutdown singal + signalChan := make(chan os.Signal, 1) + signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) + <-signalChan + + log.Info("Got OS shutdown signal, shutting down webhook server gracefully...") + _ = whsvr.server.Shutdown(context.Background()) +} diff --git a/go-apps/meep-webhook/webhook.go b/go-apps/meep-webhook/webhook.go new file mode 100644 index 0000000000000000000000000000000000000000..83532168e7c148ae7ede3f590e750b82e0fa018d --- /dev/null +++ b/go-apps/meep-webhook/webhook.go @@ -0,0 +1,411 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + * + * NOTICE: File content based on https://github.com/morvencao/kube-mutating-webhook-tutorial (Apache 2.0) + */ + +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + + ceModel "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model" + log "github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger" + + "github.com/ghodss/yaml" + "k8s.io/api/admission/v1beta1" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" +) + +const moduleCtrlEngine string = "ctrl-engine" +const typeActive string = "active" +const channelCtrlActive string = moduleCtrlEngine + "-" + typeActive +const meepOrigin = "scenario" + +// Active scenarion name +var activeScenarioName string + +var ( + runtimeScheme = runtime.NewScheme() + codecs = serializer.NewCodecFactory(runtimeScheme) + deserializer = codecs.UniversalDeserializer() +) + +type WebhookServer struct { + sidecarConfig *Config + server *http.Server +} + +// Webhook Server parameters +type WhSvrParameters struct { + port int // webhook server port + certFile string // path to the x509 certificate for https + keyFile string // path to the x509 private key matching `CertFile` + sidecarCfgFile string // path to sidecar injector configuration file +} + +type Config struct { + Containers []corev1.Container `yaml:"containers"` + Volumes []corev1.Volume `yaml:"volumes"` +} + +type patchOperation struct { + Op string `json:"op"` + Path string `json:"path"` + Value interface{} `json:"value,omitempty"` +} + +func init() { + _ = corev1.AddToScheme(runtimeScheme) + _ = admissionregistrationv1beta1.AddToScheme(runtimeScheme) +} + +func activeDBConnect() (err error) { + // Connect to Active DB + err = DBConnect() + if err != nil { + log.Error("Failed connection to Active DB. Error: ", err) + return err + } + log.Info("Connected to Active DB") + + // Subscribe to Pub-Sub events for MEEP Controller + // NOTE: Current implementation is RedisDB Pub-Sub + err = Subscribe(channelCtrlActive) + if err != nil { + log.Error("Failed to subscribe to Pub/Sub events. Error: ", err) + return + } + log.Info("Subscribed to Pub/Sub events") + + // Initialize using current active scenario + processActiveScenarioUpdate() + + return nil +} + +func activeDBListen() { + // Listen for subscribed events. Provide event handler method. + _ = Listen(eventHandler) +} + +func eventHandler(channel string, payload string) { + // Handle Message according to Rx Channel + switch channel { + + // MEEP Ctrl Engine active scenario update Channel + case channelCtrlActive: + log.Debug("Event received on channel: ", channelCtrlActive) + processActiveScenarioUpdate() + + default: + log.Warn("Unsupported channel") + } +} + +func processActiveScenarioUpdate() { + // Retrieve active scenario from DB + jsonScenario, err := DBJsonGetEntry(moduleCtrlEngine+":"+typeActive, ".") + if err != nil { + log.Error(err.Error()) + clearScenario() + return + } + + // Unmarshal Active scenario + var scenario ceModel.Scenario + err = json.Unmarshal([]byte(jsonScenario), &scenario) + if err != nil { + log.Error(err.Error()) + clearScenario() + return + } + + // Parse scenario + parseScenario(scenario) +} + +func clearScenario() { + log.Debug("clearScenario() -- Resetting all variables") + activeScenarioName = "" +} + +func parseScenario(scenario ceModel.Scenario) { + log.Debug("parseScenario") + + // Update active scenatio name + activeScenarioName = scenario.Name + log.Info("Active scenario name set to: ", activeScenarioName) +} + +func loadConfig(configFile string) (*Config, error) { + data, err := ioutil.ReadFile(configFile) + if err != nil { + return nil, err + } + var cfg Config + if err := yaml.Unmarshal(data, &cfg); err != nil { + return nil, err + } + return &cfg, nil +} + +// Retrieve App Name from provided network element name string, if any +func getAppName(name string) string { + names := bytes.Split([]byte(name), []byte(activeScenarioName+"-")) + if len(names) != 2 { + return "" + } + return string(names[1]) +} + +func getSidecarPatch(template corev1.PodTemplateSpec, sidecarConfig *Config, meepAppName string) (patch []byte, err error) { + + // Apply labels + newLabels := make(map[string]string) + newLabels["meepApp"] = meepAppName + newLabels["meepOrigin"] = meepOrigin + newLabels["meepScenario"] = activeScenarioName + newLabels["processId"] = meepAppName + + // Add environment variables to sidecar containers + var envVars []corev1.EnvVar + var envVar corev1.EnvVar + envVar.Name = "MEEP_POD_NAME" + envVar.Value = meepAppName + envVars = append(envVars, envVar) + + var sidecarContainers []corev1.Container + for _, container := range sidecarConfig.Containers { + container.Env = envVars + sidecarContainers = append(sidecarContainers, container) + } + + // Create patch operations + var patchOps []patchOperation + patchOps = append(patchOps, addContainer(template.Spec.Containers, sidecarContainers, "/spec/template/spec/containers")...) + patchOps = append(patchOps, addVolume(template.Spec.Volumes, sidecarConfig.Volumes, "/spec/template/spec/volumes")...) + patchOps = append(patchOps, updateLabels(template.ObjectMeta.Labels, newLabels, "/spec/template/metadata/labels")...) + + // Serialize patch + patch, err = json.Marshal(patchOps) + if err != nil { + return nil, err + } + + return patch, nil +} + +func addContainer(target, added []corev1.Container, basePath string) (patch []patchOperation) { + first := len(target) == 0 + var value interface{} + for _, add := range added { + value = add + path := basePath + if first { + first = false + value = []corev1.Container{add} + } else { + path = path + "/-" + } + + patch = append(patch, patchOperation{ + Op: "add", + Path: path, + Value: value, + }) + } + return patch +} + +func addVolume(target, added []corev1.Volume, basePath string) (patch []patchOperation) { + first := len(target) == 0 + var value interface{} + for _, add := range added { + value = add + path := basePath + if first { + first = false + value = []corev1.Volume{add} + } else { + path = path + "/-" + } + patch = append(patch, patchOperation{ + Op: "add", + Path: path, + Value: value, + }) + } + return patch +} + +func updateLabels(target map[string]string, added map[string]string, basePath string) (patch []patchOperation) { + for key, value := range added { + path := basePath + "/" + key + op := "add" + if target != nil && target[key] != "" { + op = "replace" + } + patch = append(patch, patchOperation{ + Op: op, + Path: path, + Value: value, + }) + } + return patch +} + +// main mutation process +func (whsvr *WebhookServer) mutate(ar *v1beta1.AdmissionReview) *v1beta1.AdmissionResponse { + req := ar.Request + log.Info("Mutate request Name[", req.Name, "] Kind[", req.Kind, "] Namespace[", req.Namespace, "]") + + // Ignore if no active scenario + if activeScenarioName == "" { + log.Info("No active scenario. Ignoring request...") + return &v1beta1.AdmissionResponse{ + Allowed: true, + } + } + + // Retrieve resource-specific information + var resourceName string + var template corev1.PodTemplateSpec + + switch req.Kind.Kind { + case "Deployment": + // Unmarshal Deployment + var deployment appsv1.Deployment + if err := json.Unmarshal(req.Object.Raw, &deployment); err != nil { + log.Error("Could not unmarshal raw object: ", err.Error()) + return &v1beta1.AdmissionResponse{ + Result: &metav1.Status{ + Message: err.Error(), + }, + } + } + log.Info("Deployment Name: ", deployment.Name) + resourceName = deployment.Name + template = deployment.Spec.Template + + case "StatefulSet": + // Unmarshal StatefulSet + var statefulset appsv1.StatefulSet + if err := json.Unmarshal(req.Object.Raw, &statefulset); err != nil { + log.Error("Could not unmarshal raw object: ", err.Error()) + return &v1beta1.AdmissionResponse{ + Result: &metav1.Status{ + Message: err.Error(), + }, + } + } + log.Info("StatefulSet Name: ", statefulset.Name) + resourceName = statefulset.Name + template = statefulset.Spec.Template + + default: + log.Info("Unsupported admission request Kind[", req.Kind.Kind, "]") + return &v1beta1.AdmissionResponse{ + Allowed: true, + } + } + + // Retrieve App Name from resource name + meepAppName := getAppName(resourceName) + if meepAppName == "" { + log.Info("Resource not part of active scenario. Ignoring request...") + return &v1beta1.AdmissionResponse{ + Allowed: true, + } + } + log.Info("MEEP App Name: ", meepAppName) + + // Get sidecar patch + patch, err := getSidecarPatch(template, whsvr.sidecarConfig, meepAppName) + if err != nil { + return &v1beta1.AdmissionResponse{ + Result: &metav1.Status{ + Message: err.Error(), + }, + } + } + + log.Debug("AdmissionResponse: patch=", string(patch)) + return &v1beta1.AdmissionResponse{ + Allowed: true, + Patch: patch, + PatchType: func() *v1beta1.PatchType { + pt := v1beta1.PatchTypeJSONPatch + return &pt + }(), + } +} + +// Serve method for webhook server +func (whsvr *WebhookServer) serve(w http.ResponseWriter, r *http.Request) { + var body []byte + if r.Body != nil { + if data, err := ioutil.ReadAll(r.Body); err == nil { + body = data + } + } + if len(body) == 0 { + log.Error("empty body") + http.Error(w, "empty body", http.StatusBadRequest) + return + } + + // verify the content type is accurate + contentType := r.Header.Get("Content-Type") + if contentType != "application/json" { + log.Error("Content-Type=", contentType, ", expect application/json") + http.Error(w, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType) + return + } + + var admissionResponse *v1beta1.AdmissionResponse + ar := v1beta1.AdmissionReview{} + if _, _, err := deserializer.Decode(body, nil, &ar); err != nil { + log.Error("Can't decode body: ", err.Error()) + admissionResponse = &v1beta1.AdmissionResponse{ + Result: &metav1.Status{ + Message: err.Error(), + }, + } + } else { + admissionResponse = whsvr.mutate(&ar) + } + + admissionReview := v1beta1.AdmissionReview{} + if admissionResponse != nil { + admissionReview.Response = admissionResponse + if ar.Request != nil { + admissionReview.Response.UID = ar.Request.UID + } + } + + resp, err := json.Marshal(admissionReview) + if err != nil { + log.Error("Can't encode response: ", err.Error()) + http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError) + } + log.Info("Ready to write reponse ...") + if _, err := w.Write(resp); err != nil { + log.Error("Can't write response: ", err.Error()) + http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError) + } +} diff --git a/go-apps/meepctl/.gitignore b/go-apps/meepctl/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4ae45c82c35890c6ee7f76026d71fda3f1dd7f6c --- /dev/null +++ b/go-apps/meepctl/.gitignore @@ -0,0 +1,3 @@ +cypress/screenshots +cypress/videos +coverage \ No newline at end of file diff --git a/go-apps/meepctl/LICENSE b/go-apps/meepctl/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..d07713ac2e05969b9e6a6d475ad2ddcdce5e4677 --- /dev/null +++ b/go-apps/meepctl/LICENSE @@ -0,0 +1,6 @@ +Copyright (c) 2019 +InterDigital Communications, Inc. +All rights reserved. + +The information provided herein is the proprietary and confidential +information of InterDigital Communications, Inc. diff --git a/go-apps/meepctl/cmd/build.go b/go-apps/meepctl/cmd/build.go new file mode 100644 index 0000000000000000000000000000000000000000..102ef10c2ea4a664a3bf3d6702fe46a5e247cf60 --- /dev/null +++ b/go-apps/meepctl/cmd/build.go @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + "os" + "os/exec" + "time" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +var buildCodecov bool +var buildNolint bool + +// buildCmd represents the build command +var buildCmd = &cobra.Command{ + Use: "build ", + Short: "Build core components", + Long: `Build core components + +AdvantEDGE is composed of a collection of micro-services. + +Build command genrates AdvantEDGE binaries. + +Valid targets:`, + Example: `# Build all components + meepctl build all +# Build meep-ctrl-engine component only + meepctl build meep-ctrl-engine + `, + Args: cobra.ExactValidArgs(1), + // WARNING -- meep-frontend comes before meep-ctrl-engine so that "all" works + ValidArgs: []string{"all", "meep-frontend", "meep-ctrl-engine", "meep-webhook", "meep-mg-manager", "meep-mon-engine", "meep-tc-engine", "meep-tc-sidecar", "meep-virt-engine"}, + + Run: func(cmd *cobra.Command, args []string) { + target := "" + if len(args) > 0 { + target = args[0] + } + + v, _ := cmd.Flags().GetBool("verbose") + t, _ := cmd.Flags().GetBool("time") + + if v { + fmt.Println("Build called") + fmt.Println("[arg] target:", target) + fmt.Println("[flag] codecov:", buildCodecov) + fmt.Println("[flag] verbose:", v) + fmt.Println("[flag] time:", t) + } + + start := time.Now() + utils.InitRepoConfig() + if target == "all" { + buildAll(cmd) + } else { + build(target, cmd) + } + + elapsed := time.Since(start) + if t { + fmt.Println("Took ", elapsed.Round(time.Millisecond).String()) + } + }, +} + +func init() { + var argsStr string + for _, arg := range buildCmd.ValidArgs { + argsStr += "\n * " + arg + } + buildCmd.Long += argsStr + + rootCmd.AddCommand(buildCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // buildCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // buildCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + buildCmd.Flags().BoolVar(&buildCodecov, "codecov", false, "Build a code coverage binary (dev. option)") + buildCmd.Flags().BoolVar(&buildNolint, "nolint", false, "Disable linting") +} + +func buildAll(cobraCmd *cobra.Command) { + for _, target := range cobraCmd.ValidArgs { + if target == "all" { + continue + } + build(target, cobraCmd) + fmt.Println("") + } +} + +func build(targetName string, cobraCmd *cobra.Command) { + target := utils.RepoCfg.GetStringMapString("repo.core." + targetName) + if len(target) == 0 { + fmt.Println("Invalid target:", targetName) + return + } + + if targetName == "meep-frontend" { + buildFrontend(targetName, cobraCmd) + } else { + buildGoApp(targetName, cobraCmd) + } +} + +func buildFrontend(targetName string, cobraCmd *cobra.Command) { + fmt.Println("--", targetName, "--") + target := utils.RepoCfg.GetStringMapString("repo.core." + targetName) + gitDir := viper.GetString("meep.gitdir") + srcDir := gitDir + "/" + target["src"] + binDir := gitDir + "/" + target["bin"] + lintEnabled := utils.RepoCfg.GetBool("repo.core." + targetName + ".lint") + + // dependencies + fmt.Println(" + checking external dependencies") + cmd := exec.Command("npm", "ci") + cmd.Dir = srcDir + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + + locDeps := utils.RepoCfg.GetStringMapString("repo.core." + targetName + ".local-deps") + if len(locDeps) > 0 { + fmt.Println(" + checking local dependencies") + for dep, depDir := range locDeps { + fmt.Println(" * " + dep) + cmd := exec.Command("npm", "ci") + cmd.Dir = gitDir + "/" + depDir + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + } + } + + // remove old binDir if exists + if _, err := os.Stat(binDir); !os.IsNotExist(err) { + cmd = exec.Command("rm", "-r", binDir) + cmd.Dir = srcDir + out, err = utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + } + + // linter: ESLint + if lintEnabled && !buildNolint { + fmt.Println(" + running linter") + cmd := exec.Command("eslint", "src/js/") + cmd.Dir = srcDir + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + fmt.Println("Linting failed. Exiting...") + fmt.Println("To skip linting run build with --nolint") + return + } + } + + //build + fmt.Println(" + building " + targetName) + cmd = exec.Command("npm", "run", "build", "--", "--output-path="+binDir) + cmd.Dir = srcDir + out, err = utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } +} + +func buildGoApp(targetName string, cobraCmd *cobra.Command) { + fmt.Println("--", targetName, "--") + target := utils.RepoCfg.GetStringMapString("repo.core." + targetName) + gitDir := viper.GetString("meep.gitdir") + srcDir := gitDir + "/" + target["src"] + binDir := gitDir + "/" + target["bin"] + codecovCapable := utils.RepoCfg.GetBool("repo.core." + targetName + ".codecov") + lintEnabled := utils.RepoCfg.GetBool("repo.core." + targetName + ".lint") + + // dependencies + fmt.Println(" + checking external dependencies") + cmd := exec.Command("go", "mod", "vendor") + cmd.Dir = srcDir + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + + // linter: goloangci-lint + if lintEnabled && !buildNolint { + fmt.Println(" + running linter") + cmd := exec.Command("golangci-lint", "run") + cmd.Dir = srcDir + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + fmt.Println("Linting failed. Exiting...") + fmt.Println("To skip linting run build with --nolint") + return + } + } + + // for go, local dependencies are handled via the Go toolchain so nothing to do + + // Remove unnecessary deps + fixDeps(targetName, cobraCmd) + + // build + buildFlags := utils.RepoCfg.GetStringSlice("repo.core." + targetName + ".build-flags") + if buildCodecov && codecovCapable { + fmt.Println(" + building " + targetName + " (warning: development build - code coverage)") + args := []string{"test", "-covermode=count", "-coverpkg=./...", "-c"} + args = append(args, buildFlags...) + args = append(args, "-o", binDir+"/"+targetName, srcDir) + cmd = exec.Command("go", args...) + } else { + fmt.Println(" + building " + targetName) + args := []string{"build"} + args = append(args, buildFlags...) + args = append(args, "-o", binDir+"/"+targetName, srcDir) + cmd = exec.Command("go", args...) + } + cmd.Dir = srcDir + out, err = utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + + // Copy Dockerfile + cmd = exec.Command("cp", "Dockerfile", binDir) + cmd.Dir = srcDir + out, err = utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } +} + +func fixDeps(targetName string, cobraCmd *cobra.Command) { + target := utils.RepoCfg.GetStringMapString("repo.core." + targetName) + gitDir := viper.GetString("meep.gitdir") + srcDir := gitDir + "/" + target["src"] + + switch targetName { + case "meep-webhook": + cmd := exec.Command("rm", "-Rf", srcDir+"/vendor/github.com/hashicorp/golang-lru") + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + + case "meep-mon-engine": + cmd := exec.Command("rm", srcDir+"/vendor/k8s.io/client-go/tools/cache/mutation_cache.go") + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + cmd = exec.Command("rm", "-Rf", srcDir+"/vendor/github.com/hashicorp/golang-lru") + out, err = utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + } +} diff --git a/go-apps/meepctl/cmd/config.go b/go-apps/meepctl/cmd/config.go new file mode 100644 index 0000000000000000000000000000000000000000..6de5e7eaffbb985f4af2c3f25dd37744c7189eaa --- /dev/null +++ b/go-apps/meepctl/cmd/config.go @@ -0,0 +1,65 @@ +/* + + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +// configCmd represents the config command +var configCmd = &cobra.Command{ + Use: "config", + Short: "Config allows to manage meep environment configuration", + Long: `Config allows to manage meep environment configuration + +meepctl relies on a configuration file that lives here ~/.meepctl.yaml + +On first meepctl execution, the configuration file is created with default values +It then needs to be initialized once by running initial configuration command (below). +It also manages dashboards and configuration items present in Kibana. +`, + Example: ` # Initial configuration + meepctl config set --ip --gitdir + # Help on set command + meepctl config set --help + # Help on kibana command + meepctl config kibana --help`, + + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("") + fmt.Println(" PARAMETER\t\tDESCRIPTION\t\t\t CURRENT VALUE") + fmt.Println(" version\t\tconfig file version\t\t", viper.GetString("version")) + fmt.Println(" node.ip\t\tnode's IP address\t\t", viper.GetString("node.ip")) + fmt.Println(" meep.gitdir\t\tAdvantEDGE repo path\t\t", viper.GetString("meep.gitdir")) + fmt.Println(" meep.workdir\t\tRuntime storage path\t\t", viper.GetString("meep.workdir")) + fmt.Println("") + fmt.Println(cmd.Long) + fmt.Println(cmd.Example) + fmt.Println("") + }, +} + +func init() { + rootCmd.AddCommand(configCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // configCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // configCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/go-apps/meepctl/cmd/configKibana.go b/go-apps/meepctl/cmd/configKibana.go new file mode 100644 index 0000000000000000000000000000000000000000..5d9d4da20802a1a3dfa98499f0c1e299366374e1 --- /dev/null +++ b/go-apps/meepctl/cmd/configKibana.go @@ -0,0 +1,60 @@ +// Copyright © 2019 NAME HERE +// +// 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. + +package cmd + +import ( + "fmt" + "time" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + "github.com/spf13/cobra" +) + +// configKibana represents the configKibana command +var configKibana = &cobra.Command{ + Use: "kibana", + Short: "Configures Kibana (index pattern, saved objects such as dashboards, visualisations, etc.)", + Long: `Configures Kibana (index pattern, saved objects such as dashboards, visualisations, etc.) + `, + Example: ` # Configure Kibana by downloading saved objects (dashboards, visualizations, etc) and applying a default index pattern + # NOTE: Any Kibana saved object will be overwritten in the process if the object Id are the same + meepctl config kibana.`, + Run: func(cmd *cobra.Command, args []string) { + t, _ := cmd.Flags().GetBool("time") + start := time.Now() + utils.DeployKibanaDashboards(cmd) + + elapsed := time.Since(start) + if t { + fmt.Println("Took ", elapsed.Round(time.Millisecond).String()) + } + + }, +} + +func init() { + configCmd.AddCommand(configKibana) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // configKibana.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // configKibana.Flags().BoolP("toggle", "t", false, "Help message for toggle") + +} diff --git a/go-apps/meepctl/cmd/configSet.go b/go-apps/meepctl/cmd/configSet.go new file mode 100644 index 0000000000000000000000000000000000000000..3f6122623bdcaa344f61d0f7f2f891ddb68de498 --- /dev/null +++ b/go-apps/meepctl/cmd/configSet.go @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + "time" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +var ip, gitdir string // flags + +// configSet represents the set command +var configSet = &cobra.Command{ + Use: "set", + Short: "Set value(s) in the meepctl config file", + Long: `Set value(s) in the meepctl config file + `, + Example: ` # Configure IP address + meepctl config set --ip 1.2.3.4 + # Configure GIT directory + meepctl config set --gitdir /home/some-user/AdvantEDGE + # Configure GIT to local directory + IP simultaneously + meepctl config set --gitdir /home/some-user/AdvantEDGE --ip 1.2.3.4 + `, + Args: cobra.OnlyValidArgs, + ValidArgs: []string{"ip", "gitdir"}, + Run: func(cmd *cobra.Command, args []string) { + v, _ := cmd.Flags().GetBool("verbose") + t, _ := cmd.Flags().GetBool("time") + if v { + fmt.Println("config set called") + fmt.Println("[flag] ip:", ip) + fmt.Println("[flag] gitdir:", gitdir) + fmt.Println("[flag] verbose:", v) + fmt.Println("[flag] time:", t) + } + + fmt.Println("len(args)", len(args), "|| args ", args) + + start := time.Now() + if ip != "" { + valid, reason := utils.ConfigIPValid(ip) + if valid { + cfg := utils.ConfigReadFile(viper.ConfigFileUsed()) + cfg.Node.IP = ip + err := utils.ConfigWriteFile(cfg, viper.ConfigFileUsed()) + if err != nil { + fmt.Println(err) + return + } + fmt.Println("Updated node.ip with [" + ip + "]") + } else { + fmt.Println("Invalid IP: " + reason) + } + } + + if gitdir != "" { + valid, reason := utils.ConfigGitdirValid(gitdir) + if valid { + cfg := utils.ConfigReadFile(viper.ConfigFileUsed()) + cfg.Meep.Gitdir = gitdir + err := utils.ConfigWriteFile(cfg, viper.ConfigFileUsed()) + if err != nil { + fmt.Println(err) + } + fmt.Println("Updated meep.gitdir with [" + gitdir + "]") + } else { + fmt.Println("Invalid Gitdir: " + reason) + } + } + + if ip == "" && gitdir == "" { + fmt.Println("Which flag do you want to set", cmd.ValidArgs, "?") + fmt.Println() + fmt.Println(cmd.Long) + fmt.Println(cmd.Example) + } + + elapsed := time.Since(start) + if t { + fmt.Println("Took ", elapsed.Round(time.Millisecond).String()) + } + + }, +} + +func init() { + configCmd.AddCommand(configSet) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // setCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + configSet.Flags().StringVar(&ip, "ip", "", "IP address of AdvantEDGE node (local IP address)") + configSet.Flags().StringVar(&gitdir, "gitdir", "", "Path to the AdvantEDGE GIT directory") + +} diff --git a/go-apps/meepctl/cmd/delete.go b/go-apps/meepctl/cmd/delete.go new file mode 100644 index 0000000000000000000000000000000000000000..9f2ab021446f7aa0e2d7270a767bd7882d6d9f26 --- /dev/null +++ b/go-apps/meepctl/cmd/delete.go @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + "os/exec" + "time" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +// deleteCmd represents the delete command +var deleteCmd = &cobra.Command{ + Use: "delete ", + Short: "Delete containers from the K8s cluster", + Long: `Delete containers from the K8s cluster + +AdvantEDGE is composed of a collection of micro-services (a.k.a the groups). + +Delete command removes a group of containers from the K8s cluster. + +Valid groups: + * core: AdvantEDGE core containers + * dep: Dependency containers + * all: All containers + `, + Example: ` # Delete all containers + meepctl delete all + # Delete only AdvantEDGE core containers + meepctl delete core + `, + Args: cobra.ExactValidArgs(1), + ValidArgs: []string{"all", "dep", "core"}, + Run: func(cmd *cobra.Command, args []string) { + group := args[0] + v, _ := cmd.Flags().GetBool("verbose") + t, _ := cmd.Flags().GetBool("time") + if v { + fmt.Println("Delete called") + fmt.Println("[arg] group:", group) + fmt.Println("[flag] verbose:", v) + fmt.Println("[flag] time:", t) + } + + start := time.Now() + utils.InitRepoConfig() + if group == "all" { + deleteCore(cmd) + deleteDep(cmd) + } else if group == "core" { + deleteCore(cmd) + } else if group == "dep" { + deleteDep(cmd) + } + elapsed := time.Since(start) + if t { + fmt.Println("Took ", elapsed.Round(time.Millisecond).String()) + } + }, +} + +func deleteCore(cobraCmd *cobra.Command) { + k8sDelete("meep-virt-engine", cobraCmd) + deleteVirtEngine(cobraCmd) + k8sDelete("meep-webhook", cobraCmd) + k8sDelete("meep-mg-manager", cobraCmd) + k8sDelete("meep-tc-engine", cobraCmd) + k8sDelete("meep-mon-engine", cobraCmd) + k8sDelete("meep-ctrl-engine", cobraCmd) + deleteMeepUserAccount(cobraCmd) +} + +func deleteVirtEngine(cobraCmd *cobra.Command) { + pid, err := utils.GetProcess("meep-virt-engine", cobraCmd) + if err == nil { + var timeoutMsg string + start := time.Now() + // Try interrupting process first + utils.InterruptProcess(pid, cobraCmd) + err = utils.WaitProcess(pid, "5", cobraCmd) + if err != nil { + // Kill process if it did not exit before timeout + utils.KillProcess(pid, cobraCmd) + err = utils.WaitProcess(pid, "5", cobraCmd) + if err != nil { + timeoutMsg = " failed with timeout error: " + err.Error() + } + } + elapsed := time.Since(start) + r := utils.FormatResult("Deleted meep-virt-engine (ext.)"+timeoutMsg, elapsed, cobraCmd) + fmt.Println(r) + } +} + +func deleteMeepUserAccount(cobraCmd *cobra.Command) { + gitdir := viper.GetString("meep.gitdir") + + cmd := exec.Command("kubectl", "delete", "-f", gitdir+"/"+utils.RepoCfg.GetString("repo.core.meep-user.service-account")) + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + + cmd = exec.Command("kubectl", "delete", "-f", gitdir+"/"+utils.RepoCfg.GetString("repo.core.meep-user.cluster-role-binding")) + out, err = utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } +} + +func deleteDep(cobraCmd *cobra.Command) { + gitdir := viper.GetString("meep.gitdir") + "/" + + // Local storage bindings + // NOTE: Helm charts don't remove pvc for statefulsets because helm did not create them + // Run in separate threads in order to complete uninstall successfully + messages := make(chan string) + go k8sDeletePvc("data-meep-elasticsearch-data-0", cobraCmd, messages) + go k8sDeletePvc("data-meep-elasticsearch-master-0", cobraCmd, messages) + go k8sDeletePvc("data-meep-elasticsearch-master-1", cobraCmd, messages) + + k8sDelete("meep-redis", cobraCmd) + k8sDelete("meep-kube-state-metrics", cobraCmd) + k8sDelete("meep-metricbeat", cobraCmd) + k8sDelete("meep-couchdb", cobraCmd) + k8sDelete("meep-kibana", cobraCmd) + k8sDelete("meep-filebeat", cobraCmd) + k8sDelete("meep-curator", cobraCmd) + k8sDelete("meep-elasticsearch", cobraCmd) + + // Wait for all pvc delete routines to complete + // NOTE: Must be checked after deleting elastic + for i := 0; i < 3; i++ { + fmt.Println(<-messages) + } + + // Local storage bindings + // @TODO move to respective charts + cmd := exec.Command("kubectl", "delete", "-f", gitdir+utils.RepoCfg.GetString("repo.dep.elastic.es.pv")) + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } +} + +func init() { + rootCmd.AddCommand(deleteCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // deleteCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // deleteCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +func k8sDelete(component string, cobraCmd *cobra.Command) { + // If release exist + exist, _ := utils.IsHelmRelease(component, cobraCmd) + if exist { + // Delete + err := utils.HelmDelete(component, cobraCmd) + if err != nil { + fmt.Println("Helm delete failed with Error: ", err) + } + } +} + +func k8sDeletePvc(pvc string, cobraCmd *cobra.Command, messages chan string) { + cmd := exec.Command("kubectl", "delete", "pvc", pvc) + out, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error:", err) + fmt.Println(out) + } + messages <- "Deleted pvc: " + pvc +} diff --git a/go-apps/meepctl/cmd/deploy.go b/go-apps/meepctl/cmd/deploy.go new file mode 100644 index 0000000000000000000000000000000000000000..209be621e85c3e3493ff7dd9b62825683f91fd06 --- /dev/null +++ b/go-apps/meepctl/cmd/deploy.go @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "errors" + "fmt" + "os" + "os/exec" + "strings" + "time" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +var deployCodecov bool + +// deployCmd represents the deploy command +var deployCmd = &cobra.Command{ + Use: "deploy [registry] [tag]", + Short: "Deploy containers on the K8s cluster", + Long: `Deploy containers on the K8s cluster + +AdvantEDGE is composed of a collection of micro-services (a.k.a the groups). + +Deploy command starts a group of containers the in the K8s cluster. +Optional registry & tag parameters allows to specify a shared registry & tag for core images. +Default registry/tag are: local registry & latest + +Valid groups: + * core: AdvantEDGE core containers + * dep: Dependency containers + * all: All containers + `, + Example: ` # Deploy all containers + meepctl deploy all + # Delete and re-deploy only AdvantEDGE core containers + meepctl deploy core --force + # Deploy AdvantEDGE version 1.0.0 from my.registry.com + meepctl deploy core my.registry.com 1.0.0 + `, + Args: cobra.RangeArgs(1, 3), + Run: func(cmd *cobra.Command, args []string) { + group := args[0] + registry := "" + if len(args) > 1 { + registry = args[1] + } + tag := "latest" + if len(args) > 2 { + tag = args[2] + } + + f, _ := cmd.Flags().GetBool("force") + v, _ := cmd.Flags().GetBool("verbose") + t, _ := cmd.Flags().GetBool("time") + if v { + fmt.Println("Deploy called") + fmt.Println("[arg] group:", group) + fmt.Println("[arg] registry:", registry) + fmt.Println("[arg] tag:", tag) + fmt.Println("[flag] force:", f) + fmt.Println("[flag] verbose:", v) + fmt.Println("[flag] time:", t) + } + + start := time.Now() + utils.InitRepoConfig() + if group == "all" { + deployDep(cmd) + deployCore(cmd, registry, tag) + } else if group == "core" { + deployCore(cmd, registry, tag) + } else if group == "dep" { + deployDep(cmd) + } else { + fmt.Println("Invalid group ", group) + fmt.Println(cmd.Long) + } + elapsed := time.Since(start) + if t { + fmt.Println("Took ", elapsed.Round(time.Millisecond).String()) + } + }, +} + +func init() { + rootCmd.AddCommand(deployCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // deployCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + deployCmd.Flags().BoolP("force", "f", false, "Deployed components are deleted and deployed") + deployCmd.Flags().BoolVar(&deployCodecov, "codecov", false, "Use when deploying code coverage binaries (dev. option)") +} + +func ensureCoreStorage(cobraCmd *cobra.Command) { + workdir := viper.GetString("meep.workdir") + "/" + + // Local storage strucutre + cmd := exec.Command("mkdir", "-p", workdir) + _, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + err = errors.New("Error creating path [" + workdir + "]") + fmt.Println(err) + } + + //templates + templatedir := viper.GetString("meep.gitdir") + "/" + utils.RepoCfg.GetString("repo.core.meep-virt-engine.template") + cmd = exec.Command("rm", "-rf", workdir+"template-bak") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("mv", workdir+"template", workdir+"template-bak") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("cp", "-r", templatedir, workdir+"template") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + //codecov + cmd = exec.Command("rm", "-rf", workdir+"codecov-bak") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("mv", workdir+"codecov", workdir+"codecov-bak") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("mkdir", "-p", workdir+"codecov") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + for _, targetName := range buildCmd.ValidArgs { + if targetName == "all" { + continue + } + codecovCapable := utils.RepoCfg.GetBool("repo.core." + targetName + ".codecov") + if codecovCapable { + cmd = exec.Command("mkdir", "-p", workdir+"codecov/"+targetName) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + } + } + //certs + cmd = exec.Command("mkdir", "-p", workdir+"certs") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) +} + +func ensureDepStorage(cobraCmd *cobra.Command) { + workdir := viper.GetString("meep.workdir") + "/" + + // Local storage structure + cmd := exec.Command("mkdir", "-p", workdir) + cmd.Args = append(cmd.Args, workdir+"couchdb") + cmd.Args = append(cmd.Args, workdir+"es-data") + cmd.Args = append(cmd.Args, workdir+"es-master-0") + cmd.Args = append(cmd.Args, workdir+"es-master-1") + cmd.Args = append(cmd.Args, workdir+"kibana") + + _, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + err = errors.New("Error creating path [" + workdir + "]") + fmt.Println(err) + } + + //copy the yaml files in workdir and apply a modification to the tmp file, original is untouched + cmd = exec.Command("mkdir", "-p", workdir+"tmp") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + pvES := viper.GetString("meep.gitdir") + "/" + utils.RepoCfg.GetString("repo.dep.elastic.es.pv") + cmd = exec.Command("cp", pvES, workdir+"tmp/meep-pv-es.yaml") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + valuesFB := viper.GetString("meep.gitdir") + "/" + utils.RepoCfg.GetString("repo.dep.elastic.filebeat.values") + cmd = exec.Command("cp", valuesFB, workdir+"tmp/filebeat-values.yaml") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + //search and replace in yaml fil + tmpStr := strings.Replace(workdir, "/", "\\/", -1) + str := "s//" + tmpStr + "/g" + cmd = exec.Command("sed", "-i", str, workdir+"tmp/meep-pv-es.yaml") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("sed", "-i", str, workdir+"tmp/filebeat-values.yaml") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + + // Local storage bindings + // @TODO move to respective chart + cmd = exec.Command("kubectl", "apply", "-f", workdir+"tmp/meep-pv-es.yaml") + _, _ = utils.ExecuteCmd(cmd, cobraCmd) +} + +func deployCore(cobraCmd *cobra.Command, registry string, tag string) { + // Storage + ensureCoreStorage(cobraCmd) + // Runtime + if registry != "" { + registry = registry + "/" + } + gitdir := viper.GetString("meep.gitdir") + "/" + workdir := viper.GetString("meep.workdir") + "/" + + deployMeepUserAccount(cobraCmd) + + //--- + repo := "meep-ctrl-engine" + chart := gitdir + utils.RepoCfg.GetString("repo.core.meep-ctrl-engine.chart") + k8sDeployCore(repo, registry, tag, chart, nil, cobraCmd) + //--- + repo = "meep-mon-engine" + chart = gitdir + utils.RepoCfg.GetString("repo.core.meep-mon-engine.chart") + k8sDeployCore(repo, registry, tag, chart, nil, cobraCmd) + //--- + repo = "meep-tc-engine" + chart = gitdir + utils.RepoCfg.GetString("repo.core.meep-tc-engine.chart") + k8sDeployCore(repo, registry, tag, chart, nil, cobraCmd) + //--- + repo = "meep-mg-manager" + chart = gitdir + utils.RepoCfg.GetString("repo.core.meep-mg-manager.chart") + k8sDeployCore(repo, registry, tag, chart, nil, cobraCmd) + //--- + repo = "meep-webhook" + chart = gitdir + utils.RepoCfg.GetString("repo.core.meep-webhook.chart") + cert, key, cabundle := createWebhookCerts(chart, workdir+"certs", cobraCmd) + flags := utils.HelmFlags(nil, "--set", "sidecar.image.repository="+registry+"meep-tc-sidecar") + flags = utils.HelmFlags(flags, "--set", "sidecar.image.tag="+tag) + flags = utils.HelmFlags(flags, "--set", "webhook.cert="+cert) + flags = utils.HelmFlags(flags, "--set", "webhook.key="+key) + flags = utils.HelmFlags(flags, "--set", "webhook.cabundle="+cabundle) + k8sDeployCore(repo, registry, tag, chart, flags, cobraCmd) + //--- + repo = "meep-virt-engine" + chart = gitdir + utils.RepoCfg.GetString("repo.core.meep-virt-engine.chart") + flags = utils.HelmFlags(nil, "--set", "service.ip="+viper.GetString("node.ip")) + k8sDeploy(repo, chart, flags, cobraCmd) + deployVirtEngineExt(repo, cobraCmd) +} + +func deployDep(cobraCmd *cobra.Command) { + gitDir := viper.GetString("meep.gitdir") + "/" + workdir := viper.GetString("meep.workdir") + "/" + + // Storage + ensureDepStorage(cobraCmd) + // Runtime + repo := "meep-elasticsearch" + chart := utils.RepoCfg.GetString("repo.dep.elastic.es.chart") + flags := utils.HelmFlags(nil, "--version", utils.RepoCfg.GetString("repo.dep.elastic.es.version")) + flags = utils.HelmFlags(flags, "--values", gitDir+utils.RepoCfg.GetString("repo.dep.elastic.es.values")) + k8sDeploy(repo, chart, flags, cobraCmd) + //--- + repo = "meep-curator" + chart = gitDir + utils.RepoCfg.GetString("repo.dep.elastic.es-curator.chart") + flags = nil + k8sDeploy(repo, chart, flags, cobraCmd) + //--- + repo = "meep-kibana" + chart = gitDir + utils.RepoCfg.GetString("repo.dep.elastic.kibana.chart") + flags = utils.HelmFlags(nil, "--set", "persistentVolume.location="+workdir+"kibana/") + k8sDeploy(repo, chart, flags, cobraCmd) + //--- + // Value file is modified, use the tmp/ version + repo = "meep-filebeat" + chart = utils.RepoCfg.GetString("repo.dep.elastic.filebeat.chart") + flags = utils.HelmFlags(nil, "--version", utils.RepoCfg.GetString("repo.dep.elastic.filebeat.version")) + flags = utils.HelmFlags(flags, "--values", workdir+"tmp/filebeat-values.yaml") + k8sDeploy(repo, chart, flags, cobraCmd) + //--- + repo = "meep-couchdb" + chart = gitDir + utils.RepoCfg.GetString("repo.dep.couchdb.chart") + flags = utils.HelmFlags(nil, "--set", "persistentVolume.location="+workdir+"couchdb/") + k8sDeploy(repo, chart, flags, cobraCmd) + //--- + repo = "meep-redis" + chart = utils.RepoCfg.GetString("repo.dep.redis.chart") + flags = utils.HelmFlags(nil, "--version", utils.RepoCfg.GetString("repo.dep.redis.version")) + flags = utils.HelmFlags(flags, "--values", gitDir+utils.RepoCfg.GetString("repo.dep.redis.values")) + k8sDeploy(repo, chart, flags, cobraCmd) + //--- + repo = "meep-kube-state-metrics" + chart = gitDir + utils.RepoCfg.GetString("repo.dep.k8s.kube-state-metrics.chart") + flags = nil + k8sDeploy(repo, chart, flags, cobraCmd) + //--- + repo = "meep-metricbeat" + chart = gitDir + utils.RepoCfg.GetString("repo.dep.elastic.metricbeat.chart") + flags = utils.HelmFlags(nil, "--set", "image.pullPolicy=IfNotPresent") + k8sDeploy(repo, chart, flags, cobraCmd) +} + +func k8sDeployCore(repo string, registry string, tag string, chart string, flags [][]string, cobraCmd *cobra.Command) { + coreFlags := utils.HelmFlags(flags, "--set", "image.repository="+registry+repo) + coreFlags = utils.HelmFlags(coreFlags, "--set", "image.tag="+tag) + codecovCapable := utils.RepoCfg.GetBool("repo.core." + repo + ".codecov") + if deployCodecov && codecovCapable { + coreFlags = utils.HelmFlags(coreFlags, "--set", "codecov.enabled=true") + } + k8sDeploy(repo, chart, coreFlags, cobraCmd) +} + +func k8sDeploy(component string, chart string, flags [][]string, cobraCmd *cobra.Command) { + force, _ := cobraCmd.Flags().GetBool("force") + + // If release exist && --force, delete + exist, _ := utils.IsHelmRelease(component, cobraCmd) + if exist { + if force { + _ = utils.HelmDelete(component, cobraCmd) + } else { + fmt.Println("Skipping " + component + ": already deployed -- use [-f, --force] flag to force deployment") + return + } + } + + // Deploy + _ = utils.HelmInstall(component, chart, flags, cobraCmd) +} + +func deployVirtEngineExt(component string, cobraCmd *cobra.Command) { + verbose, _ := cobraCmd.Flags().GetBool("verbose") + force, _ := cobraCmd.Flags().GetBool("force") + gitDir := viper.GetString("meep.gitdir") + "/" + workdir := viper.GetString("meep.workdir") + "/" + start := time.Now() + + // If release exist && --force, delete + pid, err := utils.GetProcess(component, cobraCmd) + if err == nil && pid != "" { + if force { + deleteVirtEngine(cobraCmd) + } else { + fmt.Println("Skipping " + component + " (ext.): already deployed -- use [-f, --force] flag to force deployment") + return + } + } + + // Deploy + // ensure directory + logdir := workdir + "log" + cmd := exec.Command("mkdir", "-p", logdir) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + // start ext. component + file, err := os.Create(logdir + "/virt-engine.log") + if err != nil { + fmt.Println("Error starting virt.engine (ext.)") + fmt.Println(err) + return + } + + codecovCapable := utils.RepoCfg.GetBool("repo.core." + component + ".codecov") + virtEngineApp := gitDir + utils.RepoCfg.GetString("repo.core.meep-virt-engine.bin") + "/meep-virt-engine" + if deployCodecov && codecovCapable { + codecovFile := workdir + "/codecov/" + component + "/codecov-meep-virt-engine.out" + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command(virtEngineApp, "-test.coverprofile="+codecovFile, "__DEVEL--code-cov") + } else { + cmd = exec.Command(virtEngineApp) + } + cmd.Stdout = file + cmd.Stderr = file + if verbose { + fmt.Println("Args:", cmd.Args) + } + err = cmd.Start() + elapsed := time.Since(start) + + if err != nil { + fmt.Println("Error starting virt.engine (ext.)") + fmt.Println(err) + } else { + r := utils.FormatResult("Deployed meep-virt-engine (ext.)", elapsed, cobraCmd) + fmt.Println(r) + } +} + +func deployMeepUserAccount(cobraCmd *cobra.Command) { + gitdir := viper.GetString("meep.gitdir") + + cmd := exec.Command("kubectl", "create", "-f", gitdir+"/"+utils.RepoCfg.GetString("repo.core.meep-user.service-account")) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + + cmd = exec.Command("kubectl", "create", "-f", gitdir+"/"+utils.RepoCfg.GetString("repo.core.meep-user.cluster-role-binding")) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) +} + +func createWebhookCerts(chart string, certdir string, cobraCmd *cobra.Command) (string, string, string) { + cmd := exec.Command("sh", "-c", chart+"/webhook-create-signed-cert.sh --certdir "+certdir) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("sh", "-c", "cat "+certdir+"/server-cert.pem | base64 -w0") + cert, _ := utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("sh", "-c", "cat "+certdir+"/server-key.pem | base64 -w0") + key, _ := utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("kubectl", "config", "view", "--raw", "--minify", "--flatten", + "-o=jsonpath='{.clusters[].cluster.certificate-authority-data}'") + cabundle, _ := utils.ExecuteCmd(cmd, cobraCmd) + return cert, key, cabundle +} diff --git a/go-apps/meepctl/cmd/dockerize.go b/go-apps/meepctl/cmd/dockerize.go new file mode 100644 index 0000000000000000000000000000000000000000..99299c6059ccd335bc5cb6de0014bf4a266e4790 --- /dev/null +++ b/go-apps/meepctl/cmd/dockerize.go @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + "os" + "os/exec" + "time" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +// dockerizeCmd represents the dockerize command +var dockerizeCmd = &cobra.Command{ + Use: "dockerize ", + Short: "Dockerize core components", + Long: `Dockerize core components + +AdvantEDGE is composed of a collection of micro-services. + +Dockerize command genrates AdvantEDGE Docker images and stores them in +the local Docker registry. + +Valid targets:`, + Example: ` # Dockerize all components + meepctl dockerize all + # Dockerize meep-ctrl-engine component only + meepctl dockerize meep-ctrl-engine + `, + Args: cobra.ExactValidArgs(1), + ValidArgs: []string{"all", "meep-ctrl-engine", "meep-webhook", "meep-mg-manager", "meep-mon-engine", "meep-tc-engine", "meep-tc-sidecar"}, + Run: func(cmd *cobra.Command, args []string) { + target := "" + if len(args) > 0 { + target = args[0] + } + + v, _ := cmd.Flags().GetBool("verbose") + t, _ := cmd.Flags().GetBool("time") + + if v { + fmt.Println("Dockerize called") + fmt.Println("[arg] target:", target) + fmt.Println("[flag] verbose:", v) + fmt.Println("[flag] time:", t) + } + + start := time.Now() + utils.InitRepoConfig() + if target == "all" { + dockerizeAll(cmd) + } else { + dockerize(target, cmd) + } + + elapsed := time.Since(start) + if t { + fmt.Println("Took ", elapsed.Round(time.Millisecond).String()) + } + }, +} + +func init() { + var argsStr string + for _, arg := range dockerizeCmd.ValidArgs { + argsStr += "\n * " + arg + } + dockerizeCmd.Long += argsStr + + rootCmd.AddCommand(dockerizeCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // dockerizeCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // dockerizeCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +func dockerizeAll(cobraCmd *cobra.Command) { + for _, target := range cobraCmd.ValidArgs { + if target == "all" { + continue + } + dockerize(target, cobraCmd) + } +} + +func dockerize(targetName string, cobraCmd *cobra.Command) { + verbose, _ := cobraCmd.Flags().GetBool("verbose") + target := utils.RepoCfg.GetStringMapString("repo.core." + targetName) + gitDir := viper.GetString("meep.gitdir") + binDir := gitDir + "/" + target["bin"] + + if len(target) == 0 { + fmt.Println("Invalid target:", targetName) + return + } + + //copy container data locally + data := utils.RepoCfg.GetStringMapString("repo.core." + targetName + ".docker-data") + if len(data) != 0 { + for k, v := range data { + dstDataDir := binDir + "/" + k + srcDataDir := gitDir + "/" + v + if _, err := os.Stat(srcDataDir); !os.IsNotExist(err) { + if verbose { + fmt.Println(" Using: " + srcDataDir + " --> " + dstDataDir) + } + cmd := exec.Command("rm", "-r", dstDataDir) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + cmd = exec.Command("cp", "-r", srcDataDir, dstDataDir) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + } else { + fmt.Println(" Source data not found: " + srcDataDir + " --> " + dstDataDir) + } + } + } + + // dockerize + path := gitDir + "/" + target["bin"] + fmt.Println("Dockerizing", targetName) + cmd := exec.Command("docker", "build", "--no-cache", "--rm", "-t", targetName, path) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + + // cleanup data + if len(data) != 0 { + for k := range data { + dstDataDir := binDir + "/" + k + cmd := exec.Command("rm", "-r", dstDataDir) + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + } + } + +} diff --git a/go-apps/meepctl/cmd/genmd.go b/go-apps/meepctl/cmd/genmd.go new file mode 100644 index 0000000000000000000000000000000000000000..aeb2aea960e0feb8bb2d600b39ad2360e296f852 --- /dev/null +++ b/go-apps/meepctl/cmd/genmd.go @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + "log" + "os" + + "github.com/roymx/viper" + "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" +) + +// genmdCmd represents the genmd command +var genmdCmd = &cobra.Command{ + Use: "genmd", + Short: "Generate markdown files for meepctl", + Long: `Generate markdown files for meepctl`, + Run: func(cmd *cobra.Command, args []string) { + outDir := viper.GetString("meep.gitdir") + "/docs/meepctl" + if _, err := os.Stat(outDir); os.IsNotExist(err) { + // default outdir not found ... use /tmp + outDir = "/tmp" + } + err := doc.GenMarkdownTree(rootCmd, outDir) + if err != nil { + log.Fatal(err) + return + } + fmt.Println("Markdown files can be found in ", outDir, " folder") + }, +} + +func init() { + rootCmd.AddCommand(genmdCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // genmdCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // genmdCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/go-apps/meepctl/cmd/publish.go b/go-apps/meepctl/cmd/publish.go new file mode 100644 index 0000000000000000000000000000000000000000..710c83989cc2ac72bd83db74bed8a61174028126 --- /dev/null +++ b/go-apps/meepctl/cmd/publish.go @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + "time" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + "github.com/spf13/cobra" +) + +// publishCmd represents the publish command +var publishCmd = &cobra.Command{ + Use: "publish [tag]", + Short: "Publish image on a registry", + Long: `Publish image on a registry + +AdvantEDGE is composed of a collection of micro-services. + +Publish command is a utility function that pushes AdvatEDGE core images to a specified registry. +Core images are pushed from local-registry/core-repo:latest to registry/core-repo:tag (no tag = latest) +`, + Example: ` # Publish images to your.registry.com:latest + meepctl publish your.registry.com + # Publish images to your.registry.com:latest:1.1.0 + meepctl publish your.registry.com 1.1.0`, + Args: cobra.RangeArgs(1, 2), + Run: func(cmd *cobra.Command, args []string) { + registry := args[0] + tag := "latest" + if len(args) > 1 { + tag = args[1] + } + + v, _ := cmd.Flags().GetBool("verbose") + t, _ := cmd.Flags().GetBool("time") + if v { + fmt.Println("Publish called") + fmt.Println("[arg] registry:", registry) + fmt.Println("[arg] tag:", tag) + fmt.Println("[flag] verbose:", v) + fmt.Println("[flag] time:", t) + } + + start := time.Now() + publishImage(cmd, registry, "meep-ctrl-engine", tag) + publishImage(cmd, registry, "meep-mon-engine", tag) + publishImage(cmd, registry, "meep-tc-engine", tag) + publishImage(cmd, registry, "meep-tc-sidecar", tag) + publishImage(cmd, registry, "meep-mg-manager", tag) + publishImage(cmd, registry, "meep-webhook", tag) + elapsed := time.Since(start) + if t { + fmt.Println("Took ", elapsed.Round(time.Millisecond).String()) + } + + }, +} + +func init() { + rootCmd.AddCommand(publishCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // publishCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // publishCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} +func publishImage(cobraCmd *cobra.Command, registry string, repo string, tag string) { + // docker tag meep-ctrl-engine:latest dev.advantedge.com/meep-ctrl-engine:0.2.17 + // docker push dev.advantedge.com/meep-ctrl-engine:0.2.17 + + exist, _ := utils.IsDockerImage(repo, cobraCmd) + if exist { + localTag, _ := utils.GetDockerTag(repo, cobraCmd) + localRepo := repo + ":" + localTag + newRepo := registry + "/" + repo + ":" + tag + _ = utils.TagDockerImage(localRepo, newRepo, cobraCmd) + _ = utils.PushDockerImage(newRepo, cobraCmd) + } else { + fmt.Println("Image", repo, ":latest not found") + } +} diff --git a/go-apps/meepctl/cmd/root.go b/go-apps/meepctl/cmd/root.go new file mode 100644 index 0000000000000000000000000000000000000000..1bcf1a26e06588779b6d05001917551b938cefe7 --- /dev/null +++ b/go-apps/meepctl/cmd/root.go @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + "os" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + homedir "github.com/mitchellh/go-homedir" + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +var cfgFile string + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "meepctl", + Short: "meepctl - CLI application to control the AdvantEDGE platform", + Long: ` +meepctl - CLI application to control the AdvantEDGE platform + + Find more information [here](https://kopsvas19p.interdigital.com/wbu-tep/AdvantEDGE/blob/develop/docs/meepctl/meepctl.md) +`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + _, err := utils.ConfigCreateIfNotExist() + if err != nil { + fmt.Println("Error accessing config file at $(HOME)/.meepctl.yaml") + fmt.Println(err) + os.Exit(1) + } + utils.ConfigValidate("") + + if err := rootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + //rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.meepctl.yaml)") + rootCmd.PersistentFlags().BoolP("verbose", "v", false, "Display debug information") + rootCmd.PersistentFlags().BoolP("time", "t", false, "Display timing information") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + //rootCmd.Flags().BoolP("verbose", "v", false, "Display debug information") +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := homedir.Dir() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // Search config in home directory with name ".meepctl" (without extension). + viper.AddConfigPath(home) + viper.SetConfigName(".meepctl") + } + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using meepctl config file:", viper.ConfigFileUsed()) + } +} diff --git a/go-apps/meepctl/cmd/test.go b/go-apps/meepctl/cmd/test.go new file mode 100644 index 0000000000000000000000000000000000000000..48d0888c34ee4738b8143471cf76e119c852c132 --- /dev/null +++ b/go-apps/meepctl/cmd/test.go @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "fmt" + "os" + "os/exec" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +// testCmd represents the test command +var testCmd = &cobra.Command{ + Use: "test", + Short: "Generate code coverage report", + Long: `Generate code coverage report + + AdvantEDGE components can be compiled in code coverage (codecov) mode. + When instrumented with codecov, AdventEDGE micro-services generate a coverage report on termination. + + Use this command after terminating codecov execution to genrate a report. + `, + Run: func(cobraCmd *cobra.Command, args []string) { + utils.InitRepoConfig() + targets := utils.RepoCfg.GetStringMapString("repo.core") + + for k := range targets { + codecovCapable := utils.RepoCfg.GetBool("repo.core." + k + ".codecov") + if codecovCapable { + gitDir := viper.GetString("meep.gitdir") + workDir := viper.GetString("meep.workdir") + codecovFile := workDir + "/codecov/" + k + "/codecov-" + k + ".out" + if _, err := os.Stat(codecovFile); !os.IsNotExist(err) { + fmt.Println("Found " + codecovFile) + targetDir := gitDir + "/go-apps/" + k + + //go tool cover -html=c.out -o coverage.html + htmlReport := gitDir + "/test/codecov-" + k + ".html" + fmt.Println(" + Generating html report ", htmlReport) + cmd := exec.Command("go", "tool", "cover", "-html="+codecovFile, "-o", htmlReport) + cmd.Dir = targetDir + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + + // go tool cover -func=c.out + txtReport := gitDir + "/test/codecov-" + k + ".txt" + fmt.Println(" + Generating text report ", txtReport) + cmd = exec.Command("go", "tool", "cover", "-func="+codecovFile, "-o", txtReport) + cmd.Dir = targetDir + _, _ = utils.ExecuteCmd(cmd, cobraCmd) + + } + } + + } + + }, +} + +func init() { + rootCmd.AddCommand(testCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // testCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // testCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/go-apps/meepctl/cmd/version.go b/go-apps/meepctl/cmd/version.go new file mode 100644 index 0000000000000000000000000000000000000000..7c77e2200a6db4d43434b401dd6a6566eb8766e3 --- /dev/null +++ b/go-apps/meepctl/cmd/version.go @@ -0,0 +1,254 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package cmd + +import ( + "encoding/json" + "fmt" + "os/exec" + "strings" + "time" + + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/utils" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +// versionCmd represents the version command +var versionCmd = &cobra.Command{ + Use: "version ", + Short: "Display version information", + Long: `Display version information + +AdvantEDGE is composed of a collection of components running as micro-services/applications. + +Versions command collects and displays version of core & dependency components + +Valid groups: + * core: AdvantEDGE core containers + * dep: Dependency applications + * all: All containers and applications + * : Displays the version of the meepctl tool + `, + Example: ` # Displays Versions of all containers + meepctl version all + # Display versions of only AdvantEDGE core containers + meepctl version core + `, + Args: cobra.MaximumNArgs(1), + ValidArgs: []string{"all", "dep", "core"}, + Run: func(cmd *cobra.Command, args []string) { + group := "" + if len(args) > 0 { + group = args[0] + } + v, _ := cmd.Flags().GetBool("verbose") + t, _ := cmd.Flags().GetBool("time") + if v { + fmt.Println("Version called") + fmt.Println("[arg] group:", group) + fmt.Println("[flag] verbose:", v) + fmt.Println("[flag] time:", t) + } + + start := time.Now() + utils.InitRepoConfig() + ver := formatVersion("meepctl", meepctlVersion, "") + fmt.Println(ver) + cfgVer := formatVersion(".meepctl.yaml", viper.GetString("version"), "") + fmt.Println(cfgVer) + repoVer := formatVersion(".meepctl-repocfg.yaml", utils.RepoCfg.GetString("version"), "") + fmt.Println(repoVer) + if group == "all" { + versionsDep(cmd) + versionsCore(cmd) + } else if group == "core" { + versionsCore(cmd) + } else if group == "dep" { + versionsDep(cmd) + } + elapsed := time.Since(start) + if t { + fmt.Println("Took ", elapsed.Round(time.Millisecond).String()) + } + }, +} + +type versionInfo struct { + Name string `json:"name"` + Version string `json:"version,omitempty"` + VersionID string `json:"id,omitempty"` +} + +const meepctlVersion = "1.0.0" +const na = "NA" + +var corePodsNameMap = [...]string{ + "couchdb", + "elasticsearch-curator", + "elasticsearch", + "filebeat", + "kibana", + "kube-state-metrics", + "meep-ctrl-engine", + "meep-webhook", + "meep-mg-manager", + "meep-mon-engine", + "meep-redis", + "meep-tc-engine", + "metricbeat", +} + +var depPodsNameMap = [...]string{"weave"} + +func init() { + rootCmd.AddCommand(versionCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // versionsCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // versionsCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +func formatVersion(name string, version string, id string) string { + var info versionInfo + info.Name = name + info.Version = version + info.VersionID = id + v, _ := json.Marshal(info) + return " " + string(v) +} + +func getHelmVersion(cobraCmd *cobra.Command) { + clientStr := formatVersion("helm client", na, na) + serverStr := formatVersion("helm server", na, na) + cmd := exec.Command("helm", "version") + output, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error getting helm version\n", err) + } else { + output = strings.Replace(output, "\"", "", -1) + outAll := strings.Split(output, "}") + outClient := outAll[0] + outServer := outAll[1] + //client part + out := strings.Split(outClient, ",") + clientStr = formatVersion("helm client", strings.Split(out[0], ":")[2], strings.Split(out[1], ":")[1]) + //server part + out = strings.Split(outServer, ",") + serverStr = formatVersion("helm server", strings.Split(out[0], ":")[2], strings.Split(out[1], ":")[1]) + } + + fmt.Println(clientStr) + fmt.Println(serverStr) +} + +func getDockerVersion(cobraCmd *cobra.Command) { + clientStr := formatVersion("docker client", na, na) + serverStr := formatVersion("docker server", na, na) + cmd := exec.Command("docker", "version") + output, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error getting docker version\n", err) + } else { + output = strings.Replace(output, " ", "", -1) + output = strings.Replace(output, "\n", ":", -1) + out := strings.Split(output, ":") + + clientStr = formatVersion("docker client", out[3], out[9]) + serverStr = formatVersion("docker server", out[24], out[30]) + } + fmt.Println(clientStr) + fmt.Println(serverStr) +} + +func getKubernetesVersion(cobraCmd *cobra.Command) { + clientStr := formatVersion("k8s client", na, na) + serverStr := formatVersion("k8s server", na, na) + cmd := exec.Command("kubectl", "version") + output, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error getting kubernetes version\n", err) + } else { + output = strings.Replace(output, "\"", "", -1) + output = strings.Replace(output, "\n", ":", -1) + out := strings.Split(output, ":") + + outVersion := strings.Split(out[4], ",") + outGitCommit := strings.Split(out[5], ",") + clientStr = formatVersion("k8s client", outVersion[0], outGitCommit[0]) + + outVersion = strings.Split(out[17], ",") + outGitCommit = strings.Split(out[18], ",") + serverStr = formatVersion("k8s server", outVersion[0], outGitCommit[0]) + } + fmt.Println(clientStr) + fmt.Println(serverStr) + + /* weave section as part of kubernetes */ + outVer := getPodVersions(cobraCmd) + for i := range depPodsNameMap { + if p, ok := outVer[depPodsNameMap[i]]; ok { + fmt.Println(formatVersion(p.Name, p.Version, p.VersionID)) + } else { + fmt.Println(formatVersion(depPodsNameMap[i], na, na)) + } + } +} + +/* just a generic function that gets all the pod from all namespaces, filtering should be done by the caller */ +func getPodVersions(cobraCmd *cobra.Command) map[string]*versionInfo { + outMap := make(map[string]*versionInfo) + cmd := exec.Command("kubectl", "get", "pods", "--all-namespaces", "-o", "jsonpath={range .items[*]}{\"{\\\"Name\\\":\\\"\"}{.status.containerStatuses[].name}{\"\\\",\"}{\"\\\"Version\\\":\\\"\"}{.status.containerStatuses[].image}{\"\\\",\"}{\"\\\"VersionID\\\":\\\"\"}{.status.containerStatuses[].imageID}{\"\\\"}\\n\"}") + output, err := utils.ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error getting pods version\n", err) + } else { + pods := strings.Split(output, "\n") + for i := range pods { + vi := new(versionInfo) + err := json.Unmarshal([]byte(pods[i]), &vi) + if err != nil { + continue + } + if vi.Name != "" { + outMap[vi.Name] = vi + tv := strings.Split(vi.Version, ":") + vi.Version = tv[len(tv)-1] + tid := strings.Split(vi.VersionID, ":") + vi.VersionID = tid[len(tid)-1] + } + } + } + return outMap +} + +func versionsDep(cobraCmd *cobra.Command) { + getHelmVersion(cobraCmd) + getDockerVersion(cobraCmd) + getKubernetesVersion(cobraCmd) +} + +func versionsCore(cobraCmd *cobra.Command) { + outVer := getPodVersions(cobraCmd) + for i := range corePodsNameMap { + if p, ok := outVer[corePodsNameMap[i]]; ok { + fmt.Println(formatVersion(p.Name, p.Version, p.VersionID)) + } else { + fmt.Println(formatVersion(corePodsNameMap[i], na, na)) + } + } +} diff --git a/go-apps/meepctl/go.mod b/go-apps/meepctl/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..fa9055c2b072e6b599a95f2a3ae4bb9500358e0c --- /dev/null +++ b/go-apps/meepctl/go.mod @@ -0,0 +1,13 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl + +go 1.12 + +require ( + github.com/BurntSushi/toml v0.3.1 // indirect + github.com/cpuguy83/go-md2man v1.0.10 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 + github.com/roymx/viper v1.3.3-0.20190416163942-b9a223fc58a3 + github.com/spf13/cobra v0.0.0-20190109003409-7547e83b2d85 + gopkg.in/yaml.v2 v2.2.2 +) diff --git a/go-apps/meepctl/go.sum b/go-apps/meepctl/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..27b7e89ec11ec7b382d4dad5894f4fa1119aff51 --- /dev/null +++ b/go-apps/meepctl/go.sum @@ -0,0 +1,51 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/roymx/viper v1.3.3-0.20190416163942-b9a223fc58a3 h1:lBNvYUFo7d4fHs8BXUmoTzbdUo4usq6PlP5qn894sGA= +github.com/roymx/viper v1.3.3-0.20190416163942-b9a223fc58a3/go.mod h1:jo59Sv6xirZtbxbaZbCtrQd1CSufmcxJZIC8hm2tepw= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.0-20190109003409-7547e83b2d85 h1:UQHWkFUuJBy5rWN1DxosG/efssLu7u0fXXSTC2HHKfQ= +github.com/spf13/cobra v0.0.0-20190109003409-7547e83b2d85/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/go-apps/meepctl/install.sh b/go-apps/meepctl/install.sh new file mode 100755 index 0000000000000000000000000000000000000000..52f37dd331178cf7cc0e9979129ab549ff93be0b --- /dev/null +++ b/go-apps/meepctl/install.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Get full path to script directory +SCRIPT=$(readlink -f "$0") +BASEDIR=$(dirname "$SCRIPT") + +# Configure environment +GOOS=linux +IMAGE_NAME=meepctl +BINDIR=../../bin/meepctl +echo "$IMAGE_NAME" + +cd $BASEDIR + +# Clean build +echo "...clean" +go clean + +# Create vendor folder +echo "...vendor" +go mod vendor + +# Lint code +echo "...lint" +golangci-lint run + +# Build +echo "...build" +go build -o ./$IMAGE_NAME . + +# Copy to bin folder +mkdir -p $BINDIR +cp ./$IMAGE_NAME $BINDIR + +# Install +echo "...install" +go install diff --git a/go-apps/meepctl/main.go b/go-apps/meepctl/main.go new file mode 100644 index 0000000000000000000000000000000000000000..20e4912814541c408a5c2b210c47d44fa1222b3f --- /dev/null +++ b/go-apps/meepctl/main.go @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package main + +import ( + "github.com/InterDigitalInc/AdvantEDGE/go-apps/meepctl/cmd" +) + +func main() { + cmd.Execute() +} diff --git a/go-apps/meepctl/utils/config.go b/go-apps/meepctl/utils/config.go new file mode 100644 index 0000000000000000000000000000000000000000..63ca05706bb1cd9442dc9d93256355e5198bbae7 --- /dev/null +++ b/go-apps/meepctl/utils/config.go @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package utils + +import ( + "errors" + "fmt" + "io/ioutil" + "net" + "os" + "strconv" + "strings" + + homedir "github.com/mitchellh/go-homedir" + "github.com/roymx/viper" + yaml "gopkg.in/yaml.v2" +) + +var RepoCfg *viper.Viper + +// Config version needs to be bumped only when new elements are added +var defaultConfig = ` +version: 1.0.0 + +node: + ip: "Not-Initialized" + +meep: + gitdir: "Not-Initialized" + workdir: "/.meep" +` + +// Node parameters node +type Node struct { + // Node IP Address + IP string `json:"ip,omitempty"` +} + +// Meep parameters node +type Meep struct { + // GIT directory + Gitdir string `json:"gitdir,omitempty"` + // MEEP work directory + Workdir string `json:"workdir,omitempty"` +} + +// Config structure +type Config struct { + Version string `json:"version,omitempty"` + // Node parameters + Node Node `json:"ip,omitempty"` + // Meep parameters + Meep Meep `json:"meep,omitempty"` +} + +// ConfigGetDefaultPath get default config file path +func ConfigGetDefaultPath() (path string) { + // Find home directory. + home, err := homedir.Dir() + if err != nil { + fmt.Println(err) + return path + } + return home + "/.meepctl.yaml" +} + +// ConfigCreateIfNotExist test for config file existence & create default if needed +func ConfigCreateIfNotExist() (exist bool, err error) { + path := ConfigGetDefaultPath() + if path == "" { + os.Exit(1) + } + + // meepctl uses this config file located in $(HOME)/.meepctl.yaml + // If it does not exist, create one. + _, err = os.Stat(path) + if err == nil { + // we're good + return true, nil + } else if os.IsNotExist(err) { + // file does not exist so create default + cfg := ConfigReadFile("") // returns default config + err = ConfigWriteFile(cfg, path) + fmt.Println("Creating default config file @ " + path) + return true, err + } // else file may exist ... just return the error + return true, err +} + +// ConfigReadFile read the configuration file +func ConfigReadFile(filePath string) (cfg *Config) { + var err error + var data []byte + cfg = new(Config) + + // Read from config file + if filePath != "" { + data, err = ioutil.ReadFile(filePath) + if err != nil { + fmt.Println("Error reading config file [" + filePath + "]") + fmt.Println(err) + return nil + } + } + // Revert to default if readfile failed + if len(data) == 0 { + data = []byte(defaultConfig) + str := fmt.Sprintf("%s", data) + home, _ := homedir.Dir() + newStr := strings.Replace(str, "", home, -1) + data = []byte(newStr) + } + + err = yaml.Unmarshal(data, cfg) + if err != nil { + fmt.Println("Error unmarshalling config file [" + filePath + "]") + fmt.Println(err) + // Revert to default if unmarshall failed + _ = yaml.Unmarshal([]byte(defaultConfig), cfg) + } + + return cfg +} + +// ConfigValidate validates config file +func ConfigValidate(filePath string) (valid bool) { + if filePath == "" { + filePath = ConfigGetDefaultPath() + } + cfg := ConfigReadFile(filePath) + + // Validate IPV4 + ipValid, reason := ConfigIPValid(cfg.Node.IP) + if !ipValid { + fmt.Println("") + fmt.Println(" WARNING invalid meepctl config: node.ip") + fmt.Println(" Reason: " + reason) + fmt.Println(" Fix with: ./meepctl config set --ip ") + return false + } + + // Validate Gitdir + ipValid, reason = ConfigGitdirValid(cfg.Meep.Gitdir) + if !ipValid { + fmt.Println("") + fmt.Println(" WARNING invalid meepctl config: meep.gitdir") + fmt.Println(" Reason: " + reason) + fmt.Println(" Fix with: ./meepctl config set --gitdir ") + return false + } + return true +} + +// ConfigGitdirValid validates IP address +func ConfigGitdirValid(gitdir string) (valid bool, reason string) { + valid = true + fi, err := os.Stat(gitdir) + + if err != nil { + reason = "Path error [" + gitdir + "]" + valid = false + } else { + if !fi.IsDir() { + reason = "Not a directory [" + gitdir + "]" + valid = false + } + } + return valid, reason +} + +// ConfigIPValid validates IP address +func ConfigIPValid(ipAddr string) (valid bool, reason string) { + valid = true + // only ipv4 address + if ConfigIsIpv4(ipAddr) { + // not localhost + ip := net.ParseIP(ipAddr) + if ip.IsLoopback() { + reason = "Invalid local IP address [" + ipAddr + "] (loopback)" + valid = false + } + // only local address + addrs, _ := net.InterfaceAddrs() + var local = false + // var localV4 []string + for _, a := range addrs { + if strings.Contains(a.String(), ipAddr) { + local = true + } + // aIP := strings.Split(a.String(), "/")[0] + // if ConfigIsIpv4(aIP) { + // localV4 = append(localV4, aIP) + // } + } + if !local { + reason = "Not a local IP address [" + ipAddr + "]" + valid = false + } + } else { + reason = "Not an IPV4 address [" + ipAddr + "]" + valid = false + } + return valid, reason +} + +// ConfigWriteFile writes the configuration file +func ConfigWriteFile(cfg *Config, filePath string) (err error) { + data, err := yaml.Marshal(cfg) + if err != nil { + err = errors.New("Error marshalling config") + return err + } + + err = ioutil.WriteFile(filePath, data, os.ModePerm) + if err != nil { + err = errors.New("Error writing config file [" + filePath + "]") + return err + } + + return nil +} + +// ConfigIsIpv4 checks if IP address is IPV4 +func ConfigIsIpv4(host string) bool { + parts := strings.Split(host, ".") + if len(parts) < 4 { + return false + } + for _, x := range parts { + if i, err := strconv.Atoi(x); err == nil { + if i < 0 || i > 255 { + return false + } + } else { + return false + } + } + return true +} + +// InitRepoConfig initializes & returns the repo config +func InitRepoConfig() *viper.Viper { + repodir := viper.GetString("meep.gitdir") + RepoCfg = viper.New() + RepoCfg.SetConfigFile(repodir + "/.meepctl-repocfg.yaml") + if err := RepoCfg.ReadInConfig(); err == nil { + fmt.Println("Using repo config file:", RepoCfg.ConfigFileUsed()) + } else { + RepoCfg = nil + fmt.Println(err) + } + return RepoCfg +} diff --git a/go-apps/meepctl/utils/docker.go b/go-apps/meepctl/utils/docker.go new file mode 100644 index 0000000000000000000000000000000000000000..30926b1478fbf96ab3b958fddeca16f465c952e2 --- /dev/null +++ b/go-apps/meepctl/utils/docker.go @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package utils + +import ( + "errors" + "fmt" + "os/exec" + "strings" + "time" + + "github.com/spf13/cobra" +) + +// IsDockerImage Returns true if a Docker image exists +func IsDockerImage(name string, cobraCmd *cobra.Command) (exist bool, err error) { + exist = false + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + start := time.Now() + cmd := exec.Command("docker", "images", name, "-q") + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + if err != nil { + err = errors.New("Error listing component [" + name + "]") + fmt.Println(err) + } else { + s := string(out) + exist = s != "" + } + if verbose { + r := FormatResult("Result: "+string(out), elapsed, cobraCmd) + fmt.Println(r) + } + + return exist, err + +} + +// GetDockerTag Returns image tag +func GetDockerTag(name string, cobraCmd *cobra.Command) (tag string, err error) { + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + start := time.Now() + cmd := exec.Command("docker", "images", name) + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + if err != nil { + err = errors.New("Error listing component [" + name + "]") + fmt.Println(err) + } else { + s := string(out) + sl := strings.Fields(s) + tag = "" + for i, f := range sl { + if f == name { + tag = sl[i+1] + } + } + } + if verbose { + r := FormatResult("Result: "+string(out), elapsed, cobraCmd) + fmt.Println(r) + } + + return tag, err + +} + +// TagDockerImage Tag a docker image +func TagDockerImage(localRepo string, newRepo string, cobraCmd *cobra.Command) (err error) { + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + start := time.Now() + cmd := exec.Command("docker", "tag", localRepo, newRepo) + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + if err != nil { + err = errors.New("Error tagging Docker image [" + localRepo + "] to [" + newRepo + "]") + fmt.Println(err) + } + if verbose { + r := FormatResult("Result: "+string(out), elapsed, cobraCmd) + fmt.Println(r) + } + + return err + +} + +// PushDockerImage Push a docker image +func PushDockerImage(newRepo string, cobraCmd *cobra.Command) (err error) { + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + start := time.Now() + cmd := exec.Command("docker", "push", newRepo) + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + if err != nil { + err = errors.New("Error pushing Docker image [" + newRepo + "]") + fmt.Println(err) + } + if verbose { + r := FormatResult("Result: "+string(out), elapsed, cobraCmd) + fmt.Println(r) + } + + return err + +} + +// PullDockerImage Pulls a docker image +func PullDockerImage(repo string, cobraCmd *cobra.Command) (err error) { + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + start := time.Now() + cmd := exec.Command("docker", "pull", repo) + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + if err != nil { + err = errors.New("Error pulling Docker image [" + repo + "]") + fmt.Println(err) + } + if verbose { + r := FormatResult("Result: "+string(out), elapsed, cobraCmd) + fmt.Println(r) + } + + return err +} diff --git a/go-apps/meepctl/utils/exec.go b/go-apps/meepctl/utils/exec.go new file mode 100644 index 0000000000000000000000000000000000000000..42fa2b0eaceb307798fa7682412aadff9c0d5d91 --- /dev/null +++ b/go-apps/meepctl/utils/exec.go @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package utils + +import ( + "fmt" + "os/exec" + "strings" + "time" + + "github.com/spf13/cobra" +) + +// ExecuteCmd wraps exec.Command.CombinedOutput with verbosity +func ExecuteCmd(cmd *exec.Cmd, cobraCmd *cobra.Command) (output string, err error) { + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + start := time.Now() + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + output = string(out) + if verbose { + var r string + if len(output) > 0 { + r = "Result: " + output + } else { + r = "Result: OK" + } + r = FormatResult(r, elapsed, cobraCmd) + fmt.Println(r) + } + return output, err +} + +// GetProcess get a running process ID by name +func GetProcess(name string, cobraCmd *cobra.Command) (string, error) { + cmd := exec.Command("pidof", name) + pid, err := ExecuteCmd(cmd, cobraCmd) + if err != nil { + return pid, err + } + pid = strings.TrimSuffix(pid, "\n") + return pid, nil +} + +// WaitProcess get a running process ID by name +func WaitProcess(pid string, timeout string, cobraCmd *cobra.Command) error { + cmd := exec.Command("timeout", timeout, "tail", "--pid="+pid, "-f", "/dev/null") + _, err := ExecuteCmd(cmd, cobraCmd) + return err +} + +// KillProcess kill a process by PID +func KillProcess(pid string, cobraCmd *cobra.Command) { + cmd := exec.Command("kill", "-9", pid) + _, err := ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error terminating " + pid) + fmt.Println(err) + } +} + +// InterruptProcess SIGINT a process by PID +func InterruptProcess(pid string, cobraCmd *cobra.Command) { + cmd := exec.Command("kill", "-2", pid) + _, err := ExecuteCmd(cmd, cobraCmd) + if err != nil { + fmt.Println("Error interrupting " + pid) + fmt.Println(err) + } +} diff --git a/go-apps/meepctl/utils/format.go b/go-apps/meepctl/utils/format.go new file mode 100644 index 0000000000000000000000000000000000000000..1f6bca82c911b12d5c870e26c24bf685a05389c4 --- /dev/null +++ b/go-apps/meepctl/utils/format.go @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package utils + +import ( + "time" + + "github.com/spf13/cobra" +) + +// FormatResult consistent formatting for results to be displayed +func FormatResult(result string, elapsed time.Duration, cobraCmd *cobra.Command) string { + ret := result + + t, _ := cobraCmd.Flags().GetBool("time") + if t { + ret += (" [" + elapsed.Round(time.Millisecond).String() + "]") + } + + return ret +} diff --git a/go-apps/meepctl/utils/helm.go b/go-apps/meepctl/utils/helm.go new file mode 100644 index 0000000000000000000000000000000000000000..1e10d3596461bacfe54fcacbe62c666709a451b1 --- /dev/null +++ b/go-apps/meepctl/utils/helm.go @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package utils + +import ( + "errors" + "fmt" + "os/exec" + "strings" + "time" + + "github.com/spf13/cobra" +) + +// IsHelmRelease Returns true if a Helm release exists +func IsHelmRelease(name string, cobraCmd *cobra.Command) (exist bool, err error) { + exist = false + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + start := time.Now() + cmd := exec.Command("helm", "ls", name, "--short") + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + if err != nil { + err = errors.New("Error listing component [" + name + "]") + fmt.Println(err) + } else { + s := string(out) + exist = strings.HasPrefix(s, name) + + } + if verbose { + r := FormatResult("Result: "+string(out), elapsed, cobraCmd) + fmt.Println(r) + } + + return exist, err +} + +// HelmDelete Deletes specified release +func HelmDelete(name string, cobraCmd *cobra.Command) (err error) { + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + start := time.Now() + cmd := exec.Command("helm", "delete", name, "--purge") + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + + if err != nil { + err = errors.New("Error deleting component [" + name + "]") + fmt.Println(err) + } else { + r := FormatResult("Deleted "+name, elapsed, cobraCmd) + fmt.Println(r) + } + if verbose { + fmt.Println("Result: " + string(out)) + } + + return err +} + +// HelmInstall Install specified releases +func HelmInstall(name string, chart string, flags [][]string, cobraCmd *cobra.Command) (err error) { + err = nil + verbose, _ := cobraCmd.Flags().GetBool("verbose") + + start := time.Now() + cmd := exec.Command("helm", "install", "--name", name, "--set", "fullnameOverride="+name, chart, "--replace") + for _, f := range flags { + cmd.Args = append(cmd.Args, f[0]) + cmd.Args = append(cmd.Args, f[1]) + } + if verbose { + fmt.Println("Cmd:", cmd.Args) + } + out, err := cmd.CombinedOutput() + elapsed := time.Since(start) + if err != nil { + err = errors.New("Error installing component [" + name + "]") + fmt.Println(err) + } else { + r := FormatResult("Deployed "+name, elapsed, cobraCmd) + fmt.Println(r) + } + if verbose { + fmt.Println("Result: " + string(out)) + } + return err +} + +// HelmFlags Takes helm flag & value pair and formats it into an array of flag value pair +func HelmFlags(flagsIn [][]string, flag string, value string) (flagsOut [][]string) { + if flagsIn == nil { + flagsOut = make([][]string, 0) + } else { + flagsOut = flagsIn + } + if flag != "" { + f := make([]string, 0) + f = append(f, flag) + f = append(f, value) + flagsOut = append(flagsOut, f) + } + return flagsOut + +} diff --git a/go-apps/meepctl/utils/kibana.go b/go-apps/meepctl/utils/kibana.go new file mode 100644 index 0000000000000000000000000000000000000000..418c887b0b4bcd4cb7d298bcce3fc2ed902848ad --- /dev/null +++ b/go-apps/meepctl/utils/kibana.go @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package utils + +import ( + "bufio" + "errors" + "fmt" + "os" + "os/exec" + "strings" + "time" + + "github.com/roymx/viper" + "github.com/spf13/cobra" +) + +func DeployKibanaDashboards(cobraCmd *cobra.Command) { + + gitDir := viper.GetString("meep.gitdir") + "/" + workdir := viper.GetString("meep.workdir") + + start := time.Now() + + //make sure kibana is up and ready to receive messages + //this only happens when kibana is able to connect to elastic search + //so elastic search must be up and running as well as kibana for the rest api server to be up + isKibanaUp := false + kibanaFailedAttempts := 0 + for !isKibanaUp { + isKibanaUp = isKibanaReady(cobraCmd) + if !isKibanaUp { + kibanaFailedAttempts++ + if kibanaFailedAttempts > 3 { + elapsed := time.Since(start) + r := FormatResult("Failure during deployment kibana dashboards", elapsed, cobraCmd) + fmt.Println(r) + return + } + } + } + + cmd := exec.Command("cp", gitDir+"dashboards/dashboards.conf", workdir+"/tmp/dashboards.conf") + _, _ = ExecuteCmd(cmd, cobraCmd) + //search and replace in yaml file + tmpStr := strings.Replace(gitDir, "/", "\\/", -1) + str := "s//" + tmpStr + "/g" + cmd = exec.Command("sed", "-i", str, workdir+"/tmp/dashboards.conf") + _, _ = ExecuteCmd(cmd, cobraCmd) + + f, _ := os.Open(workdir + "/tmp/dashboards.conf") + //read file line by line + line := bufio.NewScanner(f) + for line.Scan() { + //dashboard[0] = name, dashboard[1] = location + dashboard := strings.Split(line.Text(), ":") + if dashboard != nil && dashboard[0] != "" && dashboard[0][0] != '#' { + //defaultIndex is reserved + if dashboard[0] == "defaultIndex" { + defaultIndex := strings.TrimSpace(dashboard[1]) + _ = uploadDefaultIndex(defaultIndex, cobraCmd) + } else { + if len(dashboard) >= 2 { + dashboard_location := strings.TrimSpace(dashboard[1]) + if dashboard_location[:4] == "http" { + //location is a http location, it had an extra":", so put back the string together + dashboard_location = strings.TrimSpace(dashboard[2][2:]) + uploadDashboardHttp(dashboard_location, cobraCmd) + } else { + uploadDashboardFile(dashboard_location, cobraCmd) + } + } + } + } + } + + err := line.Err() + if err != nil { + fmt.Println(err) + } + elapsed := time.Since(start) + r := FormatResult("Deployed kibana dashboards", elapsed, cobraCmd) + fmt.Println(r) + +} + +//sending a DUMMY value just to see if the service is up (conditions to be up are: +//- all elastic search(ES) pods are up +//- kibana pod is up +//- kibana connected successfully to ES +func isKibanaReady(cobraCmd *cobra.Command) bool { + isReady := false + err := uploadDefaultIndex("DUMMY", cobraCmd) + if err == nil { + isReady = true + } + return isReady +} + +func uploadDefaultIndex(indexId string, cobraCmd *cobra.Command) error { + kibanaHost, _ := os.Hostname() + cmd := exec.Command("curl", "-vX", "POST", "http://"+kibanaHost+":32003/api/kibana/settings/defaultIndex", "-H", "Content-Type: application/json", "-H", "kbn-xsrf: true", "-d", "{\"value\": \""+indexId+"\"}") + out, err := cmd.CombinedOutput() + if err != nil { + err = errors.New("Error sending a curl command") + } else { + str := string(out) + isServiceUnavailable := strings.Contains(str, "Service Unavailable") + + if isServiceUnavailable { + err = errors.New("Error: Service Unavailable") + } + } + + return err +} + +func uploadDashboardHttp(location string, cobraCmd *cobra.Command) { + //no support yet for url in kibana 6.4.2... but we can get the file to /tmp and then download the file + strArray := strings.Split(location, "/") + tmpLocation := "/tmp/" + strArray[len(strArray)-1] + cmd := exec.Command("wget", "-O", tmpLocation, location) + _, _ = ExecuteCmd(cmd, cobraCmd) + + uploadDashboardFile(tmpLocation, cobraCmd) +} + +func uploadDashboardFile(location string, cobraCmd *cobra.Command) { + kibanaHost, _ := os.Hostname() + //forcing the overwrite of already existing saved object with the same id + cmd := exec.Command("curl", "-vX", "POST", "http://"+kibanaHost+":32003/api/kibana/dashboards/import?force=true", "-H", "Content-Type: application/json", "-H", "kbn-xsrf: true", "-d", "@"+location) + _, _ = ExecuteCmd(cmd, cobraCmd) +} diff --git a/go-packages/meep-ctrl-engine-client/.gitignore b/go-packages/meep-ctrl-engine-client/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..daf913b1b347aae6de6f48d599bc89ef8c8693d6 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/go-packages/meep-ctrl-engine-client/.swagger-codegen-ignore b/go-packages/meep-ctrl-engine-client/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/go-packages/meep-ctrl-engine-client/.swagger-codegen/VERSION b/go-packages/meep-ctrl-engine-client/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..a6254504e40175d135cea7feb34ad31fa0d0bca3 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.1 \ No newline at end of file diff --git a/go-packages/meep-ctrl-engine-client/.travis.yml b/go-packages/meep-ctrl-engine-client/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..f5cb2ce9a5aad73c57eed886e845d2e79c2899d1 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/.travis.yml @@ -0,0 +1,8 @@ +language: go + +install: + - go get -d -v . + +script: + - go build -v ./ + diff --git a/go-packages/meep-ctrl-engine-client/README.md b/go-packages/meep-ctrl-engine-client/README.md new file mode 100644 index 0000000000000000000000000000000000000000..99fb0e357f22e1dae6b4672d1be51b74b00e6d96 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/README.md @@ -0,0 +1,75 @@ +# Go API client for client + +Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: 1.0.0 +- Package version: 1.0.0 +- Build package: io.swagger.codegen.languages.GoClientCodegen + +## Installation +Put the package under your project folder and add the following in import: +``` + "./client" +``` + +## Documentation for API Endpoints + +All URIs are relative to *http://localhost/v1* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*MEEPSettingsApi* | [**GetMeepSettings**](docs/MEEPSettingsApi.md#getmeepsettings) | **Get** /settings | Retrieve MEEP Controller settings +*MEEPSettingsApi* | [**SetMeepSettings**](docs/MEEPSettingsApi.md#setmeepsettings) | **Put** /settings | Set MEEP Controller settings +*PodStatesApi* | [**GetStates**](docs/PodStatesApi.md#getstates) | **Get** /states | This operation returns status information for pods +*ScenarioConfigurationApi* | [**CreateScenario**](docs/ScenarioConfigurationApi.md#createscenario) | **Post** /scenarios/{name} | Add new scenario to MEEP store +*ScenarioConfigurationApi* | [**DeleteScenario**](docs/ScenarioConfigurationApi.md#deletescenario) | **Delete** /scenarios/{name} | Delete scenario from MEEP store +*ScenarioConfigurationApi* | [**DeleteScenarioList**](docs/ScenarioConfigurationApi.md#deletescenariolist) | **Delete** /scenarios | Delete all scenarios in MEEP store +*ScenarioConfigurationApi* | [**GetScenario**](docs/ScenarioConfigurationApi.md#getscenario) | **Get** /scenarios/{name} | Retrieve scenario from MEEP store +*ScenarioConfigurationApi* | [**GetScenarioList**](docs/ScenarioConfigurationApi.md#getscenariolist) | **Get** /scenarios | Retrieve list of scenarios in MEEP store +*ScenarioConfigurationApi* | [**SetScenario**](docs/ScenarioConfigurationApi.md#setscenario) | **Put** /scenarios/{name} | Update scenario in MEEP store +*ScenarioExecutionApi* | [**ActivateScenario**](docs/ScenarioExecutionApi.md#activatescenario) | **Post** /active/{name} | Activate (deploy) scenario +*ScenarioExecutionApi* | [**GetActiveClientServiceMaps**](docs/ScenarioExecutionApi.md#getactiveclientservicemaps) | **Get** /active/serviceMaps | Retrieve list of active external client service mappings +*ScenarioExecutionApi* | [**GetActiveScenario**](docs/ScenarioExecutionApi.md#getactivescenario) | **Get** /active | Retrieve active (deployed) scenario +*ScenarioExecutionApi* | [**GetEventList**](docs/ScenarioExecutionApi.md#geteventlist) | **Get** /events | Retrieve list of supported event types for active (deployed) scenario +*ScenarioExecutionApi* | [**SendEvent**](docs/ScenarioExecutionApi.md#sendevent) | **Post** /events/{type} | Send event to active (deployed) scenario +*ScenarioExecutionApi* | [**TerminateScenario**](docs/ScenarioExecutionApi.md#terminatescenario) | **Delete** /active | Terminate active (deployed) scenario + + +## Documentation For Models + + - [ClientServiceMap](docs/ClientServiceMap.md) + - [Deployment](docs/Deployment.md) + - [Domain](docs/Domain.md) + - [Event](docs/Event.md) + - [EventList](docs/EventList.md) + - [EventNetworkCharacteristicsUpdate](docs/EventNetworkCharacteristicsUpdate.md) + - [EventOther](docs/EventOther.md) + - [EventPoasInRange](docs/EventPoasInRange.md) + - [EventUeMobility](docs/EventUeMobility.md) + - [ExternalConfig](docs/ExternalConfig.md) + - [NetworkLocation](docs/NetworkLocation.md) + - [PhysicalLocation](docs/PhysicalLocation.md) + - [PodStatus](docs/PodStatus.md) + - [PodsStatus](docs/PodsStatus.md) + - [Process](docs/Process.md) + - [Scenario](docs/Scenario.md) + - [ScenarioConfig](docs/ScenarioConfig.md) + - [ScenarioList](docs/ScenarioList.md) + - [ServiceConfig](docs/ServiceConfig.md) + - [ServiceMap](docs/ServiceMap.md) + - [ServicePort](docs/ServicePort.md) + - [Settings](docs/Settings.md) + - [Zone](docs/Zone.md) + + +## Documentation For Authorization + Endpoints do not require authorization. + + +## Author + + + diff --git a/interfaces/meep-ctrl-engine.yaml b/go-packages/meep-ctrl-engine-client/api/swagger.yaml similarity index 99% rename from interfaces/meep-ctrl-engine.yaml rename to go-packages/meep-ctrl-engine-client/api/swagger.yaml index 15a6b4766d024ddeae86a132b441ce01c1b86246..2bd4fafe5116a4e3e2f74b61b506e78b2447ccda 100644 --- a/interfaces/meep-ctrl-engine.yaml +++ b/go-packages/meep-ctrl-engine-client/api/swagger.yaml @@ -1,7 +1,9 @@ --- swagger: "2.0" info: - description: "MEEP Controller REST API" + description: "Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved.\ + \ The information provided herein is the proprietary and confidential information\ + \ of InterDigital Communications, Inc.\n" version: "1.0.0" title: "MEEP Controller REST API" basePath: "/v1" @@ -2462,12 +2464,6 @@ definitions: nbPodRestart: "15005" startTime: "2018-09-10 14:24:00 +0000 UTC" parameters: - AppName: - in: "body" - name: "appName" - description: "App name string" - required: true - x-exportParamName: "AppName" Name: name: "name" in: "path" @@ -2498,18 +2494,6 @@ parameters: schema: $ref: "http://localhost:8291/meep-model.yaml#/definitions/Event" x-exportParamName: "Event" - PodName: - in: "body" - name: "podName" - description: "Pod name string" - required: true - x-exportParamName: "PodName" - PodType: - in: "body" - name: "podType" - description: "Pod type string" - required: true - x-exportParamName: "PodType" Settings: in: "body" name: "settings" @@ -2518,12 +2502,6 @@ parameters: schema: $ref: "http://localhost:8291/meep-model.yaml#/definitions/Settings" x-exportParamName: "Settings" - ScenarioName: - in: "body" - name: "scenarioName" - description: "Scenario name string" - required: true - x-exportParamName: "ScenarioName" responses: Std200: description: "OK" diff --git a/go-packages/meep-ctrl-engine-client/api_client.go b/go-packages/meep-ctrl-engine-client/api_client.go new file mode 100644 index 0000000000000000000000000000000000000000..8c55dd3af020a9c8aed9658737bb048e6cb5b14e --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/api_client.go @@ -0,0 +1,430 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/net/context" + "golang.org/x/oauth2" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") + xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") +) + +// APIClient manages communication with the MEEP Controller REST API API v1.0.0 +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service // Reuse a single struct instead of allocating one for each service on the heap. + + // API Services + MEEPSettingsApi *MEEPSettingsApiService + PodStatesApi *PodStatesApiService + ScenarioConfigurationApi *ScenarioConfigurationApiService + ScenarioExecutionApi *ScenarioExecutionApiService +} + +type service struct { + client *APIClient +} + +// NewAPIClient creates a new API client. Requires a userAgent string describing your application. +// optionally a custom http.Client to allow for advanced features such as caching. +func NewAPIClient(cfg *Configuration) *APIClient { + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + + c := &APIClient{} + c.cfg = cfg + c.common.client = c + + // API Services + c.MEEPSettingsApi = (*MEEPSettingsApiService)(&c.common) + c.PodStatesApi = (*PodStatesApiService)(&c.common) + c.ScenarioConfigurationApi = (*ScenarioConfigurationApiService)(&c.common) + c.ScenarioExecutionApi = (*ScenarioExecutionApiService)(&c.common) + + return c +} + +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] // use the first content type specified in 'consumes' +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + // Make sure there is an object. + if obj == nil { + return nil + } + + // Check the type is as expected. + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string) string { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return fmt.Sprintf("%v", obj) +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// prepareRequest build the request +func (c *APIClient) prepareRequest( + ctx context.Context, + path string, method string, + postBody interface{}, + headerParams map[string]string, + queryParams url.Values, + formParams url.Values, + fileName string, + fileBytes []byte) (localVarRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + contentType := headerParams["Content-Type"] + if contentType == "" { + contentType = detectContentType(postBody) + headerParams["Content-Type"] = contentType + } + + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // add form parameters and file if available. + if len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { + if body != nil { + return nil, errors.New("Cannot specify postBody and multipart form at the same time.") + } + body = &bytes.Buffer{} + w := multipart.NewWriter(body) + + for k, v := range formParams { + for _, iv := range v { + if strings.HasPrefix(k, "@") { // file + err = addFile(w, k[1:], iv) + if err != nil { + return nil, err + } + } else { // form value + w.WriteField(k, iv) + } + } + } + if len(fileBytes) > 0 && fileName != "" { + w.Boundary() + //_, fileNm := filepath.Split(fileName) + part, err := w.CreateFormFile("file", filepath.Base(fileName)) + if err != nil { + return nil, err + } + _, err = part.Write(fileBytes) + if err != nil { + return nil, err + } + // Set the Boundary in the Content-Type + headerParams["Content-Type"] = w.FormDataContentType() + } + + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + w.Close() + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Adding Query Param + query := url.Query() + for k, v := range queryParams { + for _, iv := range v { + query.Add(k, iv) + } + } + + // Encode the parameters. + url.RawQuery = query.Encode() + + // Generate a new request + if body != nil { + localVarRequest, err = http.NewRequest(method, url.String(), body) + } else { + localVarRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add header parameters, if any + if len(headerParams) > 0 { + headers := http.Header{} + for h, v := range headerParams { + headers.Set(h, v) + } + localVarRequest.Header = headers + } + + // Override request host, if applicable + if c.cfg.Host != "" { + localVarRequest.Host = c.cfg.Host + } + + // Add the user agent to the request. + localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) + + if ctx != nil { + // add context to the request + localVarRequest = localVarRequest.WithContext(ctx) + + // Walk through any authentication. + + // OAuth2 authentication + if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { + // We were able to grab an oauth2 token from the context + var latestToken *oauth2.Token + if latestToken, err = tok.Token(); err != nil { + return nil, err + } + + latestToken.SetAuthHeader(localVarRequest) + } + + // Basic HTTP Authentication + if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { + localVarRequest.SetBasicAuth(auth.UserName, auth.Password) + } + + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) + } + } + + for header, value := range c.cfg.DefaultHeader { + localVarRequest.Header.Add(header, value) + } + + return localVarRequest, nil +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} diff --git a/go-packages/meep-ctrl-engine-client/api_response.go b/go-packages/meep-ctrl-engine-client/api_response.go new file mode 100644 index 0000000000000000000000000000000000000000..20225cf0b4797b24a3430b63eb366715147ae1bd --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/api_response.go @@ -0,0 +1,43 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "net/http" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/go-packages/meep-ctrl-engine-client/client_service_map.go b/go-packages/meep-ctrl-engine-client/client_service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..35564845e442aac285fd6e0905028284a94982f1 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/client_service_map.go @@ -0,0 +1,19 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Client-specific list of mappings of exposed port to internal service +type ClientServiceMap struct { + + // Unique external client identifier + Client string `json:"client,omitempty"` + + ServiceMap []ServiceMap `json:"serviceMap,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/configuration.go b/go-packages/meep-ctrl-engine-client/configuration.go new file mode 100644 index 0000000000000000000000000000000000000000..07da4229b2cd9f3ebb097241d0ef3def0ccce0f9 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/configuration.go @@ -0,0 +1,72 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "net/http" +) + +// contextKeys are used to identify the type of value in the context. +// Since these are string, it is possible to get a short description of the +// context key for logging and debugging using key.String(). + +type contextKey string + +func (c contextKey) String() string { + return "auth " + string(c) +} + +var ( + // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. + ContextOAuth2 = contextKey("token") + + // ContextBasicAuth takes BasicAuth as authentication for the request. + ContextBasicAuth = contextKey("basic") + + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") + + // ContextAPIKey takes an APIKey as authentication for the request + ContextAPIKey = contextKey("apikey") +) + +// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth +type BasicAuth struct { + UserName string `json:"userName,omitempty"` + Password string `json:"password,omitempty"` +} + +// APIKey provides API key based authentication to a request passed via context using ContextAPIKey +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "http://localhost/v1", + DefaultHeader: make(map[string]string), + UserAgent: "Swagger-Codegen/1.0.0/go", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/go-packages/meep-ctrl-engine-client/deployment.go b/go-packages/meep-ctrl-engine-client/deployment.go new file mode 100644 index 0000000000000000000000000000000000000000..17b04c8f0104f67e84bd356570f4c45528191235 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/deployment.go @@ -0,0 +1,28 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Network deployment object +type Deployment struct { + + // Latency in ms between domains + InterDomainLatency int32 `json:"interDomainLatency,omitempty"` + + // Latency variation in ms between domains + InterDomainLatencyVariation int32 `json:"interDomainLatencyVariation,omitempty"` + + // The limit of the traffic supported between domains + InterDomainThroughput int32 `json:"interDomainThroughput,omitempty"` + + // Packet lost (in terms of percentage) between domains + InterDomainPacketLoss float64 `json:"interDomainPacketLoss,omitempty"` + + Domains []Domain `json:"domains,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/docs/ClientServiceMap.md b/go-packages/meep-ctrl-engine-client/docs/ClientServiceMap.md new file mode 100644 index 0000000000000000000000000000000000000000..ab6a26d413c1c00848da0769a35a87d2bc087aa9 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ClientServiceMap.md @@ -0,0 +1,11 @@ +# ClientServiceMap + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Client** | **string** | Unique external client identifier | [optional] [default to null] +**ServiceMap** | [**[]ServiceMap**](ServiceMap.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/Deployment.md b/go-packages/meep-ctrl-engine-client/docs/Deployment.md new file mode 100644 index 0000000000000000000000000000000000000000..1ffa15070c5d5e35534890dfa800c321d3eb03f3 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/Deployment.md @@ -0,0 +1,14 @@ +# Deployment + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**InterDomainLatency** | **int32** | Latency in ms between domains | [optional] [default to null] +**InterDomainLatencyVariation** | **int32** | Latency variation in ms between domains | [optional] [default to null] +**InterDomainThroughput** | **int32** | The limit of the traffic supported between domains | [optional] [default to null] +**InterDomainPacketLoss** | **float64** | Packet lost (in terms of percentage) between domains | [optional] [default to null] +**Domains** | [**[]Domain**](Domain.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/Domain.md b/go-packages/meep-ctrl-engine-client/docs/Domain.md new file mode 100644 index 0000000000000000000000000000000000000000..6bdf9f243b0fccc61dfc94a2f9ae92469f809cd9 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/Domain.md @@ -0,0 +1,17 @@ +# Domain + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique domain ID | [optional] [default to null] +**Name** | **string** | Domain name | [optional] [default to null] +**Type_** | **string** | Domain type | [optional] [default to null] +**InterZoneLatency** | **int32** | Latency in ms between zones within domain | [optional] [default to null] +**InterZoneLatencyVariation** | **int32** | Latency variation in ms between zones within domain | [optional] [default to null] +**InterZoneThroughput** | **int32** | The limit of the traffic supported between zones within the domain | [optional] [default to null] +**InterZonePacketLoss** | **float64** | Packet lost (in terms of percentage) between zones within the domain | [optional] [default to null] +**Zones** | [**[]Zone**](Zone.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/Event.md b/go-packages/meep-ctrl-engine-client/docs/Event.md new file mode 100644 index 0000000000000000000000000000000000000000..33fd474fc8489ffa73eab78be973afea3b3006d9 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/Event.md @@ -0,0 +1,15 @@ +# Event + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Event name | [optional] [default to null] +**Type_** | **string** | Event type | [optional] [default to null] +**EventNetworkCharacteristicsUpdate** | [***EventNetworkCharacteristicsUpdate**](EventNetworkCharacteristicsUpdate.md) | | [optional] [default to null] +**EventUeMobility** | [***EventUeMobility**](EventUeMobility.md) | | [optional] [default to null] +**EventPoasInRange** | [***EventPoasInRange**](EventPoasInRange.md) | | [optional] [default to null] +**EventOther** | [***EventOther**](EventOther.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/EventList.md b/go-packages/meep-ctrl-engine-client/docs/EventList.md new file mode 100644 index 0000000000000000000000000000000000000000..0b0211421b1382f2b11f24b950a81b76904f831f --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/EventList.md @@ -0,0 +1,10 @@ +# EventList + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Events** | [**[]Event**](Event.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/EventNetworkCharacteristicsUpdate.md b/go-packages/meep-ctrl-engine-client/docs/EventNetworkCharacteristicsUpdate.md new file mode 100644 index 0000000000000000000000000000000000000000..29f2be3e32f90351a4462e5851e8f2bec5d08aaf --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/EventNetworkCharacteristicsUpdate.md @@ -0,0 +1,15 @@ +# EventNetworkCharacteristicsUpdate + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ElementName** | **string** | Name of the network element to be updated | [optional] [default to null] +**ElementType** | **string** | Type of the network element to be updated | [optional] [default to null] +**Latency** | **int32** | Latency in ms | [optional] [default to null] +**LatencyVariation** | **int32** | Latency variation in ms | [optional] [default to null] +**Throughput** | **int32** | Throughput limit | [optional] [default to null] +**PacketLoss** | **float64** | Packet loss percentage | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/EventOther.md b/go-packages/meep-ctrl-engine-client/docs/EventOther.md new file mode 100644 index 0000000000000000000000000000000000000000..df06c50f6a72108d8cb82cc5f12d78c91565e0ef --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/EventOther.md @@ -0,0 +1,10 @@ +# EventOther + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Event** | **string** | Other event string | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/EventPoasInRange.md b/go-packages/meep-ctrl-engine-client/docs/EventPoasInRange.md new file mode 100644 index 0000000000000000000000000000000000000000..640a0aec15b81fc6595e5a6cac9f9d3107dc55ee --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/EventPoasInRange.md @@ -0,0 +1,11 @@ +# EventPoasInRange + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Ue** | **string** | UE identifier | [optional] [default to null] +**PoasInRange** | **[]string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/EventUeMobility.md b/go-packages/meep-ctrl-engine-client/docs/EventUeMobility.md new file mode 100644 index 0000000000000000000000000000000000000000..0df09a5791ffc3a7a4829682d84be165e2774f67 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/EventUeMobility.md @@ -0,0 +1,11 @@ +# EventUeMobility + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Ue** | **string** | UE identifier | [optional] [default to null] +**Dest** | **string** | Destination identifier | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/ExternalConfig.md b/go-packages/meep-ctrl-engine-client/docs/ExternalConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..7a25f4aad9e315036f94794ed3e7f49c14cf451d --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ExternalConfig.md @@ -0,0 +1,11 @@ +# ExternalConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**IngressServiceMap** | [**[]ServiceMap**](ServiceMap.md) | | [optional] [default to null] +**EgressServiceMap** | [**[]ServiceMap**](ServiceMap.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/MEEPSettingsApi.md b/go-packages/meep-ctrl-engine-client/docs/MEEPSettingsApi.md new file mode 100644 index 0000000000000000000000000000000000000000..a8105103e5b8ebee70bfe62c89760e58666b266b --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/MEEPSettingsApi.md @@ -0,0 +1,62 @@ +# \MEEPSettingsApi + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**GetMeepSettings**](MEEPSettingsApi.md#GetMeepSettings) | **Get** /settings | Retrieve MEEP Controller settings +[**SetMeepSettings**](MEEPSettingsApi.md#SetMeepSettings) | **Put** /settings | Set MEEP Controller settings + + +# **GetMeepSettings** +> Settings GetMeepSettings(ctx, ) +Retrieve MEEP Controller settings + + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + +[**Settings**](Settings.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **SetMeepSettings** +> SetMeepSettings(ctx, settings) +Set MEEP Controller settings + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **settings** | [**Settings**](Settings.md)| MEEP Settings | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-ctrl-engine-client/docs/NetworkLocation.md b/go-packages/meep-ctrl-engine-client/docs/NetworkLocation.md new file mode 100644 index 0000000000000000000000000000000000000000..6599c7cd83dc42930bae089da6fb918013addf0d --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/NetworkLocation.md @@ -0,0 +1,17 @@ +# NetworkLocation + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique network location ID | [optional] [default to null] +**Name** | **string** | Network location name | [optional] [default to null] +**Type_** | **string** | Network location type | [optional] [default to null] +**TerminalLinkLatency** | **int32** | Latency in ms for all terminal links within network location | [optional] [default to null] +**TerminalLinkLatencyVariation** | **int32** | Latency variation in ms for all terminal links within network location | [optional] [default to null] +**TerminalLinkThroughput** | **int32** | The limit of the traffic supported for all terminal links within the network location | [optional] [default to null] +**TerminalLinkPacketLoss** | **float64** | Packet lost (in terms of percentage) for all terminal links within the network location | [optional] [default to null] +**PhysicalLocations** | [**[]PhysicalLocation**](PhysicalLocation.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/PhysicalLocation.md b/go-packages/meep-ctrl-engine-client/docs/PhysicalLocation.md new file mode 100644 index 0000000000000000000000000000000000000000..321343c2471f6bcb457e5deeb43b895526febfb6 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/PhysicalLocation.md @@ -0,0 +1,15 @@ +# PhysicalLocation + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique physical location ID | [optional] [default to null] +**Name** | **string** | Physical location name | [optional] [default to null] +**Type_** | **string** | Physical location type | [optional] [default to null] +**IsExternal** | **bool** | true: Physical location is external to MEEP false: Physical location is internal to MEEP | [optional] [default to null] +**NetworkLocationsInRange** | **[]string** | | [optional] [default to null] +**Processes** | [**[]Process**](Process.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/PodStatesApi.md b/go-packages/meep-ctrl-engine-client/docs/PodStatesApi.md new file mode 100644 index 0000000000000000000000000000000000000000..ff7932b4be5c2cf43289f9f98f20b39da4de8f2b --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/PodStatesApi.md @@ -0,0 +1,45 @@ +# \PodStatesApi + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**GetStates**](PodStatesApi.md#GetStates) | **Get** /states | This operation returns status information for pods + + +# **GetStates** +> PodsStatus GetStates(ctx, optional) +This operation returns status information for pods + +Returns pod status info for a list of pods + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **optional** | **map[string]interface{}** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a map[string]interface{}. + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **long** | **string**| Enables detailed stats if true | + **type_** | **string**| Pod type | + +### Return type + +[**PodsStatus**](PodsStatus.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-ctrl-engine-client/docs/PodStatus.md b/go-packages/meep-ctrl-engine-client/docs/PodStatus.md new file mode 100644 index 0000000000000000000000000000000000000000..a23be3ed2cf7929fa24d25aa52531d66d17a6a46 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/PodStatus.md @@ -0,0 +1,26 @@ +# PodStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Pod name | [optional] [default to null] +**Namespace** | **string** | Pod namespace | [optional] [default to null] +**MeepApp** | **string** | Pod process name | [optional] [default to null] +**MeepOrigin** | **string** | Pod origin(core, scenario) | [optional] [default to null] +**MeepScenario** | **string** | Pod scenario name | [optional] [default to null] +**Phase** | **string** | Pod phase | [optional] [default to null] +**PodInitialized** | **string** | Pod initialized (true/false) | [optional] [default to null] +**PodReady** | **string** | Pod ready (true/false) | [optional] [default to null] +**PodScheduled** | **string** | Pod scheduled (true/false) | [optional] [default to null] +**PodUnschedulable** | **string** | Pod unschedulable (true/false) | [optional] [default to null] +**PodConditionError** | **string** | Pod error message | [optional] [default to null] +**ContainerStatusesMsg** | **string** | Failed container error message | [optional] [default to null] +**NbOkContainers** | **string** | Number of containers that are up | [optional] [default to null] +**NbTotalContainers** | **string** | Number of total containers in the pod | [optional] [default to null] +**NbPodRestart** | **string** | Number of container failures leading to pod restarts | [optional] [default to null] +**LogicalState** | **string** | State that is mapping the kubernetes api state | [optional] [default to null] +**StartTime** | **string** | Pod creation time | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/PodsStatus.md b/go-packages/meep-ctrl-engine-client/docs/PodsStatus.md new file mode 100644 index 0000000000000000000000000000000000000000..148d06e683d0a51f84ae61485d60d1347c6456f5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/PodsStatus.md @@ -0,0 +1,10 @@ +# PodsStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**PodStatus** | [**[]PodStatus**](PodStatus.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/Process.md b/go-packages/meep-ctrl-engine-client/docs/Process.md new file mode 100644 index 0000000000000000000000000000000000000000..1e32ea0e21a98b9be00a73c0ec6e4d279f0b92e4 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/Process.md @@ -0,0 +1,23 @@ +# Process + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique process ID | [optional] [default to null] +**Name** | **string** | Process name | [optional] [default to null] +**Type_** | **string** | Process type | [optional] [default to null] +**IsExternal** | **bool** | true: process is external to MEEP false: process is internal to MEEP | [optional] [default to null] +**Image** | **string** | Docker image to deploy inside MEEP | [optional] [default to null] +**Environment** | **string** | Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" | [optional] [default to null] +**CommandArguments** | **string** | Arguments to command executable | [optional] [default to null] +**CommandExe** | **string** | Executable to invoke at container start up | [optional] [default to null] +**ServiceConfig** | [***ServiceConfig**](ServiceConfig.md) | | [optional] [default to null] +**ExternalConfig** | [***ExternalConfig**](ExternalConfig.md) | | [optional] [default to null] +**Status** | **string** | Process status | [optional] [default to null] +**UserChartLocation** | **string** | Chart location for the deployment of the chart provided by the user | [optional] [default to null] +**UserChartAlternateValues** | **string** | Chart values.yaml file location for the deployment of the chart provided by the user | [optional] [default to null] +**UserChartGroup** | **string** | Chart supplemental information related to the group (service) | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/Scenario.md b/go-packages/meep-ctrl-engine-client/docs/Scenario.md new file mode 100644 index 0000000000000000000000000000000000000000..eb4a453d0fe6ebaddef6f3dfe96279ff643bc8ce --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/Scenario.md @@ -0,0 +1,12 @@ +# Scenario + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Unique scenario name | [optional] [default to null] +**Config** | [***ScenarioConfig**](ScenarioConfig.md) | | [optional] [default to null] +**Deployment** | [***Deployment**](Deployment.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/ScenarioConfig.md b/go-packages/meep-ctrl-engine-client/docs/ScenarioConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..0f6e1dbeee6174a63026df8c4ffb2e036a371029 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ScenarioConfig.md @@ -0,0 +1,11 @@ +# ScenarioConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Visualization** | **string** | Visualization configuration | [optional] [default to null] +**Other** | **string** | Other scenario configuration | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/ScenarioConfigurationApi.md b/go-packages/meep-ctrl-engine-client/docs/ScenarioConfigurationApi.md new file mode 100644 index 0000000000000000000000000000000000000000..49c8f1dc248755c65d95701cc16f77653382c484 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ScenarioConfigurationApi.md @@ -0,0 +1,176 @@ +# \ScenarioConfigurationApi + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**CreateScenario**](ScenarioConfigurationApi.md#CreateScenario) | **Post** /scenarios/{name} | Add new scenario to MEEP store +[**DeleteScenario**](ScenarioConfigurationApi.md#DeleteScenario) | **Delete** /scenarios/{name} | Delete scenario from MEEP store +[**DeleteScenarioList**](ScenarioConfigurationApi.md#DeleteScenarioList) | **Delete** /scenarios | Delete all scenarios in MEEP store +[**GetScenario**](ScenarioConfigurationApi.md#GetScenario) | **Get** /scenarios/{name} | Retrieve scenario from MEEP store +[**GetScenarioList**](ScenarioConfigurationApi.md#GetScenarioList) | **Get** /scenarios | Retrieve list of scenarios in MEEP store +[**SetScenario**](ScenarioConfigurationApi.md#SetScenario) | **Put** /scenarios/{name} | Update scenario in MEEP store + + +# **CreateScenario** +> CreateScenario(ctx, name, scenario) +Add new scenario to MEEP store + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **name** | **string**| Scenario name | + **scenario** | [**Scenario**](Scenario.md)| Scenario to add to MEEP store | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **DeleteScenario** +> DeleteScenario(ctx, name) +Delete scenario from MEEP store + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **name** | **string**| Scenario name | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **DeleteScenarioList** +> DeleteScenarioList(ctx, ) +Delete all scenarios in MEEP store + + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetScenario** +> Scenario GetScenario(ctx, name) +Retrieve scenario from MEEP store + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **name** | **string**| Scenario name | + +### Return type + +[**Scenario**](Scenario.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetScenarioList** +> ScenarioList GetScenarioList(ctx, ) +Retrieve list of scenarios in MEEP store + + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + +[**ScenarioList**](ScenarioList.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **SetScenario** +> SetScenario(ctx, name, scenario) +Update scenario in MEEP store + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **name** | **string**| Scenario name | + **scenario** | [**Scenario**](Scenario.md)| Scenario to add to MEEP store | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-ctrl-engine-client/docs/ScenarioExecutionApi.md b/go-packages/meep-ctrl-engine-client/docs/ScenarioExecutionApi.md new file mode 100644 index 0000000000000000000000000000000000000000..cb00c056c2f13a7c9027eca2e8c858a91d18a196 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ScenarioExecutionApi.md @@ -0,0 +1,179 @@ +# \ScenarioExecutionApi + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**ActivateScenario**](ScenarioExecutionApi.md#ActivateScenario) | **Post** /active/{name} | Activate (deploy) scenario +[**GetActiveClientServiceMaps**](ScenarioExecutionApi.md#GetActiveClientServiceMaps) | **Get** /active/serviceMaps | Retrieve list of active external client service mappings +[**GetActiveScenario**](ScenarioExecutionApi.md#GetActiveScenario) | **Get** /active | Retrieve active (deployed) scenario +[**GetEventList**](ScenarioExecutionApi.md#GetEventList) | **Get** /events | Retrieve list of supported event types for active (deployed) scenario +[**SendEvent**](ScenarioExecutionApi.md#SendEvent) | **Post** /events/{type} | Send event to active (deployed) scenario +[**TerminateScenario**](ScenarioExecutionApi.md#TerminateScenario) | **Delete** /active | Terminate active (deployed) scenario + + +# **ActivateScenario** +> ActivateScenario(ctx, name) +Activate (deploy) scenario + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **name** | **string**| Scenario name | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetActiveClientServiceMaps** +> []ClientServiceMap GetActiveClientServiceMaps(ctx, optional) +Retrieve list of active external client service mappings + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **optional** | **map[string]interface{}** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a map[string]interface{}. + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **client** | **string**| Unique client identifier | + **service** | **string**| Exposed service name | + +### Return type + +[**[]ClientServiceMap**](ClientServiceMap.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetActiveScenario** +> Scenario GetActiveScenario(ctx, ) +Retrieve active (deployed) scenario + + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + +[**Scenario**](Scenario.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetEventList** +> EventList GetEventList(ctx, ) +Retrieve list of supported event types for active (deployed) scenario + + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + +[**EventList**](EventList.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **SendEvent** +> SendEvent(ctx, type_, event) +Send event to active (deployed) scenario + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **type_** | **string**| Event type | + **event** | [**Event**](Event.md)| Event to send to active scenario | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TerminateScenario** +> TerminateScenario(ctx, ) +Terminate active (deployed) scenario + + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-ctrl-engine-client/docs/ScenarioList.md b/go-packages/meep-ctrl-engine-client/docs/ScenarioList.md new file mode 100644 index 0000000000000000000000000000000000000000..99bf8929d621ec6bd487bf3ee7e3f00a92f17425 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ScenarioList.md @@ -0,0 +1,10 @@ +# ScenarioList + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Scenarios** | [**[]Scenario**](Scenario.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/ServiceConfig.md b/go-packages/meep-ctrl-engine-client/docs/ServiceConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..6db2202b3aa2fd40150333ca1be13f854a10f7c5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ServiceConfig.md @@ -0,0 +1,12 @@ +# ServiceConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Unique service name | [optional] [default to null] +**MeSvcName** | **string** | Multi-Edge service name, if any | [optional] [default to null] +**Ports** | [**[]ServicePort**](ServicePort.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/ServiceMap.md b/go-packages/meep-ctrl-engine-client/docs/ServiceMap.md new file mode 100644 index 0000000000000000000000000000000000000000..c8ac3a0a957d39752d1af1a792e188d307b9a5d5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ServiceMap.md @@ -0,0 +1,14 @@ +# ServiceMap + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Service name | [optional] [default to null] +**Ip** | **string** | Service IP address for external service only (egress) <li>N/A for internal services | [optional] [default to null] +**Port** | **int32** | Service port number | [optional] [default to null] +**ExternalPort** | **int32** | Port used to expose internal service only (ingress) <li>Must be unique port in range (30000 - 32767) <li>N/A for external services | [optional] [default to null] +**Protocol** | **string** | Protocol that the application is using (TCP or UDP) | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/ServicePort.md b/go-packages/meep-ctrl-engine-client/docs/ServicePort.md new file mode 100644 index 0000000000000000000000000000000000000000..6b6c33d586b9c04db79900945f2904fc4eaba286 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/ServicePort.md @@ -0,0 +1,12 @@ +# ServicePort + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Protocol** | **string** | Protocol that the application is using (TCP or UDP) | [optional] [default to null] +**Port** | **int32** | Port number that the service is listening on | [optional] [default to null] +**ExternalPort** | **int32** | External port number on which to expose the application (30000 - 32767) <li>Only one application allowed per external port <li>Scenario builder must configure to prevent conflicts | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/Settings.md b/go-packages/meep-ctrl-engine-client/docs/Settings.md new file mode 100644 index 0000000000000000000000000000000000000000..0bd3d571efdb26096a75efe9972a55674e449853 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/Settings.md @@ -0,0 +1,9 @@ +# Settings + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/docs/Zone.md b/go-packages/meep-ctrl-engine-client/docs/Zone.md new file mode 100644 index 0000000000000000000000000000000000000000..5e24dc058eca726e53670004beb9f67eb9588724 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/docs/Zone.md @@ -0,0 +1,25 @@ +# Zone + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique zone ID | [optional] [default to null] +**Name** | **string** | Zone name | [optional] [default to null] +**Type_** | **string** | Zone type | [optional] [default to null] +**InterFogLatency** | **int32** | Latency in ms between fog nodes (or PoAs) within zone | [optional] [default to null] +**InterFogLatencyVariation** | **int32** | Latency variation in ms between fog nodes (or PoAs) within zone | [optional] [default to null] +**InterFogThroughput** | **int32** | The limit of the traffic supported between fog nodes (or PoAs) within the zone | [optional] [default to null] +**InterFogPacketLoss** | **float64** | Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone | [optional] [default to null] +**InterEdgeLatency** | **int32** | Latency in ms between edge nodes within zone | [optional] [default to null] +**InterEdgeLatencyVariation** | **int32** | Latency variation in ms between edge nodes within zone | [optional] [default to null] +**InterEdgeThroughput** | **int32** | The limit of the traffic supported between edge nodes within the zone | [optional] [default to null] +**InterEdgePacketLoss** | **float64** | Packet lost (in terms of percentage) between edge nodes within the zone | [optional] [default to null] +**EdgeFogLatency** | **int32** | Latency in ms between fog nodes (or PoAs) and edge nodes within zone | [optional] [default to null] +**EdgeFogLatencyVariation** | **int32** | Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone | [optional] [default to null] +**EdgeFogThroughput** | **int32** | The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone | [optional] [default to null] +**EdgeFogPacketLoss** | **float64** | Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone | [optional] [default to null] +**NetworkLocations** | [**[]NetworkLocation**](NetworkLocation.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-client/domain.go b/go-packages/meep-ctrl-engine-client/domain.go new file mode 100644 index 0000000000000000000000000000000000000000..cb73b6d5cbf4aa342c182b292f6f165d9cd575dc --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/domain.go @@ -0,0 +1,37 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Operator domain object +type Domain struct { + + // Unique domain ID + Id string `json:"id,omitempty"` + + // Domain name + Name string `json:"name,omitempty"` + + // Domain type + Type_ string `json:"type,omitempty"` + + // Latency in ms between zones within domain + InterZoneLatency int32 `json:"interZoneLatency,omitempty"` + + // Latency variation in ms between zones within domain + InterZoneLatencyVariation int32 `json:"interZoneLatencyVariation,omitempty"` + + // The limit of the traffic supported between zones within the domain + InterZoneThroughput int32 `json:"interZoneThroughput,omitempty"` + + // Packet lost (in terms of percentage) between zones within the domain + InterZonePacketLoss float64 `json:"interZonePacketLoss,omitempty"` + + Zones []Zone `json:"zones,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/event.go b/go-packages/meep-ctrl-engine-client/event.go new file mode 100644 index 0000000000000000000000000000000000000000..aeff23dbef7900dae29f0dd4c59c9b1d29ab6a44 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/event.go @@ -0,0 +1,28 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Event object +type Event struct { + + // Event name + Name string `json:"name,omitempty"` + + // Event type + Type_ string `json:"type,omitempty"` + + EventNetworkCharacteristicsUpdate *EventNetworkCharacteristicsUpdate `json:"eventNetworkCharacteristicsUpdate,omitempty"` + + EventUeMobility *EventUeMobility `json:"eventUeMobility,omitempty"` + + EventPoasInRange *EventPoasInRange `json:"eventPoasInRange,omitempty"` + + EventOther *EventOther `json:"eventOther,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/event_list.go b/go-packages/meep-ctrl-engine-client/event_list.go new file mode 100644 index 0000000000000000000000000000000000000000..a61415d7811f6955a0978a90af0d6cd367be5533 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/event_list.go @@ -0,0 +1,15 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Event list object +type EventList struct { + Events []Event `json:"events,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/event_network_characteristics_update.go b/go-packages/meep-ctrl-engine-client/event_network_characteristics_update.go new file mode 100644 index 0000000000000000000000000000000000000000..25a729228dda0c697d061734e6368e793d4c40f6 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/event_network_characteristics_update.go @@ -0,0 +1,32 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Network Characteristics update Event object +type EventNetworkCharacteristicsUpdate struct { + + // Name of the network element to be updated + ElementName string `json:"elementName,omitempty"` + + // Type of the network element to be updated + ElementType string `json:"elementType,omitempty"` + + // Latency in ms + Latency int32 `json:"latency,omitempty"` + + // Latency variation in ms + LatencyVariation int32 `json:"latencyVariation,omitempty"` + + // Throughput limit + Throughput int32 `json:"throughput,omitempty"` + + // Packet loss percentage + PacketLoss float64 `json:"packetLoss,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/event_other.go b/go-packages/meep-ctrl-engine-client/event_other.go new file mode 100644 index 0000000000000000000000000000000000000000..32cad96c24989937bba2f12a7d32cefd9ff003db --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/event_other.go @@ -0,0 +1,17 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Other Event object +type EventOther struct { + + // Other event string + Event string `json:"event,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/event_poas_in_range.go b/go-packages/meep-ctrl-engine-client/event_poas_in_range.go new file mode 100644 index 0000000000000000000000000000000000000000..9c965d10262f04b642d0a3e6734c74bd93710549 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/event_poas_in_range.go @@ -0,0 +1,19 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// POAs In Range Event object +type EventPoasInRange struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + PoasInRange []string `json:"poasInRange,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/event_ue_mobility.go b/go-packages/meep-ctrl-engine-client/event_ue_mobility.go new file mode 100644 index 0000000000000000000000000000000000000000..7be3a19a6838229e066c423d7b850e482cf56b12 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/event_ue_mobility.go @@ -0,0 +1,20 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// UE Mobility Event object +type EventUeMobility struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + // Destination identifier + Dest string `json:"dest,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/external_config.go b/go-packages/meep-ctrl-engine-client/external_config.go new file mode 100644 index 0000000000000000000000000000000000000000..bdd881bc171f4daf046d38fe0f5d510beb34306c --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/external_config.go @@ -0,0 +1,17 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// External Process configuration. NOTE: Only valid if 'isExternal' is set. +type ExternalConfig struct { + IngressServiceMap []ServiceMap `json:"ingressServiceMap,omitempty"` + + EgressServiceMap []ServiceMap `json:"egressServiceMap,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/git_push.sh b/go-packages/meep-ctrl-engine-client/git_push.sh new file mode 100644 index 0000000000000000000000000000000000000000..ae01b182ae9eb047d0999a496b060e62d7b01e5c --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/go-packages/meep-ctrl-engine-client/go.mod b/go-packages/meep-ctrl-engine-client/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..d3253c035a674c5b6561e66f14910a2e9cb3b12f --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/go.mod @@ -0,0 +1,8 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-client + +go 1.12 + +require ( + golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 + golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a +) diff --git a/go-packages/meep-ctrl-engine-client/go.sum b/go-packages/meep-ctrl-engine-client/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..140259886aed6f6e5a98be4585ab29c9af9112fd --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/go.sum @@ -0,0 +1,16 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 h1:tzVWzOrXxwAwdSCMrf+mbNrZFxwS0+HLP4m2qxtfdhk= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/go-packages/meep-ctrl-engine-client/meep_settings_api.go b/go-packages/meep-ctrl-engine-client/meep_settings_api.go new file mode 100644 index 0000000000000000000000000000000000000000..fa9231f7832ac9cadeedd1c02a2c9956d5b08760 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/meep_settings_api.go @@ -0,0 +1,147 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type MEEPSettingsApiService service + +/* MEEPSettingsApiService Retrieve MEEP Controller settings + + * @param ctx context.Context for authentication, logging, tracing, etc. + @return Settings*/ +func (a *MEEPSettingsApiService) GetMeepSettings(ctx context.Context) (Settings, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload Settings + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/settings" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* MEEPSettingsApiService Set MEEP Controller settings + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param settings MEEP Settings +@return */ +func (a *MEEPSettingsApiService) SetMeepSettings(ctx context.Context, settings Settings) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Put") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/settings" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &settings + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} diff --git a/go-packages/meep-ctrl-engine-client/network_location.go b/go-packages/meep-ctrl-engine-client/network_location.go new file mode 100644 index 0000000000000000000000000000000000000000..b9afe439556b98879dc9e8b0c040eb4bee4e4bd5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/network_location.go @@ -0,0 +1,37 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Logical network location object +type NetworkLocation struct { + + // Unique network location ID + Id string `json:"id,omitempty"` + + // Network location name + Name string `json:"name,omitempty"` + + // Network location type + Type_ string `json:"type,omitempty"` + + // Latency in ms for all terminal links within network location + TerminalLinkLatency int32 `json:"terminalLinkLatency,omitempty"` + + // Latency variation in ms for all terminal links within network location + TerminalLinkLatencyVariation int32 `json:"terminalLinkLatencyVariation,omitempty"` + + // The limit of the traffic supported for all terminal links within the network location + TerminalLinkThroughput int32 `json:"terminalLinkThroughput,omitempty"` + + // Packet lost (in terms of percentage) for all terminal links within the network location + TerminalLinkPacketLoss float64 `json:"terminalLinkPacketLoss,omitempty"` + + PhysicalLocations []PhysicalLocation `json:"physicalLocations,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/physical_location.go b/go-packages/meep-ctrl-engine-client/physical_location.go new file mode 100644 index 0000000000000000000000000000000000000000..7e7eb338332b7e64b6a09e3ab2ab1924faebecd4 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/physical_location.go @@ -0,0 +1,30 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Physical location object +type PhysicalLocation struct { + + // Unique physical location ID + Id string `json:"id,omitempty"` + + // Physical location name + Name string `json:"name,omitempty"` + + // Physical location type + Type_ string `json:"type,omitempty"` + + // true: Physical location is external to MEEP false: Physical location is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + NetworkLocationsInRange []string `json:"networkLocationsInRange,omitempty"` + + Processes []Process `json:"processes,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/pod_states_api.go b/go-packages/meep-ctrl-engine-client/pod_states_api.go new file mode 100644 index 0000000000000000000000000000000000000000..c39904af0914d3021147eb04afa4bcec0308bc81 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/pod_states_api.go @@ -0,0 +1,104 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type PodStatesApiService service + +/* PodStatesApiService This operation returns status information for pods +Returns pod status info for a list of pods +* @param ctx context.Context for authentication, logging, tracing, etc. +@param optional (nil or map[string]interface{}) with one or more of: + @param "long" (string) Enables detailed stats if true + @param "type_" (string) Pod type +@return PodsStatus*/ +func (a *PodStatesApiService) GetStates(ctx context.Context, localVarOptionals map[string]interface{}) (PodsStatus, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload PodsStatus + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/states" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if err := typeCheckParameter(localVarOptionals["long"], "string", "long"); err != nil { + return successPayload, nil, err + } + if err := typeCheckParameter(localVarOptionals["type_"], "string", "type_"); err != nil { + return successPayload, nil, err + } + + if localVarTempParam, localVarOk := localVarOptionals["long"].(string); localVarOk { + localVarQueryParams.Add("long", parameterToString(localVarTempParam, "")) + } + if localVarTempParam, localVarOk := localVarOptionals["type_"].(string); localVarOk { + localVarQueryParams.Add("type", parameterToString(localVarTempParam, "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} diff --git a/go-packages/meep-ctrl-engine-client/pod_status.go b/go-packages/meep-ctrl-engine-client/pod_status.go new file mode 100644 index 0000000000000000000000000000000000000000..8c7afbeb08d5a9c2cf694475ef3664dd350e99e0 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/pod_status.go @@ -0,0 +1,64 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +type PodStatus struct { + + // Pod name + Name string `json:"name,omitempty"` + + // Pod namespace + Namespace string `json:"namespace,omitempty"` + + // Pod process name + MeepApp string `json:"meepApp,omitempty"` + + // Pod origin(core, scenario) + MeepOrigin string `json:"meepOrigin,omitempty"` + + // Pod scenario name + MeepScenario string `json:"meepScenario,omitempty"` + + // Pod phase + Phase string `json:"phase,omitempty"` + + // Pod initialized (true/false) + PodInitialized string `json:"podInitialized,omitempty"` + + // Pod ready (true/false) + PodReady string `json:"podReady,omitempty"` + + // Pod scheduled (true/false) + PodScheduled string `json:"podScheduled,omitempty"` + + // Pod unschedulable (true/false) + PodUnschedulable string `json:"podUnschedulable,omitempty"` + + // Pod error message + PodConditionError string `json:"podConditionError,omitempty"` + + // Failed container error message + ContainerStatusesMsg string `json:"containerStatusesMsg,omitempty"` + + // Number of containers that are up + NbOkContainers string `json:"nbOkContainers,omitempty"` + + // Number of total containers in the pod + NbTotalContainers string `json:"nbTotalContainers,omitempty"` + + // Number of container failures leading to pod restarts + NbPodRestart string `json:"nbPodRestart,omitempty"` + + // State that is mapping the kubernetes api state + LogicalState string `json:"logicalState,omitempty"` + + // Pod creation time + StartTime string `json:"startTime,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/pods_status.go b/go-packages/meep-ctrl-engine-client/pods_status.go new file mode 100644 index 0000000000000000000000000000000000000000..ed549103c500ac431c96c29e1d3c24b6baa9c478 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/pods_status.go @@ -0,0 +1,15 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// List of all pods status +type PodsStatus struct { + PodStatus []PodStatus `json:"podStatus,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/process.go b/go-packages/meep-ctrl-engine-client/process.go new file mode 100644 index 0000000000000000000000000000000000000000..608ab5a567fed5df937733afc1b7eb8f95f16855 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/process.go @@ -0,0 +1,54 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Application or service object +type Process struct { + + // Unique process ID + Id string `json:"id,omitempty"` + + // Process name + Name string `json:"name,omitempty"` + + // Process type + Type_ string `json:"type,omitempty"` + + // true: process is external to MEEP false: process is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + // Docker image to deploy inside MEEP + Image string `json:"image,omitempty"` + + // Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" + Environment string `json:"environment,omitempty"` + + // Arguments to command executable + CommandArguments string `json:"commandArguments,omitempty"` + + // Executable to invoke at container start up + CommandExe string `json:"commandExe,omitempty"` + + ServiceConfig *ServiceConfig `json:"serviceConfig,omitempty"` + + ExternalConfig *ExternalConfig `json:"externalConfig,omitempty"` + + // Process status + Status string `json:"status,omitempty"` + + // Chart location for the deployment of the chart provided by the user + UserChartLocation string `json:"userChartLocation,omitempty"` + + // Chart values.yaml file location for the deployment of the chart provided by the user + UserChartAlternateValues string `json:"userChartAlternateValues,omitempty"` + + // Chart supplemental information related to the group (service) + UserChartGroup string `json:"userChartGroup,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/scenario.go b/go-packages/meep-ctrl-engine-client/scenario.go new file mode 100644 index 0000000000000000000000000000000000000000..a36ed7489b088d883576dc7a65c6984c21dbad95 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/scenario.go @@ -0,0 +1,21 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Scenario object +type Scenario struct { + + // Unique scenario name + Name string `json:"name,omitempty"` + + Config *ScenarioConfig `json:"config,omitempty"` + + Deployment *Deployment `json:"deployment,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/scenario_config.go b/go-packages/meep-ctrl-engine-client/scenario_config.go new file mode 100644 index 0000000000000000000000000000000000000000..b1d682947c6f63fa3ee0471cb2c1bf914c85c670 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/scenario_config.go @@ -0,0 +1,20 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Scenario configuration +type ScenarioConfig struct { + + // Visualization configuration + Visualization string `json:"visualization,omitempty"` + + // Other scenario configuration + Other string `json:"other,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/scenario_configuration_api.go b/go-packages/meep-ctrl-engine-client/scenario_configuration_api.go new file mode 100644 index 0000000000000000000000000000000000000000..6f87f693b5b5a824db90ef8e2616c3ad2665e7c6 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/scenario_configuration_api.go @@ -0,0 +1,388 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type ScenarioConfigurationApiService service + +/* ScenarioConfigurationApiService Add new scenario to MEEP store + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param name Scenario name +@param scenario Scenario to add to MEEP store +@return */ +func (a *ScenarioConfigurationApiService) CreateScenario(ctx context.Context, name string, scenario Scenario) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &scenario + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* ScenarioConfigurationApiService Delete scenario from MEEP store + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param name Scenario name +@return */ +func (a *ScenarioConfigurationApiService) DeleteScenario(ctx context.Context, name string) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Delete") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* ScenarioConfigurationApiService Delete all scenarios in MEEP store + + * @param ctx context.Context for authentication, logging, tracing, etc. + @return */ +func (a *ScenarioConfigurationApiService) DeleteScenarioList(ctx context.Context) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Delete") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* ScenarioConfigurationApiService Retrieve scenario from MEEP store + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param name Scenario name +@return Scenario*/ +func (a *ScenarioConfigurationApiService) GetScenario(ctx context.Context, name string) (Scenario, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload Scenario + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* ScenarioConfigurationApiService Retrieve list of scenarios in MEEP store + + * @param ctx context.Context for authentication, logging, tracing, etc. + @return ScenarioList*/ +func (a *ScenarioConfigurationApiService) GetScenarioList(ctx context.Context) (ScenarioList, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload ScenarioList + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* ScenarioConfigurationApiService Update scenario in MEEP store + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param name Scenario name +@param scenario Scenario to add to MEEP store +@return */ +func (a *ScenarioConfigurationApiService) SetScenario(ctx context.Context, name string, scenario Scenario) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Put") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &scenario + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} diff --git a/go-packages/meep-ctrl-engine-client/scenario_execution_api.go b/go-packages/meep-ctrl-engine-client/scenario_execution_api.go new file mode 100644 index 0000000000000000000000000000000000000000..ca749bf3bf96f255e4867898c3c08d95f8d792f1 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/scenario_execution_api.go @@ -0,0 +1,402 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type ScenarioExecutionApiService service + +/* ScenarioExecutionApiService Activate (deploy) scenario + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param name Scenario name +@return */ +func (a *ScenarioExecutionApiService) ActivateScenario(ctx context.Context, name string) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/active/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* ScenarioExecutionApiService Retrieve list of active external client service mappings + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param optional (nil or map[string]interface{}) with one or more of: + @param "client" (string) Unique client identifier + @param "service" (string) Exposed service name +@return []ClientServiceMap*/ +func (a *ScenarioExecutionApiService) GetActiveClientServiceMaps(ctx context.Context, localVarOptionals map[string]interface{}) ([]ClientServiceMap, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload []ClientServiceMap + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/active/serviceMaps" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if err := typeCheckParameter(localVarOptionals["client"], "string", "client"); err != nil { + return successPayload, nil, err + } + if err := typeCheckParameter(localVarOptionals["service"], "string", "service"); err != nil { + return successPayload, nil, err + } + + if localVarTempParam, localVarOk := localVarOptionals["client"].(string); localVarOk { + localVarQueryParams.Add("client", parameterToString(localVarTempParam, "")) + } + if localVarTempParam, localVarOk := localVarOptionals["service"].(string); localVarOk { + localVarQueryParams.Add("service", parameterToString(localVarTempParam, "")) + } + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* ScenarioExecutionApiService Retrieve active (deployed) scenario + + * @param ctx context.Context for authentication, logging, tracing, etc. + @return Scenario*/ +func (a *ScenarioExecutionApiService) GetActiveScenario(ctx context.Context) (Scenario, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload Scenario + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/active" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* ScenarioExecutionApiService Retrieve list of supported event types for active (deployed) scenario + + * @param ctx context.Context for authentication, logging, tracing, etc. + @return EventList*/ +func (a *ScenarioExecutionApiService) GetEventList(ctx context.Context) (EventList, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload EventList + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/events" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* ScenarioExecutionApiService Send event to active (deployed) scenario + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param type_ Event type +@param event Event to send to active scenario +@return */ +func (a *ScenarioExecutionApiService) SendEvent(ctx context.Context, type_ string, event Event) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/events/{type}" + localVarPath = strings.Replace(localVarPath, "{"+"type"+"}", fmt.Sprintf("%v", type_), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &event + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* ScenarioExecutionApiService Terminate active (deployed) scenario + + * @param ctx context.Context for authentication, logging, tracing, etc. + @return */ +func (a *ScenarioExecutionApiService) TerminateScenario(ctx context.Context) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Delete") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/active" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} diff --git a/go-packages/meep-ctrl-engine-client/scenario_list.go b/go-packages/meep-ctrl-engine-client/scenario_list.go new file mode 100644 index 0000000000000000000000000000000000000000..a2824014f1c7b9997d37a920011e68cdd3be4eec --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/scenario_list.go @@ -0,0 +1,15 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Scenario list object +type ScenarioList struct { + Scenarios []Scenario `json:"scenarios,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/service_config.go b/go-packages/meep-ctrl-engine-client/service_config.go new file mode 100644 index 0000000000000000000000000000000000000000..1668e949e9ff8da6f50a6b343537cba024a20916 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/service_config.go @@ -0,0 +1,22 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Service object +type ServiceConfig struct { + + // Unique service name + Name string `json:"name,omitempty"` + + // Multi-Edge service name, if any + MeSvcName string `json:"meSvcName,omitempty"` + + Ports []ServicePort `json:"ports,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/service_map.go b/go-packages/meep-ctrl-engine-client/service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..c72f8fda736e2689c10775a737f3bf5412c44ff1 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/service_map.go @@ -0,0 +1,29 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Mapping of exposed ports to internal or external services +type ServiceMap struct { + + // Service name + Name string `json:"name,omitempty"` + + // Service IP address for external service only (egress)
  • N/A for internal services + Ip string `json:"ip,omitempty"` + + // Service port number + Port int32 `json:"port,omitempty"` + + // Port used to expose internal service only (ingress)
  • Must be unique port in range (30000 - 32767)
  • N/A for external services + ExternalPort int32 `json:"externalPort,omitempty"` + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/service_port.go b/go-packages/meep-ctrl-engine-client/service_port.go new file mode 100644 index 0000000000000000000000000000000000000000..0f45cdeee931a1452eda02be7259f06a62d2b431 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/service_port.go @@ -0,0 +1,23 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Service port object +type ServicePort struct { + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` + + // Port number that the service is listening on + Port int32 `json:"port,omitempty"` + + // External port number on which to expose the application (30000 - 32767)
  • Only one application allowed per external port
  • Scenario builder must configure to prevent conflicts + ExternalPort int32 `json:"externalPort,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-client/settings.go b/go-packages/meep-ctrl-engine-client/settings.go new file mode 100644 index 0000000000000000000000000000000000000000..9e7ddee0d1e02ab0d0e99ec8c581d3498ed3a1d3 --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/settings.go @@ -0,0 +1,14 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// MEEP settings +type Settings struct { +} diff --git a/go-packages/meep-ctrl-engine-client/zone.go b/go-packages/meep-ctrl-engine-client/zone.go new file mode 100644 index 0000000000000000000000000000000000000000..690c5b8f0b6925ccceaf14841415b36bc5fd4a9d --- /dev/null +++ b/go-packages/meep-ctrl-engine-client/zone.go @@ -0,0 +1,61 @@ +/* + * MEEP Controller REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Logical zone (MEC network) object +type Zone struct { + + // Unique zone ID + Id string `json:"id,omitempty"` + + // Zone name + Name string `json:"name,omitempty"` + + // Zone type + Type_ string `json:"type,omitempty"` + + // Latency in ms between fog nodes (or PoAs) within zone + InterFogLatency int32 `json:"interFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) within zone + InterFogLatencyVariation int32 `json:"interFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) within the zone + InterFogThroughput int32 `json:"interFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone + InterFogPacketLoss float64 `json:"interFogPacketLoss,omitempty"` + + // Latency in ms between edge nodes within zone + InterEdgeLatency int32 `json:"interEdgeLatency,omitempty"` + + // Latency variation in ms between edge nodes within zone + InterEdgeLatencyVariation int32 `json:"interEdgeLatencyVariation,omitempty"` + + // The limit of the traffic supported between edge nodes within the zone + InterEdgeThroughput int32 `json:"interEdgeThroughput,omitempty"` + + // Packet lost (in terms of percentage) between edge nodes within the zone + InterEdgePacketLoss float64 `json:"interEdgePacketLoss,omitempty"` + + // Latency in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatency int32 `json:"edgeFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatencyVariation int32 `json:"edgeFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogThroughput int32 `json:"edgeFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogPacketLoss float64 `json:"edgeFogPacketLoss,omitempty"` + + NetworkLocations []NetworkLocation `json:"networkLocations,omitempty"` +} diff --git a/bin/meep-ctrl-engine/static/api/meep-model.yaml b/go-packages/meep-ctrl-engine-model/api/swagger.yaml similarity index 99% rename from bin/meep-ctrl-engine/static/api/meep-model.yaml rename to go-packages/meep-ctrl-engine-model/api/swagger.yaml index 26420d5a617517070c86d8ceb98836bb376c8f7b..059811545e6156e128df761519d4c492cc697082 100644 --- a/bin/meep-ctrl-engine/static/api/meep-model.yaml +++ b/go-packages/meep-ctrl-engine-model/api/swagger.yaml @@ -1,8 +1,11 @@ swagger: '2.0' info: - description: MEEP Controller REST API + description: > + Copyright (c) 2019 InterDigital Communications, Inc. + All rights reserved. + The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. version: 1.0.0 - title: MEEP Controller REST API + title: MEEP Model definitions: ClientServiceMap: type: object diff --git a/go-packages/meep-ctrl-engine-model/client_service_map.go b/go-packages/meep-ctrl-engine-model/client_service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..0898c3268cd32355b4ed655eb9083093f3561b63 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/client_service_map.go @@ -0,0 +1,19 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Client-specific list of mappings of exposed port to internal service +type ClientServiceMap struct { + + // Unique external client identifier + Client string `json:"client,omitempty"` + + ServiceMap []ServiceMap `json:"serviceMap,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/deployment.go b/go-packages/meep-ctrl-engine-model/deployment.go new file mode 100644 index 0000000000000000000000000000000000000000..7f2363344fd22d8f6cdedc12c22066e7a848fe4d --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/deployment.go @@ -0,0 +1,28 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Network deployment object +type Deployment struct { + + // Latency in ms between domains + InterDomainLatency int32 `json:"interDomainLatency,omitempty"` + + // Latency variation in ms between domains + InterDomainLatencyVariation int32 `json:"interDomainLatencyVariation,omitempty"` + + // The limit of the traffic supported between domains + InterDomainThroughput int32 `json:"interDomainThroughput,omitempty"` + + // Packet lost (in terms of percentage) between domains + InterDomainPacketLoss float64 `json:"interDomainPacketLoss,omitempty"` + + Domains []Domain `json:"domains,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/docs/ClientServiceMap.md b/go-packages/meep-ctrl-engine-model/docs/ClientServiceMap.md new file mode 100644 index 0000000000000000000000000000000000000000..ab6a26d413c1c00848da0769a35a87d2bc087aa9 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/ClientServiceMap.md @@ -0,0 +1,11 @@ +# ClientServiceMap + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Client** | **string** | Unique external client identifier | [optional] [default to null] +**ServiceMap** | [**[]ServiceMap**](ServiceMap.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/Deployment.md b/go-packages/meep-ctrl-engine-model/docs/Deployment.md new file mode 100644 index 0000000000000000000000000000000000000000..1ffa15070c5d5e35534890dfa800c321d3eb03f3 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/Deployment.md @@ -0,0 +1,14 @@ +# Deployment + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**InterDomainLatency** | **int32** | Latency in ms between domains | [optional] [default to null] +**InterDomainLatencyVariation** | **int32** | Latency variation in ms between domains | [optional] [default to null] +**InterDomainThroughput** | **int32** | The limit of the traffic supported between domains | [optional] [default to null] +**InterDomainPacketLoss** | **float64** | Packet lost (in terms of percentage) between domains | [optional] [default to null] +**Domains** | [**[]Domain**](Domain.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/Domain.md b/go-packages/meep-ctrl-engine-model/docs/Domain.md new file mode 100644 index 0000000000000000000000000000000000000000..6bdf9f243b0fccc61dfc94a2f9ae92469f809cd9 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/Domain.md @@ -0,0 +1,17 @@ +# Domain + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique domain ID | [optional] [default to null] +**Name** | **string** | Domain name | [optional] [default to null] +**Type_** | **string** | Domain type | [optional] [default to null] +**InterZoneLatency** | **int32** | Latency in ms between zones within domain | [optional] [default to null] +**InterZoneLatencyVariation** | **int32** | Latency variation in ms between zones within domain | [optional] [default to null] +**InterZoneThroughput** | **int32** | The limit of the traffic supported between zones within the domain | [optional] [default to null] +**InterZonePacketLoss** | **float64** | Packet lost (in terms of percentage) between zones within the domain | [optional] [default to null] +**Zones** | [**[]Zone**](Zone.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/Event.md b/go-packages/meep-ctrl-engine-model/docs/Event.md new file mode 100644 index 0000000000000000000000000000000000000000..33fd474fc8489ffa73eab78be973afea3b3006d9 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/Event.md @@ -0,0 +1,15 @@ +# Event + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Event name | [optional] [default to null] +**Type_** | **string** | Event type | [optional] [default to null] +**EventNetworkCharacteristicsUpdate** | [***EventNetworkCharacteristicsUpdate**](EventNetworkCharacteristicsUpdate.md) | | [optional] [default to null] +**EventUeMobility** | [***EventUeMobility**](EventUeMobility.md) | | [optional] [default to null] +**EventPoasInRange** | [***EventPoasInRange**](EventPoasInRange.md) | | [optional] [default to null] +**EventOther** | [***EventOther**](EventOther.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/EventList.md b/go-packages/meep-ctrl-engine-model/docs/EventList.md new file mode 100644 index 0000000000000000000000000000000000000000..0b0211421b1382f2b11f24b950a81b76904f831f --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/EventList.md @@ -0,0 +1,10 @@ +# EventList + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Events** | [**[]Event**](Event.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/EventNetworkCharacteristicsUpdate.md b/go-packages/meep-ctrl-engine-model/docs/EventNetworkCharacteristicsUpdate.md new file mode 100644 index 0000000000000000000000000000000000000000..29f2be3e32f90351a4462e5851e8f2bec5d08aaf --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/EventNetworkCharacteristicsUpdate.md @@ -0,0 +1,15 @@ +# EventNetworkCharacteristicsUpdate + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ElementName** | **string** | Name of the network element to be updated | [optional] [default to null] +**ElementType** | **string** | Type of the network element to be updated | [optional] [default to null] +**Latency** | **int32** | Latency in ms | [optional] [default to null] +**LatencyVariation** | **int32** | Latency variation in ms | [optional] [default to null] +**Throughput** | **int32** | Throughput limit | [optional] [default to null] +**PacketLoss** | **float64** | Packet loss percentage | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/EventOther.md b/go-packages/meep-ctrl-engine-model/docs/EventOther.md new file mode 100644 index 0000000000000000000000000000000000000000..df06c50f6a72108d8cb82cc5f12d78c91565e0ef --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/EventOther.md @@ -0,0 +1,10 @@ +# EventOther + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Event** | **string** | Other event string | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/EventPoasInRange.md b/go-packages/meep-ctrl-engine-model/docs/EventPoasInRange.md new file mode 100644 index 0000000000000000000000000000000000000000..640a0aec15b81fc6595e5a6cac9f9d3107dc55ee --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/EventPoasInRange.md @@ -0,0 +1,11 @@ +# EventPoasInRange + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Ue** | **string** | UE identifier | [optional] [default to null] +**PoasInRange** | **[]string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/EventUeMobility.md b/go-packages/meep-ctrl-engine-model/docs/EventUeMobility.md new file mode 100644 index 0000000000000000000000000000000000000000..0df09a5791ffc3a7a4829682d84be165e2774f67 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/EventUeMobility.md @@ -0,0 +1,11 @@ +# EventUeMobility + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Ue** | **string** | UE identifier | [optional] [default to null] +**Dest** | **string** | Destination identifier | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/ExternalConfig.md b/go-packages/meep-ctrl-engine-model/docs/ExternalConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..7a25f4aad9e315036f94794ed3e7f49c14cf451d --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/ExternalConfig.md @@ -0,0 +1,11 @@ +# ExternalConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**IngressServiceMap** | [**[]ServiceMap**](ServiceMap.md) | | [optional] [default to null] +**EgressServiceMap** | [**[]ServiceMap**](ServiceMap.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/NetworkLocation.md b/go-packages/meep-ctrl-engine-model/docs/NetworkLocation.md new file mode 100644 index 0000000000000000000000000000000000000000..6599c7cd83dc42930bae089da6fb918013addf0d --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/NetworkLocation.md @@ -0,0 +1,17 @@ +# NetworkLocation + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique network location ID | [optional] [default to null] +**Name** | **string** | Network location name | [optional] [default to null] +**Type_** | **string** | Network location type | [optional] [default to null] +**TerminalLinkLatency** | **int32** | Latency in ms for all terminal links within network location | [optional] [default to null] +**TerminalLinkLatencyVariation** | **int32** | Latency variation in ms for all terminal links within network location | [optional] [default to null] +**TerminalLinkThroughput** | **int32** | The limit of the traffic supported for all terminal links within the network location | [optional] [default to null] +**TerminalLinkPacketLoss** | **float64** | Packet lost (in terms of percentage) for all terminal links within the network location | [optional] [default to null] +**PhysicalLocations** | [**[]PhysicalLocation**](PhysicalLocation.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/PhysicalLocation.md b/go-packages/meep-ctrl-engine-model/docs/PhysicalLocation.md new file mode 100644 index 0000000000000000000000000000000000000000..321343c2471f6bcb457e5deeb43b895526febfb6 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/PhysicalLocation.md @@ -0,0 +1,15 @@ +# PhysicalLocation + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique physical location ID | [optional] [default to null] +**Name** | **string** | Physical location name | [optional] [default to null] +**Type_** | **string** | Physical location type | [optional] [default to null] +**IsExternal** | **bool** | true: Physical location is external to MEEP false: Physical location is internal to MEEP | [optional] [default to null] +**NetworkLocationsInRange** | **[]string** | | [optional] [default to null] +**Processes** | [**[]Process**](Process.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/PodStatus.md b/go-packages/meep-ctrl-engine-model/docs/PodStatus.md new file mode 100644 index 0000000000000000000000000000000000000000..a23be3ed2cf7929fa24d25aa52531d66d17a6a46 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/PodStatus.md @@ -0,0 +1,26 @@ +# PodStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Pod name | [optional] [default to null] +**Namespace** | **string** | Pod namespace | [optional] [default to null] +**MeepApp** | **string** | Pod process name | [optional] [default to null] +**MeepOrigin** | **string** | Pod origin(core, scenario) | [optional] [default to null] +**MeepScenario** | **string** | Pod scenario name | [optional] [default to null] +**Phase** | **string** | Pod phase | [optional] [default to null] +**PodInitialized** | **string** | Pod initialized (true/false) | [optional] [default to null] +**PodReady** | **string** | Pod ready (true/false) | [optional] [default to null] +**PodScheduled** | **string** | Pod scheduled (true/false) | [optional] [default to null] +**PodUnschedulable** | **string** | Pod unschedulable (true/false) | [optional] [default to null] +**PodConditionError** | **string** | Pod error message | [optional] [default to null] +**ContainerStatusesMsg** | **string** | Failed container error message | [optional] [default to null] +**NbOkContainers** | **string** | Number of containers that are up | [optional] [default to null] +**NbTotalContainers** | **string** | Number of total containers in the pod | [optional] [default to null] +**NbPodRestart** | **string** | Number of container failures leading to pod restarts | [optional] [default to null] +**LogicalState** | **string** | State that is mapping the kubernetes api state | [optional] [default to null] +**StartTime** | **string** | Pod creation time | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/PodsStatus.md b/go-packages/meep-ctrl-engine-model/docs/PodsStatus.md new file mode 100644 index 0000000000000000000000000000000000000000..148d06e683d0a51f84ae61485d60d1347c6456f5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/PodsStatus.md @@ -0,0 +1,10 @@ +# PodsStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**PodStatus** | [**[]PodStatus**](PodStatus.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/Process.md b/go-packages/meep-ctrl-engine-model/docs/Process.md new file mode 100644 index 0000000000000000000000000000000000000000..1e32ea0e21a98b9be00a73c0ec6e4d279f0b92e4 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/Process.md @@ -0,0 +1,23 @@ +# Process + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique process ID | [optional] [default to null] +**Name** | **string** | Process name | [optional] [default to null] +**Type_** | **string** | Process type | [optional] [default to null] +**IsExternal** | **bool** | true: process is external to MEEP false: process is internal to MEEP | [optional] [default to null] +**Image** | **string** | Docker image to deploy inside MEEP | [optional] [default to null] +**Environment** | **string** | Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" | [optional] [default to null] +**CommandArguments** | **string** | Arguments to command executable | [optional] [default to null] +**CommandExe** | **string** | Executable to invoke at container start up | [optional] [default to null] +**ServiceConfig** | [***ServiceConfig**](ServiceConfig.md) | | [optional] [default to null] +**ExternalConfig** | [***ExternalConfig**](ExternalConfig.md) | | [optional] [default to null] +**Status** | **string** | Process status | [optional] [default to null] +**UserChartLocation** | **string** | Chart location for the deployment of the chart provided by the user | [optional] [default to null] +**UserChartAlternateValues** | **string** | Chart values.yaml file location for the deployment of the chart provided by the user | [optional] [default to null] +**UserChartGroup** | **string** | Chart supplemental information related to the group (service) | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/Release.md b/go-packages/meep-ctrl-engine-model/docs/Release.md new file mode 100644 index 0000000000000000000000000000000000000000..946d7eca0eee2aaef30a4c0f38f9b69c467fb21e --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/Release.md @@ -0,0 +1,11 @@ +# Release + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Release name | [optional] [default to null] +**State** | **string** | Current release state | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/Scenario.md b/go-packages/meep-ctrl-engine-model/docs/Scenario.md new file mode 100644 index 0000000000000000000000000000000000000000..eb4a453d0fe6ebaddef6f3dfe96279ff643bc8ce --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/Scenario.md @@ -0,0 +1,12 @@ +# Scenario + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Unique scenario name | [optional] [default to null] +**Config** | [***ScenarioConfig**](ScenarioConfig.md) | | [optional] [default to null] +**Deployment** | [***Deployment**](Deployment.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/ScenarioConfig.md b/go-packages/meep-ctrl-engine-model/docs/ScenarioConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..0f6e1dbeee6174a63026df8c4ffb2e036a371029 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/ScenarioConfig.md @@ -0,0 +1,11 @@ +# ScenarioConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Visualization** | **string** | Visualization configuration | [optional] [default to null] +**Other** | **string** | Other scenario configuration | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/ScenarioList.md b/go-packages/meep-ctrl-engine-model/docs/ScenarioList.md new file mode 100644 index 0000000000000000000000000000000000000000..99bf8929d621ec6bd487bf3ee7e3f00a92f17425 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/ScenarioList.md @@ -0,0 +1,10 @@ +# ScenarioList + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Scenarios** | [**[]Scenario**](Scenario.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/ServiceConfig.md b/go-packages/meep-ctrl-engine-model/docs/ServiceConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..6db2202b3aa2fd40150333ca1be13f854a10f7c5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/ServiceConfig.md @@ -0,0 +1,12 @@ +# ServiceConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Unique service name | [optional] [default to null] +**MeSvcName** | **string** | Multi-Edge service name, if any | [optional] [default to null] +**Ports** | [**[]ServicePort**](ServicePort.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/ServiceMap.md b/go-packages/meep-ctrl-engine-model/docs/ServiceMap.md new file mode 100644 index 0000000000000000000000000000000000000000..c8ac3a0a957d39752d1af1a792e188d307b9a5d5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/ServiceMap.md @@ -0,0 +1,14 @@ +# ServiceMap + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Service name | [optional] [default to null] +**Ip** | **string** | Service IP address for external service only (egress) <li>N/A for internal services | [optional] [default to null] +**Port** | **int32** | Service port number | [optional] [default to null] +**ExternalPort** | **int32** | Port used to expose internal service only (ingress) <li>Must be unique port in range (30000 - 32767) <li>N/A for external services | [optional] [default to null] +**Protocol** | **string** | Protocol that the application is using (TCP or UDP) | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/ServicePort.md b/go-packages/meep-ctrl-engine-model/docs/ServicePort.md new file mode 100644 index 0000000000000000000000000000000000000000..6b6c33d586b9c04db79900945f2904fc4eaba286 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/ServicePort.md @@ -0,0 +1,12 @@ +# ServicePort + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Protocol** | **string** | Protocol that the application is using (TCP or UDP) | [optional] [default to null] +**Port** | **int32** | Port number that the service is listening on | [optional] [default to null] +**ExternalPort** | **int32** | External port number on which to expose the application (30000 - 32767) <li>Only one application allowed per external port <li>Scenario builder must configure to prevent conflicts | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/Settings.md b/go-packages/meep-ctrl-engine-model/docs/Settings.md new file mode 100644 index 0000000000000000000000000000000000000000..0bd3d571efdb26096a75efe9972a55674e449853 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/Settings.md @@ -0,0 +1,9 @@ +# Settings + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/docs/Zone.md b/go-packages/meep-ctrl-engine-model/docs/Zone.md new file mode 100644 index 0000000000000000000000000000000000000000..5e24dc058eca726e53670004beb9f67eb9588724 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/docs/Zone.md @@ -0,0 +1,25 @@ +# Zone + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique zone ID | [optional] [default to null] +**Name** | **string** | Zone name | [optional] [default to null] +**Type_** | **string** | Zone type | [optional] [default to null] +**InterFogLatency** | **int32** | Latency in ms between fog nodes (or PoAs) within zone | [optional] [default to null] +**InterFogLatencyVariation** | **int32** | Latency variation in ms between fog nodes (or PoAs) within zone | [optional] [default to null] +**InterFogThroughput** | **int32** | The limit of the traffic supported between fog nodes (or PoAs) within the zone | [optional] [default to null] +**InterFogPacketLoss** | **float64** | Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone | [optional] [default to null] +**InterEdgeLatency** | **int32** | Latency in ms between edge nodes within zone | [optional] [default to null] +**InterEdgeLatencyVariation** | **int32** | Latency variation in ms between edge nodes within zone | [optional] [default to null] +**InterEdgeThroughput** | **int32** | The limit of the traffic supported between edge nodes within the zone | [optional] [default to null] +**InterEdgePacketLoss** | **float64** | Packet lost (in terms of percentage) between edge nodes within the zone | [optional] [default to null] +**EdgeFogLatency** | **int32** | Latency in ms between fog nodes (or PoAs) and edge nodes within zone | [optional] [default to null] +**EdgeFogLatencyVariation** | **int32** | Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone | [optional] [default to null] +**EdgeFogThroughput** | **int32** | The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone | [optional] [default to null] +**EdgeFogPacketLoss** | **float64** | Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone | [optional] [default to null] +**NetworkLocations** | [**[]NetworkLocation**](NetworkLocation.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-ctrl-engine-model/domain.go b/go-packages/meep-ctrl-engine-model/domain.go new file mode 100644 index 0000000000000000000000000000000000000000..adb88319765e8d72168255ff38c300e118a388fe --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/domain.go @@ -0,0 +1,37 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Operator domain object +type Domain struct { + + // Unique domain ID + Id string `json:"id,omitempty"` + + // Domain name + Name string `json:"name,omitempty"` + + // Domain type + Type_ string `json:"type,omitempty"` + + // Latency in ms between zones within domain + InterZoneLatency int32 `json:"interZoneLatency,omitempty"` + + // Latency variation in ms between zones within domain + InterZoneLatencyVariation int32 `json:"interZoneLatencyVariation,omitempty"` + + // The limit of the traffic supported between zones within the domain + InterZoneThroughput int32 `json:"interZoneThroughput,omitempty"` + + // Packet lost (in terms of percentage) between zones within the domain + InterZonePacketLoss float64 `json:"interZonePacketLoss,omitempty"` + + Zones []Zone `json:"zones,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/event.go b/go-packages/meep-ctrl-engine-model/event.go new file mode 100644 index 0000000000000000000000000000000000000000..82a2bcf801bff9959e9c8833dedcceafa15f301d --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/event.go @@ -0,0 +1,28 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Event object +type Event struct { + + // Event name + Name string `json:"name,omitempty"` + + // Event type + Type_ string `json:"type,omitempty"` + + EventNetworkCharacteristicsUpdate *EventNetworkCharacteristicsUpdate `json:"eventNetworkCharacteristicsUpdate,omitempty"` + + EventUeMobility *EventUeMobility `json:"eventUeMobility,omitempty"` + + EventPoasInRange *EventPoasInRange `json:"eventPoasInRange,omitempty"` + + EventOther *EventOther `json:"eventOther,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/event_list.go b/go-packages/meep-ctrl-engine-model/event_list.go new file mode 100644 index 0000000000000000000000000000000000000000..c752e7bd73df15d9006b786568cda41a42092d61 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/event_list.go @@ -0,0 +1,15 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Event list object +type EventList struct { + Events []Event `json:"events,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/event_network_characteristics_update.go b/go-packages/meep-ctrl-engine-model/event_network_characteristics_update.go new file mode 100644 index 0000000000000000000000000000000000000000..854133a59c4cd1a920ef7d6b347fd80171948cc2 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/event_network_characteristics_update.go @@ -0,0 +1,32 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Network Characteristics update Event object +type EventNetworkCharacteristicsUpdate struct { + + // Name of the network element to be updated + ElementName string `json:"elementName,omitempty"` + + // Type of the network element to be updated + ElementType string `json:"elementType,omitempty"` + + // Latency in ms + Latency int32 `json:"latency,omitempty"` + + // Latency variation in ms + LatencyVariation int32 `json:"latencyVariation,omitempty"` + + // Throughput limit + Throughput int32 `json:"throughput,omitempty"` + + // Packet loss percentage + PacketLoss float64 `json:"packetLoss,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/event_other.go b/go-packages/meep-ctrl-engine-model/event_other.go new file mode 100644 index 0000000000000000000000000000000000000000..58fbc06eb99f1c2e4f44ec220adc3cf9aa766f44 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/event_other.go @@ -0,0 +1,17 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Other Event object +type EventOther struct { + + // Other event string + Event string `json:"event,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/event_poas_in_range.go b/go-packages/meep-ctrl-engine-model/event_poas_in_range.go new file mode 100644 index 0000000000000000000000000000000000000000..1c0f361b1e3a55c83840cae5a385c18b34d671ab --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/event_poas_in_range.go @@ -0,0 +1,19 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// POAs In Range Event object +type EventPoasInRange struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + PoasInRange []string `json:"poasInRange,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/event_ue_mobility.go b/go-packages/meep-ctrl-engine-model/event_ue_mobility.go new file mode 100644 index 0000000000000000000000000000000000000000..451e31989008002212938e5a0976adb680c8b188 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/event_ue_mobility.go @@ -0,0 +1,20 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// UE Mobility Event object +type EventUeMobility struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + // Destination identifier + Dest string `json:"dest,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/external_config.go b/go-packages/meep-ctrl-engine-model/external_config.go new file mode 100644 index 0000000000000000000000000000000000000000..6e7e0005b54239e61428a6a915a19eca760d46bb --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/external_config.go @@ -0,0 +1,17 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// External Process configuration. NOTE: Only valid if 'isExternal' is set. +type ExternalConfig struct { + IngressServiceMap []ServiceMap `json:"ingressServiceMap,omitempty"` + + EgressServiceMap []ServiceMap `json:"egressServiceMap,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/go.mod b/go-packages/meep-ctrl-engine-model/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..a122ea7bd1f600e79d24860047154a7a37cd2e5b --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/go.mod @@ -0,0 +1,3 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-ctrl-engine-model + +go 1.12 diff --git a/go-packages/meep-ctrl-engine-model/network_location.go b/go-packages/meep-ctrl-engine-model/network_location.go new file mode 100644 index 0000000000000000000000000000000000000000..a714b850feeebfeccc608f7909aab4063bba0775 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/network_location.go @@ -0,0 +1,37 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Logical network location object +type NetworkLocation struct { + + // Unique network location ID + Id string `json:"id,omitempty"` + + // Network location name + Name string `json:"name,omitempty"` + + // Network location type + Type_ string `json:"type,omitempty"` + + // Latency in ms for all terminal links within network location + TerminalLinkLatency int32 `json:"terminalLinkLatency,omitempty"` + + // Latency variation in ms for all terminal links within network location + TerminalLinkLatencyVariation int32 `json:"terminalLinkLatencyVariation,omitempty"` + + // The limit of the traffic supported for all terminal links within the network location + TerminalLinkThroughput int32 `json:"terminalLinkThroughput,omitempty"` + + // Packet lost (in terms of percentage) for all terminal links within the network location + TerminalLinkPacketLoss float64 `json:"terminalLinkPacketLoss,omitempty"` + + PhysicalLocations []PhysicalLocation `json:"physicalLocations,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/physical_location.go b/go-packages/meep-ctrl-engine-model/physical_location.go new file mode 100644 index 0000000000000000000000000000000000000000..c0d50cbf0993319e9772b22341e595a86d36bec5 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/physical_location.go @@ -0,0 +1,30 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Physical location object +type PhysicalLocation struct { + + // Unique physical location ID + Id string `json:"id,omitempty"` + + // Physical location name + Name string `json:"name,omitempty"` + + // Physical location type + Type_ string `json:"type,omitempty"` + + // true: Physical location is external to MEEP false: Physical location is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + NetworkLocationsInRange []string `json:"networkLocationsInRange,omitempty"` + + Processes []Process `json:"processes,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/pod_status.go b/go-packages/meep-ctrl-engine-model/pod_status.go new file mode 100644 index 0000000000000000000000000000000000000000..8bbc6a1cab67edf63b77643f591cbed240b6ce90 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/pod_status.go @@ -0,0 +1,64 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +type PodStatus struct { + + // Pod name + Name string `json:"name,omitempty"` + + // Pod namespace + Namespace string `json:"namespace,omitempty"` + + // Pod process name + MeepApp string `json:"meepApp,omitempty"` + + // Pod origin(core, scenario) + MeepOrigin string `json:"meepOrigin,omitempty"` + + // Pod scenario name + MeepScenario string `json:"meepScenario,omitempty"` + + // Pod phase + Phase string `json:"phase,omitempty"` + + // Pod initialized (true/false) + PodInitialized string `json:"podInitialized,omitempty"` + + // Pod ready (true/false) + PodReady string `json:"podReady,omitempty"` + + // Pod scheduled (true/false) + PodScheduled string `json:"podScheduled,omitempty"` + + // Pod unschedulable (true/false) + PodUnschedulable string `json:"podUnschedulable,omitempty"` + + // Pod error message + PodConditionError string `json:"podConditionError,omitempty"` + + // Failed container error message + ContainerStatusesMsg string `json:"containerStatusesMsg,omitempty"` + + // Number of containers that are up + NbOkContainers string `json:"nbOkContainers,omitempty"` + + // Number of total containers in the pod + NbTotalContainers string `json:"nbTotalContainers,omitempty"` + + // Number of container failures leading to pod restarts + NbPodRestart string `json:"nbPodRestart,omitempty"` + + // State that is mapping the kubernetes api state + LogicalState string `json:"logicalState,omitempty"` + + // Pod creation time + StartTime string `json:"startTime,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/pods_status.go b/go-packages/meep-ctrl-engine-model/pods_status.go new file mode 100644 index 0000000000000000000000000000000000000000..fbd75a7d5b0f2a43bd554adfed25432a37200bfb --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/pods_status.go @@ -0,0 +1,15 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// List of all pods status +type PodsStatus struct { + PodStatus []PodStatus `json:"podStatus,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/process.go b/go-packages/meep-ctrl-engine-model/process.go new file mode 100644 index 0000000000000000000000000000000000000000..8997b5eaf097cb9783157cb08056d2685239c7d1 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/process.go @@ -0,0 +1,54 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Application or service object +type Process struct { + + // Unique process ID + Id string `json:"id,omitempty"` + + // Process name + Name string `json:"name,omitempty"` + + // Process type + Type_ string `json:"type,omitempty"` + + // true: process is external to MEEP false: process is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + // Docker image to deploy inside MEEP + Image string `json:"image,omitempty"` + + // Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" + Environment string `json:"environment,omitempty"` + + // Arguments to command executable + CommandArguments string `json:"commandArguments,omitempty"` + + // Executable to invoke at container start up + CommandExe string `json:"commandExe,omitempty"` + + ServiceConfig *ServiceConfig `json:"serviceConfig,omitempty"` + + ExternalConfig *ExternalConfig `json:"externalConfig,omitempty"` + + // Process status + Status string `json:"status,omitempty"` + + // Chart location for the deployment of the chart provided by the user + UserChartLocation string `json:"userChartLocation,omitempty"` + + // Chart values.yaml file location for the deployment of the chart provided by the user + UserChartAlternateValues string `json:"userChartAlternateValues,omitempty"` + + // Chart supplemental information related to the group (service) + UserChartGroup string `json:"userChartGroup,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/release.go b/go-packages/meep-ctrl-engine-model/release.go new file mode 100644 index 0000000000000000000000000000000000000000..5a3117389ee7e2bede3e4147561699ac9d3c8d8f --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/release.go @@ -0,0 +1,19 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +type Release struct { + + // Release name + Name string `json:"name,omitempty"` + + // Current release state + State string `json:"state,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/scenario.go b/go-packages/meep-ctrl-engine-model/scenario.go new file mode 100644 index 0000000000000000000000000000000000000000..bb3cc05b235c2eb2a4fb8c4fe080527dc845a38c --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/scenario.go @@ -0,0 +1,21 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Scenario object +type Scenario struct { + + // Unique scenario name + Name string `json:"name,omitempty"` + + Config *ScenarioConfig `json:"config,omitempty"` + + Deployment *Deployment `json:"deployment,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/scenario_config.go b/go-packages/meep-ctrl-engine-model/scenario_config.go new file mode 100644 index 0000000000000000000000000000000000000000..e84814a3bc6cd5a9adcf094f3b4602b4bc8e7161 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/scenario_config.go @@ -0,0 +1,20 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Scenario configuration +type ScenarioConfig struct { + + // Visualization configuration + Visualization string `json:"visualization,omitempty"` + + // Other scenario configuration + Other string `json:"other,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/scenario_list.go b/go-packages/meep-ctrl-engine-model/scenario_list.go new file mode 100644 index 0000000000000000000000000000000000000000..5f8168790a516fd416b732cbd4e1aea0fcb965fb --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/scenario_list.go @@ -0,0 +1,15 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Scenario list object +type ScenarioList struct { + Scenarios []Scenario `json:"scenarios,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/service_config.go b/go-packages/meep-ctrl-engine-model/service_config.go new file mode 100644 index 0000000000000000000000000000000000000000..e06481f351611b409224d45ff13ea3c392f9d6c9 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/service_config.go @@ -0,0 +1,22 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Service object +type ServiceConfig struct { + + // Unique service name + Name string `json:"name,omitempty"` + + // Multi-Edge service name, if any + MeSvcName string `json:"meSvcName,omitempty"` + + Ports []ServicePort `json:"ports,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/service_map.go b/go-packages/meep-ctrl-engine-model/service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..9ee333f3bcf2fe629e4a12dfe9efea8c389ea1ff --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/service_map.go @@ -0,0 +1,29 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Mapping of exposed ports to internal or external services +type ServiceMap struct { + + // Service name + Name string `json:"name,omitempty"` + + // Service IP address for external service only (egress)
  • N/A for internal services + Ip string `json:"ip,omitempty"` + + // Service port number + Port int32 `json:"port,omitempty"` + + // Port used to expose internal service only (ingress)
  • Must be unique port in range (30000 - 32767)
  • N/A for external services + ExternalPort int32 `json:"externalPort,omitempty"` + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/service_port.go b/go-packages/meep-ctrl-engine-model/service_port.go new file mode 100644 index 0000000000000000000000000000000000000000..e56b4c653db9ee0f32414cce387ff6f29395375d --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/service_port.go @@ -0,0 +1,23 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Service port object +type ServicePort struct { + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` + + // Port number that the service is listening on + Port int32 `json:"port,omitempty"` + + // External port number on which to expose the application (30000 - 32767)
  • Only one application allowed per external port
  • Scenario builder must configure to prevent conflicts + ExternalPort int32 `json:"externalPort,omitempty"` +} diff --git a/go-packages/meep-ctrl-engine-model/settings.go b/go-packages/meep-ctrl-engine-model/settings.go new file mode 100644 index 0000000000000000000000000000000000000000..fd87f8860106e461974c7135e46a92b7f8ea9b79 --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/settings.go @@ -0,0 +1,14 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// MEEP settings +type Settings struct { +} diff --git a/go-packages/meep-ctrl-engine-model/zone.go b/go-packages/meep-ctrl-engine-model/zone.go new file mode 100644 index 0000000000000000000000000000000000000000..e496585c477d30140f940c93b72ad63c2b0f59ad --- /dev/null +++ b/go-packages/meep-ctrl-engine-model/zone.go @@ -0,0 +1,61 @@ +/* + * MEEP Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Logical zone (MEC network) object +type Zone struct { + + // Unique zone ID + Id string `json:"id,omitempty"` + + // Zone name + Name string `json:"name,omitempty"` + + // Zone type + Type_ string `json:"type,omitempty"` + + // Latency in ms between fog nodes (or PoAs) within zone + InterFogLatency int32 `json:"interFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) within zone + InterFogLatencyVariation int32 `json:"interFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) within the zone + InterFogThroughput int32 `json:"interFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone + InterFogPacketLoss float64 `json:"interFogPacketLoss,omitempty"` + + // Latency in ms between edge nodes within zone + InterEdgeLatency int32 `json:"interEdgeLatency,omitempty"` + + // Latency variation in ms between edge nodes within zone + InterEdgeLatencyVariation int32 `json:"interEdgeLatencyVariation,omitempty"` + + // The limit of the traffic supported between edge nodes within the zone + InterEdgeThroughput int32 `json:"interEdgeThroughput,omitempty"` + + // Packet lost (in terms of percentage) between edge nodes within the zone + InterEdgePacketLoss float64 `json:"interEdgePacketLoss,omitempty"` + + // Latency in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatency int32 `json:"edgeFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatencyVariation int32 `json:"edgeFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogThroughput int32 `json:"edgeFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogPacketLoss float64 `json:"edgeFogPacketLoss,omitempty"` + + NetworkLocations []NetworkLocation `json:"networkLocations,omitempty"` +} diff --git a/go-packages/meep-logger/go.mod b/go-packages/meep-logger/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..9aa0fdae566963e8c3702e3d47ca8ca4bc4686f4 --- /dev/null +++ b/go-packages/meep-logger/go.mod @@ -0,0 +1,5 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-logger + +go 1.12 + +require github.com/sirupsen/logrus v1.4.1 diff --git a/go-packages/meep-logger/go.sum b/go-packages/meep-logger/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..39b40444d723e97818c7db1eec29be18d95bbe49 --- /dev/null +++ b/go-packages/meep-logger/go.sum @@ -0,0 +1,9 @@ +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/go-packages/meep-logger/logger.go b/go-packages/meep-logger/logger.go new file mode 100644 index 0000000000000000000000000000000000000000..414fd4332913b20f1f7f3b2feabad4ba91ec63a1 --- /dev/null +++ b/go-packages/meep-logger/logger.go @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ + +package logger + +import ( + log "github.com/sirupsen/logrus" +) + +var componentName string + +func MeepJSONLogInit(name string) { + log.SetFormatter(&log.JSONFormatter{}) + log.SetLevel(log.DebugLevel) + componentName = name +} + +func Info(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": componentName, + }).Info(args...) +} + +func Debug(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": componentName, + }).Debug(args...) +} + +func Warn(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": componentName, + }).Warn(args...) +} +func Error(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": componentName, + }).Error(args...) +} +func Panic(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": componentName, + }).Panic(args...) +} + +func Fatal(args ...interface{}) { + log.WithFields(log.Fields{ + "meep.component": componentName, + }).Fatal(args...) +} + +func WithFields(fields log.Fields) *log.Entry { + return log.WithFields(fields) +} diff --git a/go-packages/meep-mg-app-client/.gitignore b/go-packages/meep-mg-app-client/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..daf913b1b347aae6de6f48d599bc89ef8c8693d6 --- /dev/null +++ b/go-packages/meep-mg-app-client/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/go-packages/meep-mg-app-client/.swagger-codegen-ignore b/go-packages/meep-mg-app-client/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/go-packages/meep-mg-app-client/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/go-packages/meep-mg-app-client/.swagger-codegen/VERSION b/go-packages/meep-mg-app-client/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..a6254504e40175d135cea7feb34ad31fa0d0bca3 --- /dev/null +++ b/go-packages/meep-mg-app-client/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.1 \ No newline at end of file diff --git a/go-packages/meep-mg-app-client/.travis.yml b/go-packages/meep-mg-app-client/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..f5cb2ce9a5aad73c57eed886e845d2e79c2899d1 --- /dev/null +++ b/go-packages/meep-mg-app-client/.travis.yml @@ -0,0 +1,8 @@ +language: go + +install: + - go get -d -v . + +script: + - go build -v ./ + diff --git a/go-packages/meep-mg-app-client/README.md b/go-packages/meep-mg-app-client/README.md new file mode 100644 index 0000000000000000000000000000000000000000..42fce18b02782a090915663c7370c72b73840aec --- /dev/null +++ b/go-packages/meep-mg-app-client/README.md @@ -0,0 +1,40 @@ +# Go API client for client + +Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: 1.0.0 +- Package version: 1.0.0 +- Build package: io.swagger.codegen.languages.GoClientCodegen + +## Installation +Put the package under your project folder and add the following in import: +``` + "./client" +``` + +## Documentation for API Endpoints + +All URIs are relative to *http://localhost/v1* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*StateTransferApi* | [**HandleEvent**](docs/StateTransferApi.md#handleevent) | **Post** /mg/event | Send event notification to registered Mobility Group Application + + +## Documentation For Models + + - [MobilityGroupAppState](docs/MobilityGroupAppState.md) + - [MobilityGroupEvent](docs/MobilityGroupEvent.md) + + +## Documentation For Authorization + Endpoints do not require authorization. + + +## Author + + + diff --git a/interfaces/meep-mg-app-api-client.yaml b/go-packages/meep-mg-app-client/api/swagger.yaml similarity index 92% rename from interfaces/meep-mg-app-api-client.yaml rename to go-packages/meep-mg-app-client/api/swagger.yaml index aaed41697212937cf91f31a3ab1d553e05269037..89798d0a67887f26c4b9a36a439c5d93ff7a1524 100644 --- a/interfaces/meep-mg-app-api-client.yaml +++ b/go-packages/meep-mg-app-client/api/swagger.yaml @@ -1,7 +1,9 @@ --- swagger: "2.0" info: - description: "MEEP Mobility Group Application REST API" + description: "Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved.\ + \ The information provided herein is the proprietary and confidential information\ + \ of InterDigital Communications, Inc.\n" version: "1.0.0" title: "MEEP Mobility Group Application REST API" basePath: "/v1" diff --git a/go-packages/meep-mg-app-client/api_client.go b/go-packages/meep-mg-app-client/api_client.go new file mode 100644 index 0000000000000000000000000000000000000000..08b377c5b5c4427112a2cec859a01e38b351c078 --- /dev/null +++ b/go-packages/meep-mg-app-client/api_client.go @@ -0,0 +1,424 @@ +/* + * MEEP Mobility Group Application REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/net/context" + "golang.org/x/oauth2" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") + xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") +) + +// APIClient manages communication with the MEEP Mobility Group Application REST API API v1.0.0 +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service // Reuse a single struct instead of allocating one for each service on the heap. + + // API Services + StateTransferApi *StateTransferApiService +} + +type service struct { + client *APIClient +} + +// NewAPIClient creates a new API client. Requires a userAgent string describing your application. +// optionally a custom http.Client to allow for advanced features such as caching. +func NewAPIClient(cfg *Configuration) *APIClient { + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + + c := &APIClient{} + c.cfg = cfg + c.common.client = c + + // API Services + c.StateTransferApi = (*StateTransferApiService)(&c.common) + + return c +} + +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] // use the first content type specified in 'consumes' +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + // Make sure there is an object. + if obj == nil { + return nil + } + + // Check the type is as expected. + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string) string { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return fmt.Sprintf("%v", obj) +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// prepareRequest build the request +func (c *APIClient) prepareRequest( + ctx context.Context, + path string, method string, + postBody interface{}, + headerParams map[string]string, + queryParams url.Values, + formParams url.Values, + fileName string, + fileBytes []byte) (localVarRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + contentType := headerParams["Content-Type"] + if contentType == "" { + contentType = detectContentType(postBody) + headerParams["Content-Type"] = contentType + } + + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // add form parameters and file if available. + if len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { + if body != nil { + return nil, errors.New("Cannot specify postBody and multipart form at the same time.") + } + body = &bytes.Buffer{} + w := multipart.NewWriter(body) + + for k, v := range formParams { + for _, iv := range v { + if strings.HasPrefix(k, "@") { // file + err = addFile(w, k[1:], iv) + if err != nil { + return nil, err + } + } else { // form value + w.WriteField(k, iv) + } + } + } + if len(fileBytes) > 0 && fileName != "" { + w.Boundary() + //_, fileNm := filepath.Split(fileName) + part, err := w.CreateFormFile("file", filepath.Base(fileName)) + if err != nil { + return nil, err + } + _, err = part.Write(fileBytes) + if err != nil { + return nil, err + } + // Set the Boundary in the Content-Type + headerParams["Content-Type"] = w.FormDataContentType() + } + + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + w.Close() + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Adding Query Param + query := url.Query() + for k, v := range queryParams { + for _, iv := range v { + query.Add(k, iv) + } + } + + // Encode the parameters. + url.RawQuery = query.Encode() + + // Generate a new request + if body != nil { + localVarRequest, err = http.NewRequest(method, url.String(), body) + } else { + localVarRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add header parameters, if any + if len(headerParams) > 0 { + headers := http.Header{} + for h, v := range headerParams { + headers.Set(h, v) + } + localVarRequest.Header = headers + } + + // Override request host, if applicable + if c.cfg.Host != "" { + localVarRequest.Host = c.cfg.Host + } + + // Add the user agent to the request. + localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) + + if ctx != nil { + // add context to the request + localVarRequest = localVarRequest.WithContext(ctx) + + // Walk through any authentication. + + // OAuth2 authentication + if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { + // We were able to grab an oauth2 token from the context + var latestToken *oauth2.Token + if latestToken, err = tok.Token(); err != nil { + return nil, err + } + + latestToken.SetAuthHeader(localVarRequest) + } + + // Basic HTTP Authentication + if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { + localVarRequest.SetBasicAuth(auth.UserName, auth.Password) + } + + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) + } + } + + for header, value := range c.cfg.DefaultHeader { + localVarRequest.Header.Add(header, value) + } + + return localVarRequest, nil +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} diff --git a/go-packages/meep-mg-app-client/api_response.go b/go-packages/meep-mg-app-client/api_response.go new file mode 100644 index 0000000000000000000000000000000000000000..d4e02487e94bbc2bdd91d4b64b8e1c4a9d972eb3 --- /dev/null +++ b/go-packages/meep-mg-app-client/api_response.go @@ -0,0 +1,43 @@ +/* + * MEEP Mobility Group Application REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "net/http" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/go-packages/meep-mg-app-client/configuration.go b/go-packages/meep-mg-app-client/configuration.go new file mode 100644 index 0000000000000000000000000000000000000000..48e0d771cf1629c268147016744ebda0c2148143 --- /dev/null +++ b/go-packages/meep-mg-app-client/configuration.go @@ -0,0 +1,72 @@ +/* + * MEEP Mobility Group Application REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "net/http" +) + +// contextKeys are used to identify the type of value in the context. +// Since these are string, it is possible to get a short description of the +// context key for logging and debugging using key.String(). + +type contextKey string + +func (c contextKey) String() string { + return "auth " + string(c) +} + +var ( + // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. + ContextOAuth2 = contextKey("token") + + // ContextBasicAuth takes BasicAuth as authentication for the request. + ContextBasicAuth = contextKey("basic") + + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") + + // ContextAPIKey takes an APIKey as authentication for the request + ContextAPIKey = contextKey("apikey") +) + +// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth +type BasicAuth struct { + UserName string `json:"userName,omitempty"` + Password string `json:"password,omitempty"` +} + +// APIKey provides API key based authentication to a request passed via context using ContextAPIKey +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "http://localhost/v1", + DefaultHeader: make(map[string]string), + UserAgent: "Swagger-Codegen/1.0.0/go", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/go-packages/meep-mg-app-client/docs/MobilityGroupAppState.md b/go-packages/meep-mg-app-client/docs/MobilityGroupAppState.md new file mode 100644 index 0000000000000000000000000000000000000000..f53ee6a88eb335f62705a4c4d2d946c9c5ca3dfc --- /dev/null +++ b/go-packages/meep-mg-app-client/docs/MobilityGroupAppState.md @@ -0,0 +1,11 @@ +# MobilityGroupAppState + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**UeId** | **string** | Mobility Group UE Identifier | [optional] [default to null] +**UeState** | **string** | Mobility Group Application State for provided UE | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-app-client/docs/MobilityGroupEvent.md b/go-packages/meep-mg-app-client/docs/MobilityGroupEvent.md new file mode 100644 index 0000000000000000000000000000000000000000..6745a48b6f17835788d08c910350273bf08746b1 --- /dev/null +++ b/go-packages/meep-mg-app-client/docs/MobilityGroupEvent.md @@ -0,0 +1,13 @@ +# MobilityGroupEvent + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Mobility Group event name | [optional] [default to null] +**Type_** | **string** | Mobility Group event type | [optional] [default to null] +**UeId** | **string** | Mobility Group UE identifier | [optional] [default to null] +**AppState** | [***MobilityGroupAppState**](MobilityGroupAppState.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-app-client/docs/StateTransferApi.md b/go-packages/meep-mg-app-client/docs/StateTransferApi.md new file mode 100644 index 0000000000000000000000000000000000000000..d569daca9047bc9eb68b8c5f3da1b7182fa41d5b --- /dev/null +++ b/go-packages/meep-mg-app-client/docs/StateTransferApi.md @@ -0,0 +1,37 @@ +# \StateTransferApi + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**HandleEvent**](StateTransferApi.md#HandleEvent) | **Post** /mg/event | Send event notification to registered Mobility Group Application + + +# **HandleEvent** +> HandleEvent(ctx, event) +Send event notification to registered Mobility Group Application + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **event** | [**MobilityGroupEvent**](MobilityGroupEvent.md)| Mobility Group event notification | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-mg-app-client/git_push.sh b/go-packages/meep-mg-app-client/git_push.sh new file mode 100644 index 0000000000000000000000000000000000000000..ae01b182ae9eb047d0999a496b060e62d7b01e5c --- /dev/null +++ b/go-packages/meep-mg-app-client/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/go-packages/meep-mg-app-client/go.mod b/go-packages/meep-mg-app-client/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..04f26a45172e797555fa052e3120299245ef5f49 --- /dev/null +++ b/go-packages/meep-mg-app-client/go.mod @@ -0,0 +1,8 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-app-client + +go 1.12 + +require ( + golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 + golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a +) diff --git a/go-packages/meep-mg-app-client/go.sum b/go-packages/meep-mg-app-client/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..140259886aed6f6e5a98be4585ab29c9af9112fd --- /dev/null +++ b/go-packages/meep-mg-app-client/go.sum @@ -0,0 +1,16 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 h1:tzVWzOrXxwAwdSCMrf+mbNrZFxwS0+HLP4m2qxtfdhk= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/go-packages/meep-mg-app-client/mobility_group_app_state.go b/go-packages/meep-mg-app-client/mobility_group_app_state.go new file mode 100644 index 0000000000000000000000000000000000000000..d7c7961223df2f1648f2cd712f73be31dc5a3c85 --- /dev/null +++ b/go-packages/meep-mg-app-client/mobility_group_app_state.go @@ -0,0 +1,20 @@ +/* + * MEEP Mobility Group Application REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Mobility Group Application State +type MobilityGroupAppState struct { + + // Mobility Group UE Identifier + UeId string `json:"ueId,omitempty"` + + // Mobility Group Application State for provided UE + UeState string `json:"ueState,omitempty"` +} diff --git a/go-packages/meep-mg-app-client/mobility_group_event.go b/go-packages/meep-mg-app-client/mobility_group_event.go new file mode 100644 index 0000000000000000000000000000000000000000..836481a754ff14f99619dbd27552864ee8cf1cfe --- /dev/null +++ b/go-packages/meep-mg-app-client/mobility_group_event.go @@ -0,0 +1,25 @@ +/* + * MEEP Mobility Group Application REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Event object +type MobilityGroupEvent struct { + + // Mobility Group event name + Name string `json:"name,omitempty"` + + // Mobility Group event type + Type_ string `json:"type,omitempty"` + + // Mobility Group UE identifier + UeId string `json:"ueId,omitempty"` + + AppState *MobilityGroupAppState `json:"appState,omitempty"` +} diff --git a/go-packages/meep-mg-app-client/state_transfer_api.go b/go-packages/meep-mg-app-client/state_transfer_api.go new file mode 100644 index 0000000000000000000000000000000000000000..6c80aa316b2f9e185eedfe9a35a2e0f1386077cf --- /dev/null +++ b/go-packages/meep-mg-app-client/state_transfer_api.go @@ -0,0 +1,85 @@ +/* + * MEEP Mobility Group Application REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type StateTransferApiService service + +/* StateTransferApiService Send event notification to registered Mobility Group Application + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param event Mobility Group event notification +@return */ +func (a *StateTransferApiService) HandleEvent(ctx context.Context, event MobilityGroupEvent) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/event" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &event + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} diff --git a/go-packages/meep-mg-manager-client/.gitignore b/go-packages/meep-mg-manager-client/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..daf913b1b347aae6de6f48d599bc89ef8c8693d6 --- /dev/null +++ b/go-packages/meep-mg-manager-client/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/go-packages/meep-mg-manager-client/.swagger-codegen-ignore b/go-packages/meep-mg-manager-client/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/go-packages/meep-mg-manager-client/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/go-packages/meep-mg-manager-client/.swagger-codegen/VERSION b/go-packages/meep-mg-manager-client/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..a6254504e40175d135cea7feb34ad31fa0d0bca3 --- /dev/null +++ b/go-packages/meep-mg-manager-client/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.1 \ No newline at end of file diff --git a/go-packages/meep-mg-manager-client/.travis.yml b/go-packages/meep-mg-manager-client/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..f5cb2ce9a5aad73c57eed886e845d2e79c2899d1 --- /dev/null +++ b/go-packages/meep-mg-manager-client/.travis.yml @@ -0,0 +1,8 @@ +language: go + +install: + - go get -d -v . + +script: + - go build -v ./ + diff --git a/go-packages/meep-mg-manager-client/README.md b/go-packages/meep-mg-manager-client/README.md new file mode 100644 index 0000000000000000000000000000000000000000..589829760aeed4d1774e4ab1de51bc2488653053 --- /dev/null +++ b/go-packages/meep-mg-manager-client/README.md @@ -0,0 +1,53 @@ +# Go API client for client + +Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: 1.0.0 +- Package version: 1.0.0 +- Build package: io.swagger.codegen.languages.GoClientCodegen + +## Installation +Put the package under your project folder and add the following in import: +``` + "./client" +``` + +## Documentation for API Endpoints + +All URIs are relative to *http://localhost/v1* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*MembershipApi* | [**CreateMobilityGroup**](docs/MembershipApi.md#createmobilitygroup) | **Post** /mg/{mgName} | Add new Mobility Group +*MembershipApi* | [**CreateMobilityGroupApp**](docs/MembershipApi.md#createmobilitygroupapp) | **Post** /mg/{mgName}/app/{appId} | Add new Mobility Group App +*MembershipApi* | [**CreateMobilityGroupUe**](docs/MembershipApi.md#createmobilitygroupue) | **Post** /mg/{mgName}/app/{appId}/ue | Add UE to group tracking list +*MembershipApi* | [**DeleteMobilityGroup**](docs/MembershipApi.md#deletemobilitygroup) | **Delete** /mg/{mgName} | Delete Mobility Group +*MembershipApi* | [**DeleteMobilityGroupApp**](docs/MembershipApi.md#deletemobilitygroupapp) | **Delete** /mg/{mgName}/app/{appId} | Delete Mobility Group App +*MembershipApi* | [**GetMobilityGroup**](docs/MembershipApi.md#getmobilitygroup) | **Get** /mg/{mgName} | Retrieve Mobility Groups with provided name +*MembershipApi* | [**GetMobilityGroupApp**](docs/MembershipApi.md#getmobilitygroupapp) | **Get** /mg/{mgName}/app/{appId} | Retrieve App information using provided Mobility Group Name & App ID +*MembershipApi* | [**GetMobilityGroupAppList**](docs/MembershipApi.md#getmobilitygroupapplist) | **Get** /mg/{mgName}/app | Retrieve list of Apps in provided Mobility Group +*MembershipApi* | [**GetMobilityGroupList**](docs/MembershipApi.md#getmobilitygrouplist) | **Get** /mg | Retrieve list of Mobility Groups +*MembershipApi* | [**SetMobilityGroup**](docs/MembershipApi.md#setmobilitygroup) | **Put** /mg/{mgName} | Update Mobility Group +*MembershipApi* | [**SetMobilityGroupApp**](docs/MembershipApi.md#setmobilitygroupapp) | **Put** /mg/{mgName}/app/{appId} | Update Mobility GroupApp +*StateTransferApi* | [**TransferAppState**](docs/StateTransferApi.md#transferappstate) | **Post** /mg/{mgName}/app/{appId}/state | Send state to transfer to peers + + +## Documentation For Models + + - [MobilityGroup](docs/MobilityGroup.md) + - [MobilityGroupApp](docs/MobilityGroupApp.md) + - [MobilityGroupAppState](docs/MobilityGroupAppState.md) + - [MobilityGroupUe](docs/MobilityGroupUe.md) + + +## Documentation For Authorization + Endpoints do not require authorization. + + +## Author + + + diff --git a/interfaces/meep-mg-manager.yaml b/go-packages/meep-mg-manager-client/api/swagger.yaml similarity index 98% rename from interfaces/meep-mg-manager.yaml rename to go-packages/meep-mg-manager-client/api/swagger.yaml index a747857f9e63d931a03c1e8bee5fbf3c2ad662c7..6bbb1f97c38ae6e30ccae96f968411cd20e5f3de 100644 --- a/interfaces/meep-mg-manager.yaml +++ b/go-packages/meep-mg-manager-client/api/swagger.yaml @@ -1,7 +1,9 @@ --- swagger: "2.0" info: - description: "MEEP Mobility Group Manager REST API" + description: "Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved.\ + \ The information provided herein is the proprietary and confidential information\ + \ of InterDigital Communications, Inc.\n" version: "1.0.0" title: "MEEP Mobility Group Manager REST API" basePath: "/v1" diff --git a/go-packages/meep-mg-manager-client/api_client.go b/go-packages/meep-mg-manager-client/api_client.go new file mode 100644 index 0000000000000000000000000000000000000000..b079adb731685900966adec0bdf8759c0b9b7adb --- /dev/null +++ b/go-packages/meep-mg-manager-client/api_client.go @@ -0,0 +1,426 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/net/context" + "golang.org/x/oauth2" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") + xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") +) + +// APIClient manages communication with the MEEP Mobility Group Manager REST API API v1.0.0 +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service // Reuse a single struct instead of allocating one for each service on the heap. + + // API Services + MembershipApi *MembershipApiService + StateTransferApi *StateTransferApiService +} + +type service struct { + client *APIClient +} + +// NewAPIClient creates a new API client. Requires a userAgent string describing your application. +// optionally a custom http.Client to allow for advanced features such as caching. +func NewAPIClient(cfg *Configuration) *APIClient { + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + + c := &APIClient{} + c.cfg = cfg + c.common.client = c + + // API Services + c.MembershipApi = (*MembershipApiService)(&c.common) + c.StateTransferApi = (*StateTransferApiService)(&c.common) + + return c +} + +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] // use the first content type specified in 'consumes' +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + // Make sure there is an object. + if obj == nil { + return nil + } + + // Check the type is as expected. + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string) string { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return fmt.Sprintf("%v", obj) +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// prepareRequest build the request +func (c *APIClient) prepareRequest( + ctx context.Context, + path string, method string, + postBody interface{}, + headerParams map[string]string, + queryParams url.Values, + formParams url.Values, + fileName string, + fileBytes []byte) (localVarRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + contentType := headerParams["Content-Type"] + if contentType == "" { + contentType = detectContentType(postBody) + headerParams["Content-Type"] = contentType + } + + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // add form parameters and file if available. + if len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { + if body != nil { + return nil, errors.New("Cannot specify postBody and multipart form at the same time.") + } + body = &bytes.Buffer{} + w := multipart.NewWriter(body) + + for k, v := range formParams { + for _, iv := range v { + if strings.HasPrefix(k, "@") { // file + err = addFile(w, k[1:], iv) + if err != nil { + return nil, err + } + } else { // form value + w.WriteField(k, iv) + } + } + } + if len(fileBytes) > 0 && fileName != "" { + w.Boundary() + //_, fileNm := filepath.Split(fileName) + part, err := w.CreateFormFile("file", filepath.Base(fileName)) + if err != nil { + return nil, err + } + _, err = part.Write(fileBytes) + if err != nil { + return nil, err + } + // Set the Boundary in the Content-Type + headerParams["Content-Type"] = w.FormDataContentType() + } + + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + w.Close() + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Adding Query Param + query := url.Query() + for k, v := range queryParams { + for _, iv := range v { + query.Add(k, iv) + } + } + + // Encode the parameters. + url.RawQuery = query.Encode() + + // Generate a new request + if body != nil { + localVarRequest, err = http.NewRequest(method, url.String(), body) + } else { + localVarRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add header parameters, if any + if len(headerParams) > 0 { + headers := http.Header{} + for h, v := range headerParams { + headers.Set(h, v) + } + localVarRequest.Header = headers + } + + // Override request host, if applicable + if c.cfg.Host != "" { + localVarRequest.Host = c.cfg.Host + } + + // Add the user agent to the request. + localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) + + if ctx != nil { + // add context to the request + localVarRequest = localVarRequest.WithContext(ctx) + + // Walk through any authentication. + + // OAuth2 authentication + if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { + // We were able to grab an oauth2 token from the context + var latestToken *oauth2.Token + if latestToken, err = tok.Token(); err != nil { + return nil, err + } + + latestToken.SetAuthHeader(localVarRequest) + } + + // Basic HTTP Authentication + if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { + localVarRequest.SetBasicAuth(auth.UserName, auth.Password) + } + + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) + } + } + + for header, value := range c.cfg.DefaultHeader { + localVarRequest.Header.Add(header, value) + } + + return localVarRequest, nil +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} diff --git a/go-packages/meep-mg-manager-client/api_response.go b/go-packages/meep-mg-manager-client/api_response.go new file mode 100644 index 0000000000000000000000000000000000000000..37c255b66bdb36adb7c25f2fcec31e75c1ecc1a6 --- /dev/null +++ b/go-packages/meep-mg-manager-client/api_response.go @@ -0,0 +1,43 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "net/http" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/go-packages/meep-mg-manager-client/configuration.go b/go-packages/meep-mg-manager-client/configuration.go new file mode 100644 index 0000000000000000000000000000000000000000..3a68f704958e00c18985aab674c94eadfdba6869 --- /dev/null +++ b/go-packages/meep-mg-manager-client/configuration.go @@ -0,0 +1,72 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "net/http" +) + +// contextKeys are used to identify the type of value in the context. +// Since these are string, it is possible to get a short description of the +// context key for logging and debugging using key.String(). + +type contextKey string + +func (c contextKey) String() string { + return "auth " + string(c) +} + +var ( + // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. + ContextOAuth2 = contextKey("token") + + // ContextBasicAuth takes BasicAuth as authentication for the request. + ContextBasicAuth = contextKey("basic") + + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") + + // ContextAPIKey takes an APIKey as authentication for the request + ContextAPIKey = contextKey("apikey") +) + +// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth +type BasicAuth struct { + UserName string `json:"userName,omitempty"` + Password string `json:"password,omitempty"` +} + +// APIKey provides API key based authentication to a request passed via context using ContextAPIKey +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "http://localhost/v1", + DefaultHeader: make(map[string]string), + UserAgent: "Swagger-Codegen/1.0.0/go", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/go-packages/meep-mg-manager-client/docs/MembershipApi.md b/go-packages/meep-mg-manager-client/docs/MembershipApi.md new file mode 100644 index 0000000000000000000000000000000000000000..3c5e64a2b0c1efe4a8ab15d0a239b0f05e7c36d0 --- /dev/null +++ b/go-packages/meep-mg-manager-client/docs/MembershipApi.md @@ -0,0 +1,333 @@ +# \MembershipApi + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**CreateMobilityGroup**](MembershipApi.md#CreateMobilityGroup) | **Post** /mg/{mgName} | Add new Mobility Group +[**CreateMobilityGroupApp**](MembershipApi.md#CreateMobilityGroupApp) | **Post** /mg/{mgName}/app/{appId} | Add new Mobility Group App +[**CreateMobilityGroupUe**](MembershipApi.md#CreateMobilityGroupUe) | **Post** /mg/{mgName}/app/{appId}/ue | Add UE to group tracking list +[**DeleteMobilityGroup**](MembershipApi.md#DeleteMobilityGroup) | **Delete** /mg/{mgName} | Delete Mobility Group +[**DeleteMobilityGroupApp**](MembershipApi.md#DeleteMobilityGroupApp) | **Delete** /mg/{mgName}/app/{appId} | Delete Mobility Group App +[**GetMobilityGroup**](MembershipApi.md#GetMobilityGroup) | **Get** /mg/{mgName} | Retrieve Mobility Groups with provided name +[**GetMobilityGroupApp**](MembershipApi.md#GetMobilityGroupApp) | **Get** /mg/{mgName}/app/{appId} | Retrieve App information using provided Mobility Group Name & App ID +[**GetMobilityGroupAppList**](MembershipApi.md#GetMobilityGroupAppList) | **Get** /mg/{mgName}/app | Retrieve list of Apps in provided Mobility Group +[**GetMobilityGroupList**](MembershipApi.md#GetMobilityGroupList) | **Get** /mg | Retrieve list of Mobility Groups +[**SetMobilityGroup**](MembershipApi.md#SetMobilityGroup) | **Put** /mg/{mgName} | Update Mobility Group +[**SetMobilityGroupApp**](MembershipApi.md#SetMobilityGroupApp) | **Put** /mg/{mgName}/app/{appId} | Update Mobility GroupApp + + +# **CreateMobilityGroup** +> CreateMobilityGroup(ctx, mgName, mobilityGroup) +Add new Mobility Group + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + **mobilityGroup** | [**MobilityGroup**](MobilityGroup.md)| Mobility Group to create/update | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **CreateMobilityGroupApp** +> CreateMobilityGroupApp(ctx, mgName, appId, mgApp) +Add new Mobility Group App + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + **appId** | **string**| Mobility Group App Id | + **mgApp** | [**MobilityGroupApp**](MobilityGroupApp.md)| Mobility Group App to create/update | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **CreateMobilityGroupUe** +> CreateMobilityGroupUe(ctx, mgName, appId, mgUe) +Add UE to group tracking list + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + **appId** | **string**| Mobility Group App Id | + **mgUe** | [**MobilityGroupUe**](MobilityGroupUe.md)| Mobility Group UE to create/update | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **DeleteMobilityGroup** +> DeleteMobilityGroup(ctx, mgName) +Delete Mobility Group + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **DeleteMobilityGroupApp** +> DeleteMobilityGroupApp(ctx, mgName, appId) +Delete Mobility Group App + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + **appId** | **string**| Mobility Group App Id | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetMobilityGroup** +> MobilityGroup GetMobilityGroup(ctx, mgName) +Retrieve Mobility Groups with provided name + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + +### Return type + +[**MobilityGroup**](MobilityGroup.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetMobilityGroupApp** +> MobilityGroupApp GetMobilityGroupApp(ctx, mgName, appId) +Retrieve App information using provided Mobility Group Name & App ID + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + **appId** | **string**| Mobility Group App Id | + +### Return type + +[**MobilityGroupApp**](MobilityGroupApp.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetMobilityGroupAppList** +> []MobilityGroupApp GetMobilityGroupAppList(ctx, mgName) +Retrieve list of Apps in provided Mobility Group + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + +### Return type + +[**[]MobilityGroupApp**](MobilityGroupApp.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetMobilityGroupList** +> []MobilityGroup GetMobilityGroupList(ctx, ) +Retrieve list of Mobility Groups + + + +### Required Parameters +This endpoint does not need any parameter. + +### Return type + +[**[]MobilityGroup**](MobilityGroup.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **SetMobilityGroup** +> SetMobilityGroup(ctx, mgName, mobilityGroup) +Update Mobility Group + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + **mobilityGroup** | [**MobilityGroup**](MobilityGroup.md)| Mobility Group to create/update | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **SetMobilityGroupApp** +> SetMobilityGroupApp(ctx, mgName, appId, mgApp) +Update Mobility GroupApp + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + **appId** | **string**| Mobility Group App Id | + **mgApp** | [**MobilityGroupApp**](MobilityGroupApp.md)| Mobility Group App to create/update | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-mg-manager-client/docs/MobilityGroup.md b/go-packages/meep-mg-manager-client/docs/MobilityGroup.md new file mode 100644 index 0000000000000000000000000000000000000000..947973c2ea618cd4bb8094f03119b2af09beec88 --- /dev/null +++ b/go-packages/meep-mg-manager-client/docs/MobilityGroup.md @@ -0,0 +1,14 @@ +# MobilityGroup + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Mobility Group name | [optional] [default to null] +**StateTransferMode** | **string** | State Transfer mode | [optional] [default to null] +**StateTransferTrigger** | **string** | State Transfer trigger | [optional] [default to null] +**SessionTransferMode** | **string** | Session Transfer mode | [optional] [default to null] +**LoadBalancingAlgorithm** | **string** | Load Balancing Algorithm | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-client/docs/MobilityGroupApp.md b/go-packages/meep-mg-manager-client/docs/MobilityGroupApp.md new file mode 100644 index 0000000000000000000000000000000000000000..e6eca62ad724eaaeb6c78646f6fd4f1ac6b98cba --- /dev/null +++ b/go-packages/meep-mg-manager-client/docs/MobilityGroupApp.md @@ -0,0 +1,11 @@ +# MobilityGroupApp + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Mobility Group Application Identifier | [optional] [default to null] +**Url** | **string** | Event handler url | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-client/docs/MobilityGroupAppState.md b/go-packages/meep-mg-manager-client/docs/MobilityGroupAppState.md new file mode 100644 index 0000000000000000000000000000000000000000..f53ee6a88eb335f62705a4c4d2d946c9c5ca3dfc --- /dev/null +++ b/go-packages/meep-mg-manager-client/docs/MobilityGroupAppState.md @@ -0,0 +1,11 @@ +# MobilityGroupAppState + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**UeId** | **string** | Mobility Group UE Identifier | [optional] [default to null] +**UeState** | **string** | Mobility Group Application State for provided UE | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-client/docs/MobilityGroupUe.md b/go-packages/meep-mg-manager-client/docs/MobilityGroupUe.md new file mode 100644 index 0000000000000000000000000000000000000000..e8d0c58d466f0d57a6d8c53c4e11d35bbbb32584 --- /dev/null +++ b/go-packages/meep-mg-manager-client/docs/MobilityGroupUe.md @@ -0,0 +1,10 @@ +# MobilityGroupUe + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Mobility Group UE Identifier | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-client/docs/StateTransferApi.md b/go-packages/meep-mg-manager-client/docs/StateTransferApi.md new file mode 100644 index 0000000000000000000000000000000000000000..96d4b5f69f1886adca8db99ca1edb3cdc6af22ff --- /dev/null +++ b/go-packages/meep-mg-manager-client/docs/StateTransferApi.md @@ -0,0 +1,39 @@ +# \StateTransferApi + +All URIs are relative to *http://localhost/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**TransferAppState**](StateTransferApi.md#TransferAppState) | **Post** /mg/{mgName}/app/{appId}/state | Send state to transfer to peers + + +# **TransferAppState** +> TransferAppState(ctx, mgName, appId, appState) +Send state to transfer to peers + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **mgName** | **string**| Mobility Group name | + **appId** | **string**| Mobility Group App Id | + **appState** | [**MobilityGroupAppState**](MobilityGroupAppState.md)| Mobility Group App State to transfer | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-mg-manager-client/git_push.sh b/go-packages/meep-mg-manager-client/git_push.sh new file mode 100644 index 0000000000000000000000000000000000000000..ae01b182ae9eb047d0999a496b060e62d7b01e5c --- /dev/null +++ b/go-packages/meep-mg-manager-client/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/go-packages/meep-mg-manager-client/go.mod b/go-packages/meep-mg-manager-client/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..d70c5da1be14d6a3b49717fc967e19575d443db5 --- /dev/null +++ b/go-packages/meep-mg-manager-client/go.mod @@ -0,0 +1,8 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-manager-client + +go 1.12 + +require ( + golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 + golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a +) diff --git a/go-packages/meep-mg-manager-client/membership_api.go b/go-packages/meep-mg-manager-client/membership_api.go new file mode 100644 index 0000000000000000000000000000000000000000..36d3ba8623faedc5c5a114de0d07a97d53741780 --- /dev/null +++ b/go-packages/meep-mg-manager-client/membership_api.go @@ -0,0 +1,709 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type MembershipApiService service + +/* MembershipApiService Add new Mobility Group + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@param mobilityGroup Mobility Group to create/update +@return */ +func (a *MembershipApiService) CreateMobilityGroup(ctx context.Context, mgName string, mobilityGroup MobilityGroup) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &mobilityGroup + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* MembershipApiService Add new Mobility Group App + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@param appId Mobility Group App Id +@param mgApp Mobility Group App to create/update +@return */ +func (a *MembershipApiService) CreateMobilityGroupApp(ctx context.Context, mgName string, appId string, mgApp MobilityGroupApp) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}/app/{appId}" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + localVarPath = strings.Replace(localVarPath, "{"+"appId"+"}", fmt.Sprintf("%v", appId), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &mgApp + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* MembershipApiService Add UE to group tracking list + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@param appId Mobility Group App Id +@param mgUe Mobility Group UE to create/update +@return */ +func (a *MembershipApiService) CreateMobilityGroupUe(ctx context.Context, mgName string, appId string, mgUe MobilityGroupUe) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}/app/{appId}/ue" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + localVarPath = strings.Replace(localVarPath, "{"+"appId"+"}", fmt.Sprintf("%v", appId), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &mgUe + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* MembershipApiService Delete Mobility Group + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@return */ +func (a *MembershipApiService) DeleteMobilityGroup(ctx context.Context, mgName string) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Delete") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* MembershipApiService Delete Mobility Group App + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@param appId Mobility Group App Id +@return */ +func (a *MembershipApiService) DeleteMobilityGroupApp(ctx context.Context, mgName string, appId string) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Delete") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}/app/{appId}" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + localVarPath = strings.Replace(localVarPath, "{"+"appId"+"}", fmt.Sprintf("%v", appId), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* MembershipApiService Retrieve Mobility Groups with provided name + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@return MobilityGroup*/ +func (a *MembershipApiService) GetMobilityGroup(ctx context.Context, mgName string) (MobilityGroup, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload MobilityGroup + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* MembershipApiService Retrieve App information using provided Mobility Group Name & App ID + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@param appId Mobility Group App Id +@return MobilityGroupApp*/ +func (a *MembershipApiService) GetMobilityGroupApp(ctx context.Context, mgName string, appId string) (MobilityGroupApp, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload MobilityGroupApp + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}/app/{appId}" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + localVarPath = strings.Replace(localVarPath, "{"+"appId"+"}", fmt.Sprintf("%v", appId), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* MembershipApiService Retrieve list of Apps in provided Mobility Group + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@return []MobilityGroupApp*/ +func (a *MembershipApiService) GetMobilityGroupAppList(ctx context.Context, mgName string) ([]MobilityGroupApp, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload []MobilityGroupApp + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}/app" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* MembershipApiService Retrieve list of Mobility Groups + + * @param ctx context.Context for authentication, logging, tracing, etc. + @return []MobilityGroup*/ +func (a *MembershipApiService) GetMobilityGroupList(ctx context.Context) ([]MobilityGroup, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload []MobilityGroup + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* MembershipApiService Update Mobility Group + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@param mobilityGroup Mobility Group to create/update +@return */ +func (a *MembershipApiService) SetMobilityGroup(ctx context.Context, mgName string, mobilityGroup MobilityGroup) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Put") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &mobilityGroup + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* MembershipApiService Update Mobility GroupApp + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@param appId Mobility Group App Id +@param mgApp Mobility Group App to create/update +@return */ +func (a *MembershipApiService) SetMobilityGroupApp(ctx context.Context, mgName string, appId string, mgApp MobilityGroupApp) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Put") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}/app/{appId}" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + localVarPath = strings.Replace(localVarPath, "{"+"appId"+"}", fmt.Sprintf("%v", appId), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &mgApp + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} diff --git a/go-packages/meep-mg-manager-client/mobility_group.go b/go-packages/meep-mg-manager-client/mobility_group.go new file mode 100644 index 0000000000000000000000000000000000000000..fdf78acd7cb060fc13ae91176c8ea74526730013 --- /dev/null +++ b/go-packages/meep-mg-manager-client/mobility_group.go @@ -0,0 +1,29 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Mobility Group +type MobilityGroup struct { + + // Mobility Group name + Name string `json:"name,omitempty"` + + // State Transfer mode + StateTransferMode string `json:"stateTransferMode,omitempty"` + + // State Transfer trigger + StateTransferTrigger string `json:"stateTransferTrigger,omitempty"` + + // Session Transfer mode + SessionTransferMode string `json:"sessionTransferMode,omitempty"` + + // Load Balancing Algorithm + LoadBalancingAlgorithm string `json:"loadBalancingAlgorithm,omitempty"` +} diff --git a/go-packages/meep-mg-manager-client/mobility_group_app.go b/go-packages/meep-mg-manager-client/mobility_group_app.go new file mode 100644 index 0000000000000000000000000000000000000000..79248a373f607c6294e111b2025a4e81448b87bb --- /dev/null +++ b/go-packages/meep-mg-manager-client/mobility_group_app.go @@ -0,0 +1,20 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Mobility Group Application instance +type MobilityGroupApp struct { + + // Mobility Group Application Identifier + Id string `json:"id,omitempty"` + + // Event handler url + Url string `json:"url,omitempty"` +} diff --git a/go-packages/meep-mg-manager-client/mobility_group_app_state.go b/go-packages/meep-mg-manager-client/mobility_group_app_state.go new file mode 100644 index 0000000000000000000000000000000000000000..947d3c3670afcb479e93b24e98e91a05f34c2e11 --- /dev/null +++ b/go-packages/meep-mg-manager-client/mobility_group_app_state.go @@ -0,0 +1,20 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Mobility Group Application State +type MobilityGroupAppState struct { + + // Mobility Group UE Identifier + UeId string `json:"ueId,omitempty"` + + // Mobility Group Application State for provided UE + UeState string `json:"ueState,omitempty"` +} diff --git a/go-packages/meep-mg-manager-client/mobility_group_ue.go b/go-packages/meep-mg-manager-client/mobility_group_ue.go new file mode 100644 index 0000000000000000000000000000000000000000..e9db4bfa6c1ac3a7474f7f8da77ec55456cbf375 --- /dev/null +++ b/go-packages/meep-mg-manager-client/mobility_group_ue.go @@ -0,0 +1,17 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Mobility Group UE instance +type MobilityGroupUe struct { + + // Mobility Group UE Identifier + Id string `json:"id,omitempty"` +} diff --git a/go-packages/meep-mg-manager-client/state_transfer_api.go b/go-packages/meep-mg-manager-client/state_transfer_api.go new file mode 100644 index 0000000000000000000000000000000000000000..4693b868dca093d01a414945b8f82f4b5f69363b --- /dev/null +++ b/go-packages/meep-mg-manager-client/state_transfer_api.go @@ -0,0 +1,90 @@ +/* + * MEEP Mobility Group Manager REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type StateTransferApiService service + +/* StateTransferApiService Send state to transfer to peers + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param mgName Mobility Group name +@param appId Mobility Group App Id +@param appState Mobility Group App State to transfer +@return */ +func (a *StateTransferApiService) TransferAppState(ctx context.Context, mgName string, appId string, appState MobilityGroupAppState) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/mg/{mgName}/app/{appId}/state" + localVarPath = strings.Replace(localVarPath, "{"+"mgName"+"}", fmt.Sprintf("%v", mgName), -1) + localVarPath = strings.Replace(localVarPath, "{"+"appId"+"}", fmt.Sprintf("%v", appId), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &appState + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} diff --git a/bin/meep-ctrl-engine/static/api/meep-mg-manager-model.yaml b/go-packages/meep-mg-manager-model/api/swagger.yaml similarity index 91% rename from bin/meep-ctrl-engine/static/api/meep-mg-manager-model.yaml rename to go-packages/meep-mg-manager-model/api/swagger.yaml index 327abcead9b8ad5e67e4adfeaba3459ffa9d28a3..6b8beb7da18733387be05608a3108b9f83cf482b 100644 --- a/bin/meep-ctrl-engine/static/api/meep-mg-manager-model.yaml +++ b/go-packages/meep-mg-manager-model/api/swagger.yaml @@ -1,8 +1,11 @@ swagger: '2.0' info: - description: MEEP Mobility Group Manager Model + description: > + Copyright (c) 2019 InterDigital Communications, Inc. + All rights reserved. + The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. version: 1.0.0 - title: EEP Mobility Group Manager Model + title: MEEP Mobility Group Manager Model definitions: MobilityGroup: type: object diff --git a/go-packages/meep-mg-manager-model/docs/MobilityGroup.md b/go-packages/meep-mg-manager-model/docs/MobilityGroup.md new file mode 100644 index 0000000000000000000000000000000000000000..947973c2ea618cd4bb8094f03119b2af09beec88 --- /dev/null +++ b/go-packages/meep-mg-manager-model/docs/MobilityGroup.md @@ -0,0 +1,14 @@ +# MobilityGroup + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Mobility Group name | [optional] [default to null] +**StateTransferMode** | **string** | State Transfer mode | [optional] [default to null] +**StateTransferTrigger** | **string** | State Transfer trigger | [optional] [default to null] +**SessionTransferMode** | **string** | Session Transfer mode | [optional] [default to null] +**LoadBalancingAlgorithm** | **string** | Load Balancing Algorithm | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-model/docs/MobilityGroupApp.md b/go-packages/meep-mg-manager-model/docs/MobilityGroupApp.md new file mode 100644 index 0000000000000000000000000000000000000000..e6eca62ad724eaaeb6c78646f6fd4f1ac6b98cba --- /dev/null +++ b/go-packages/meep-mg-manager-model/docs/MobilityGroupApp.md @@ -0,0 +1,11 @@ +# MobilityGroupApp + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Mobility Group Application Identifier | [optional] [default to null] +**Url** | **string** | Event handler url | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-model/docs/MobilityGroupAppState.md b/go-packages/meep-mg-manager-model/docs/MobilityGroupAppState.md new file mode 100644 index 0000000000000000000000000000000000000000..f53ee6a88eb335f62705a4c4d2d946c9c5ca3dfc --- /dev/null +++ b/go-packages/meep-mg-manager-model/docs/MobilityGroupAppState.md @@ -0,0 +1,11 @@ +# MobilityGroupAppState + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**UeId** | **string** | Mobility Group UE Identifier | [optional] [default to null] +**UeState** | **string** | Mobility Group Application State for provided UE | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-model/docs/MobilityGroupEvent.md b/go-packages/meep-mg-manager-model/docs/MobilityGroupEvent.md new file mode 100644 index 0000000000000000000000000000000000000000..6745a48b6f17835788d08c910350273bf08746b1 --- /dev/null +++ b/go-packages/meep-mg-manager-model/docs/MobilityGroupEvent.md @@ -0,0 +1,13 @@ +# MobilityGroupEvent + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Mobility Group event name | [optional] [default to null] +**Type_** | **string** | Mobility Group event type | [optional] [default to null] +**UeId** | **string** | Mobility Group UE identifier | [optional] [default to null] +**AppState** | [***MobilityGroupAppState**](MobilityGroupAppState.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-model/docs/MobilityGroupServiceMap.md b/go-packages/meep-mg-manager-model/docs/MobilityGroupServiceMap.md new file mode 100644 index 0000000000000000000000000000000000000000..eba2dfaf6e11b28da5c416d0bff1401b5c94380f --- /dev/null +++ b/go-packages/meep-mg-manager-model/docs/MobilityGroupServiceMap.md @@ -0,0 +1,11 @@ +# MobilityGroupServiceMap + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**MgSvcName** | **string** | Mobility group service name | [optional] [default to null] +**LbSvcName** | **string** | Load balanced service instance name | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-model/docs/MobilityGroupUe.md b/go-packages/meep-mg-manager-model/docs/MobilityGroupUe.md new file mode 100644 index 0000000000000000000000000000000000000000..e8d0c58d466f0d57a6d8c53c4e11d35bbbb32584 --- /dev/null +++ b/go-packages/meep-mg-manager-model/docs/MobilityGroupUe.md @@ -0,0 +1,10 @@ +# MobilityGroupUe + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Mobility Group UE Identifier | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-model/docs/NetworkElement.md b/go-packages/meep-mg-manager-model/docs/NetworkElement.md new file mode 100644 index 0000000000000000000000000000000000000000..fb5b989e7d2297ca7212bb5cc100f1542673abdc --- /dev/null +++ b/go-packages/meep-mg-manager-model/docs/NetworkElement.md @@ -0,0 +1,11 @@ +# NetworkElement + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Network element name | [optional] [default to null] +**ServiceMaps** | [**[]MobilityGroupServiceMap**](MobilityGroupServiceMap.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-model/docs/NetworkElementList.md b/go-packages/meep-mg-manager-model/docs/NetworkElementList.md new file mode 100644 index 0000000000000000000000000000000000000000..78dd7d8712adde9e9f51cf47a250f9b6043583ea --- /dev/null +++ b/go-packages/meep-mg-manager-model/docs/NetworkElementList.md @@ -0,0 +1,10 @@ +# NetworkElementList + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**NetworkElements** | [**[]NetworkElement**](NetworkElement.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-mg-manager-model/go.mod b/go-packages/meep-mg-manager-model/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..484d43732e7b13fe103092d496c5679adb3d55e1 --- /dev/null +++ b/go-packages/meep-mg-manager-model/go.mod @@ -0,0 +1,3 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-mg-manager-model + +go 1.12 diff --git a/go-packages/meep-mg-manager-model/mobility_group.go b/go-packages/meep-mg-manager-model/mobility_group.go new file mode 100644 index 0000000000000000000000000000000000000000..875518cfd0baafd66668ffff9b1106c5688e5368 --- /dev/null +++ b/go-packages/meep-mg-manager-model/mobility_group.go @@ -0,0 +1,29 @@ +/* + * MEEP Mobility Group Manager Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Mobility Group +type MobilityGroup struct { + + // Mobility Group name + Name string `json:"name,omitempty"` + + // State Transfer mode + StateTransferMode string `json:"stateTransferMode,omitempty"` + + // State Transfer trigger + StateTransferTrigger string `json:"stateTransferTrigger,omitempty"` + + // Session Transfer mode + SessionTransferMode string `json:"sessionTransferMode,omitempty"` + + // Load Balancing Algorithm + LoadBalancingAlgorithm string `json:"loadBalancingAlgorithm,omitempty"` +} diff --git a/go-packages/meep-mg-manager-model/mobility_group_app.go b/go-packages/meep-mg-manager-model/mobility_group_app.go new file mode 100644 index 0000000000000000000000000000000000000000..240bc8f43ca2b6479e2331e65c75def89901a3aa --- /dev/null +++ b/go-packages/meep-mg-manager-model/mobility_group_app.go @@ -0,0 +1,20 @@ +/* + * MEEP Mobility Group Manager Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Mobility Group Application instance +type MobilityGroupApp struct { + + // Mobility Group Application Identifier + Id string `json:"id,omitempty"` + + // Event handler url + Url string `json:"url,omitempty"` +} diff --git a/go-packages/meep-mg-manager-model/mobility_group_app_state.go b/go-packages/meep-mg-manager-model/mobility_group_app_state.go new file mode 100644 index 0000000000000000000000000000000000000000..765eb438895b70c067c370629fb9ec0d3fb08ca2 --- /dev/null +++ b/go-packages/meep-mg-manager-model/mobility_group_app_state.go @@ -0,0 +1,20 @@ +/* + * MEEP Mobility Group Manager Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Mobility Group Application State +type MobilityGroupAppState struct { + + // Mobility Group UE Identifier + UeId string `json:"ueId,omitempty"` + + // Mobility Group Application State for provided UE + UeState string `json:"ueState,omitempty"` +} diff --git a/go-packages/meep-mg-manager-model/mobility_group_event.go b/go-packages/meep-mg-manager-model/mobility_group_event.go new file mode 100644 index 0000000000000000000000000000000000000000..4968d7879c72d86f63c3fbadece7a66a00e3bff5 --- /dev/null +++ b/go-packages/meep-mg-manager-model/mobility_group_event.go @@ -0,0 +1,25 @@ +/* + * MEEP Mobility Group Manager Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Event object +type MobilityGroupEvent struct { + + // Mobility Group event name + Name string `json:"name,omitempty"` + + // Mobility Group event type + Type_ string `json:"type,omitempty"` + + // Mobility Group UE identifier + UeId string `json:"ueId,omitempty"` + + AppState *MobilityGroupAppState `json:"appState,omitempty"` +} diff --git a/go-packages/meep-mg-manager-model/mobility_group_service_map.go b/go-packages/meep-mg-manager-model/mobility_group_service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..895b8f3534aa4934c216c96812d98c1b797e4ba5 --- /dev/null +++ b/go-packages/meep-mg-manager-model/mobility_group_service_map.go @@ -0,0 +1,20 @@ +/* + * MEEP Mobility Group Manager Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Mobility group service mapping +type MobilityGroupServiceMap struct { + + // Mobility group service name + MgSvcName string `json:"mgSvcName,omitempty"` + + // Load balanced service instance name + LbSvcName string `json:"lbSvcName,omitempty"` +} diff --git a/go-packages/meep-mg-manager-model/mobility_group_ue.go b/go-packages/meep-mg-manager-model/mobility_group_ue.go new file mode 100644 index 0000000000000000000000000000000000000000..de8d5f6d9747df2016df9c1b7d22f1e7068e0740 --- /dev/null +++ b/go-packages/meep-mg-manager-model/mobility_group_ue.go @@ -0,0 +1,17 @@ +/* + * MEEP Mobility Group Manager Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Mobility Group UE instance +type MobilityGroupUe struct { + + // Mobility Group UE Identifier + Id string `json:"id,omitempty"` +} diff --git a/go-packages/meep-mg-manager-model/network_element.go b/go-packages/meep-mg-manager-model/network_element.go new file mode 100644 index 0000000000000000000000000000000000000000..6218d49c57bdc59be9dabe878d7aa91c827512de --- /dev/null +++ b/go-packages/meep-mg-manager-model/network_element.go @@ -0,0 +1,19 @@ +/* + * MEEP Mobility Group Manager Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// Network element service mappings +type NetworkElement struct { + + // Network element name + Name string `json:"name,omitempty"` + + ServiceMaps []MobilityGroupServiceMap `json:"serviceMaps,omitempty"` +} diff --git a/go-packages/meep-mg-manager-model/network_element_list.go b/go-packages/meep-mg-manager-model/network_element_list.go new file mode 100644 index 0000000000000000000000000000000000000000..3ee5334002b0d5ce64150f5fc69c7fa874fee13d --- /dev/null +++ b/go-packages/meep-mg-manager-model/network_element_list.go @@ -0,0 +1,15 @@ +/* + * MEEP Mobility Group Manager Model + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package model + +// List of network element +type NetworkElementList struct { + NetworkElements []NetworkElement `json:"networkElements,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/.gitignore b/go-packages/meep-virt-engine-client/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..daf913b1b347aae6de6f48d599bc89ef8c8693d6 --- /dev/null +++ b/go-packages/meep-virt-engine-client/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/go-packages/meep-virt-engine-client/.swagger-codegen-ignore b/go-packages/meep-virt-engine-client/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/go-packages/meep-virt-engine-client/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/go-packages/meep-virt-engine-client/.swagger-codegen/VERSION b/go-packages/meep-virt-engine-client/.swagger-codegen/VERSION new file mode 100644 index 0000000000000000000000000000000000000000..a6254504e40175d135cea7feb34ad31fa0d0bca3 --- /dev/null +++ b/go-packages/meep-virt-engine-client/.swagger-codegen/VERSION @@ -0,0 +1 @@ +2.3.1 \ No newline at end of file diff --git a/go-packages/meep-virt-engine-client/.travis.yml b/go-packages/meep-virt-engine-client/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..f5cb2ce9a5aad73c57eed886e845d2e79c2899d1 --- /dev/null +++ b/go-packages/meep-virt-engine-client/.travis.yml @@ -0,0 +1,8 @@ +language: go + +install: + - go get -d -v . + +script: + - go build -v ./ + diff --git a/go-packages/meep-virt-engine-client/README.md b/go-packages/meep-virt-engine-client/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e239ac1a1ec8a8ec3b30fbf74c4159a5c9122dc9 --- /dev/null +++ b/go-packages/meep-virt-engine-client/README.md @@ -0,0 +1,59 @@ +# Go API client for client + +Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + +## Overview +This API client was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the [swagger-spec](https://github.com/swagger-api/swagger-spec) from a remote server, you can easily generate an API client. + +- API version: 1.0.0 +- Package version: 1.0.0 +- Build package: io.swagger.codegen.languages.GoClientCodegen + +## Installation +Put the package under your project folder and add the following in import: +``` + "./client" +``` + +## Documentation for API Endpoints + +All URIs are relative to *http://meep-virt-engine/v1* + +Class | Method | HTTP request | Description +------------ | ------------- | ------------- | ------------- +*ScenarioDeploymentApi* | [**ActivateScenario**](docs/ScenarioDeploymentApi.md#activatescenario) | **Post** /scenarios/active | Activate a scenario deployment +*ScenarioDeploymentApi* | [**GetActiveScenario**](docs/ScenarioDeploymentApi.md#getactivescenario) | **Get** /scenarios/active/{name} | Retrieve deployed scenarios +*ScenarioDeploymentApi* | [**TerminateScenario**](docs/ScenarioDeploymentApi.md#terminatescenario) | **Delete** /scenarios/active/{name} | Terminate a scenario deployment +*ScenarioExecutionApi* | [**SendEvent**](docs/ScenarioExecutionApi.md#sendevent) | **Post** /scenarios/active/events/{type} | Send event to active (deployed) scenario + + +## Documentation For Models + + - [Deployment](docs/Deployment.md) + - [Domain](docs/Domain.md) + - [Event](docs/Event.md) + - [EventNetworkCharacteristicsUpdate](docs/EventNetworkCharacteristicsUpdate.md) + - [EventOther](docs/EventOther.md) + - [EventPoasInRange](docs/EventPoasInRange.md) + - [EventUeMobility](docs/EventUeMobility.md) + - [ExternalConfig](docs/ExternalConfig.md) + - [NetworkLocation](docs/NetworkLocation.md) + - [PhysicalLocation](docs/PhysicalLocation.md) + - [Process](docs/Process.md) + - [Release](docs/Release.md) + - [Scenario](docs/Scenario.md) + - [ScenarioConfig](docs/ScenarioConfig.md) + - [ServiceConfig](docs/ServiceConfig.md) + - [ServiceMap](docs/ServiceMap.md) + - [ServicePort](docs/ServicePort.md) + - [Zone](docs/Zone.md) + + +## Documentation For Authorization + Endpoints do not require authorization. + + +## Author + + + diff --git a/go-packages/meep-virt-engine-client/api/swagger.yaml b/go-packages/meep-virt-engine-client/api/swagger.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fbc42cf1d5cc22e7c0b81548e4ca80ed61d6afa6 --- /dev/null +++ b/go-packages/meep-virt-engine-client/api/swagger.yaml @@ -0,0 +1,1483 @@ +--- +swagger: "2.0" +info: + description: "Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved.\ + \ The information provided herein is the proprietary and confidential information\ + \ of InterDigital Communications, Inc.\n" + version: "1.0.0" + title: "MEEP Virtualization Engine REST API" +host: "meep-virt-engine" +basePath: "/v1" +tags: +- name: "Scenario Deployment" +schemes: +- "http" +paths: + /scenarios/active/{name}: + get: + tags: + - "Scenario Deployment" + summary: "Retrieve deployed scenarios" + description: "" + operationId: "getActiveScenario" + produces: + - "application/json" + parameters: + - name: "name" + in: "path" + description: "Scenario name" + required: true + type: "string" + x-exportParamName: "Name" + responses: + 200: + description: "OK" + schema: + type: "array" + items: + $ref: "#/definitions/Release" + 404: + description: "Not found" + delete: + tags: + - "Scenario Deployment" + summary: "Terminate a scenario deployment" + description: "" + operationId: "terminateScenario" + produces: + - "application/json" + parameters: + - name: "name" + in: "path" + description: "Scenario name" + required: true + type: "string" + x-exportParamName: "Name" + responses: + 200: + description: "OK" + 404: + description: "Not found" + /scenarios/active: + post: + tags: + - "Scenario Deployment" + summary: "Activate a scenario deployment" + description: "" + operationId: "activateScenario" + produces: + - "application/json" + parameters: + - in: "body" + name: "scenario" + description: "Scenario to deploy" + required: true + schema: + $ref: "#/definitions/Scenario" + x-exportParamName: "Scenario" + responses: + 200: + description: "OK" + 400: + description: "Bad request" + 404: + description: "Not found" + /scenarios/active/events/{type}: + post: + tags: + - "Scenario Execution" + summary: "Send event to active (deployed) scenario" + description: "" + operationId: "sendEvent" + produces: + - "application/json" + parameters: + - name: "type" + in: "path" + description: "Event type" + required: true + type: "string" + x-exportParamName: "Type_" + - in: "body" + name: "event" + description: "Event to send to active scenario" + required: true + schema: + $ref: "#/definitions/Event" + x-exportParamName: "Event" + responses: + 200: + description: "OK" + 400: + description: "Bad request" +definitions: + Release: + type: "object" + properties: + name: + type: "string" + description: "Release name" + state: + type: "string" + description: "Current release state" + example: + name: "name" + state: "state" + Scenario: + type: "object" + properties: + name: + type: "string" + description: "Unique scenario name" + config: + $ref: "#/definitions/ScenarioConfig" + deployment: + $ref: "#/definitions/Deployment" + description: "Scenario object" + example: + name: "name" + config: + visualization: "visualization" + other: "other" + deployment: + domains: + - name: "name" + id: "id" + type: "OPERATOR" + zones: + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - name: "name" + id: "id" + type: "OPERATOR" + zones: + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + ScenarioConfig: + type: "object" + properties: + visualization: + type: "string" + description: "Visualization configuration" + other: + type: "string" + description: "Other scenario configuration" + description: "Scenario configuration" + example: + visualization: "visualization" + other: "other" + Deployment: + type: "object" + properties: + interDomainLatency: + type: "integer" + description: "Latency in ms between domains" + interDomainLatencyVariation: + type: "integer" + description: "Latency variation in ms between domains" + interDomainThroughput: + type: "integer" + description: "The limit of the traffic supported between domains" + interDomainPacketLoss: + type: "number" + format: "double" + description: "Packet lost (in terms of percentage) between domains" + domains: + type: "array" + items: + $ref: "#/definitions/Domain" + description: "Network deployment object" + example: + domains: + - name: "name" + id: "id" + type: "OPERATOR" + zones: + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - name: "name" + id: "id" + type: "OPERATOR" + zones: + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + Domain: + type: "object" + properties: + id: + type: "string" + description: "Unique domain ID" + name: + type: "string" + description: "Domain name" + type: + type: "string" + description: "Domain type" + enum: + - "OPERATOR" + - "PUBLIC" + interZoneLatency: + type: "integer" + description: "Latency in ms between zones within domain" + interZoneLatencyVariation: + type: "integer" + description: "Latency variation in ms between zones within domain" + interZoneThroughput: + type: "integer" + description: "The limit of the traffic supported between zones within the\ + \ domain" + interZonePacketLoss: + type: "number" + format: "double" + description: "Packet lost (in terms of percentage) between zones within the\ + \ domain" + zones: + type: "array" + items: + $ref: "#/definitions/Zone" + description: "Operator domain object" + example: + name: "name" + id: "id" + type: "OPERATOR" + zones: + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + Zone: + type: "object" + properties: + id: + type: "string" + description: "Unique zone ID" + name: + type: "string" + description: "Zone name" + type: + type: "string" + description: "Zone type" + enum: + - "ZONE" + - "COMMON" + interFogLatency: + type: "integer" + description: "Latency in ms between fog nodes (or PoAs) within zone" + interFogLatencyVariation: + type: "integer" + description: "Latency variation in ms between fog nodes (or PoAs) within zone" + interFogThroughput: + type: "integer" + description: "The limit of the traffic supported between fog nodes (or PoAs)\ + \ within the zone" + interFogPacketLoss: + type: "number" + format: "double" + description: "Packet lost (in terms of percentage) between fog nodes (or PoAs)\ + \ within the zone" + interEdgeLatency: + type: "integer" + description: "Latency in ms between edge nodes within zone" + interEdgeLatencyVariation: + type: "integer" + description: "Latency variation in ms between edge nodes within zone" + interEdgeThroughput: + type: "integer" + description: "The limit of the traffic supported between edge nodes within\ + \ the zone" + interEdgePacketLoss: + type: "number" + format: "double" + description: "Packet lost (in terms of percentage) between edge nodes within\ + \ the zone" + edgeFogLatency: + type: "integer" + description: "Latency in ms between fog nodes (or PoAs) and edge nodes within\ + \ zone" + edgeFogLatencyVariation: + type: "integer" + description: "Latency variation in ms between fog nodes (or PoAs) and edge\ + \ nodes within zone" + edgeFogThroughput: + type: "integer" + description: "The limit of the traffic supported between fog nodes (or PoAs)\ + \ and edge nodes within the zone" + edgeFogPacketLoss: + type: "number" + format: "double" + description: "Packet lost (in terms of percentage) between fog nodes (or PoAs)\ + \ and edge nodes within the zone" + networkLocations: + type: "array" + items: + $ref: "#/definitions/NetworkLocation" + description: "Logical zone (MEC network) object" + example: + name: "name" + id: "id" + type: "ZONE" + networkLocations: + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + - physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + NetworkLocation: + type: "object" + properties: + id: + type: "string" + description: "Unique network location ID" + name: + type: "string" + description: "Network location name" + type: + type: "string" + description: "Network location type" + enum: + - "POA" + - "DEFAULT" + terminalLinkLatency: + type: "integer" + description: "Latency in ms for all terminal links within network location" + terminalLinkLatencyVariation: + type: "integer" + description: "Latency variation in ms for all terminal links within network\ + \ location" + terminalLinkThroughput: + type: "integer" + description: "The limit of the traffic supported for all terminal links within\ + \ the network location" + terminalLinkPacketLoss: + type: "number" + format: "double" + description: "Packet lost (in terms of percentage) for all terminal links\ + \ within the network location" + physicalLocations: + type: "array" + items: + $ref: "#/definitions/PhysicalLocation" + description: "Logical network location object" + example: + physicalLocations: + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + - processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + name: "name" + id: "id" + type: "POA" + PhysicalLocation: + type: "object" + properties: + id: + type: "string" + description: "Unique physical location ID" + name: + type: "string" + description: "Physical location name" + type: + type: "string" + description: "Physical location type" + enum: + - "UE" + - "FOG" + - "EDGE" + - "CN" + - "DC" + isExternal: + type: "boolean" + description: "true: Physical location is external to MEEP\nfalse: Physical\ + \ location is internal to MEEP" + networkLocationsInRange: + type: "array" + items: + type: "string" + description: "Names of network locations within range of physical location" + processes: + type: "array" + items: + $ref: "#/definitions/Process" + description: "Physical location object" + example: + processes: + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + - isExternal: true + name: "name" + id: "id" + type: "UE-APP" + status: "status" + isExternal: true + name: "name" + id: "id" + type: "UE" + Process: + type: "object" + properties: + id: + type: "string" + description: "Unique process ID" + name: + type: "string" + description: "Process name" + type: + type: "string" + description: "Process type" + enum: + - "UE-APP" + - "EDGE-APP" + - "MEC-SVC" + - "CLOUD-APP" + isExternal: + type: "boolean" + description: "true: process is external to MEEP\nfalse: process is internal\ + \ to MEEP" + image: + type: "string" + description: "Docker image to deploy inside MEEP" + environment: + type: "string" + description: "Environment variables using the format NAME=\"value\",NAME=\"\ + value\",NAME=\"value\"" + commandArguments: + type: "string" + description: "Arguments to command executable" + commandExe: + type: "string" + description: "Executable to invoke at container start up" + serviceConfig: + $ref: "#/definitions/ServiceConfig" + externalConfig: + $ref: "#/definitions/ExternalConfig" + status: + type: "string" + description: "Process status" + userChartLocation: + type: "string" + description: "Chart location for the deployment of the chart provided by the\ + \ user" + userChartAlternateValues: + type: "string" + description: "Chart values.yaml file location for the deployment of the chart\ + \ provided by the user" + userChartGroup: + type: "string" + description: "Chart supplemental information related to the group (service)" + description: "Application or service object" + ServiceConfig: + type: "object" + properties: + name: + type: "string" + description: "Unique service name" + meSvcName: + type: "string" + description: "Multi-Edge service name, if any" + ports: + type: "array" + items: + $ref: "#/definitions/ServicePort" + description: "Service object" + ServicePort: + type: "object" + properties: + protocol: + type: "string" + description: "Protocol that the application is using (TCP or UDP)" + port: + type: "integer" + description: "Port number that the service is listening on" + externalPort: + type: "integer" + description: "External port number on which to expose the application (30000\ + \ - 32767)
  • Only one application allowed per external port
  • Scenario\ + \ builder must configure to prevent conflicts\n" + description: "Service port object" + ExternalConfig: + type: "object" + properties: + ingressServiceMap: + type: "array" + items: + $ref: "#/definitions/ServiceMap" + egressServiceMap: + type: "array" + items: + $ref: "#/definitions/ServiceMap" + description: "External Process configuration.\nNOTE: Only valid if 'isExternal'\ + \ is set." + ServiceMap: + type: "object" + properties: + name: + type: "string" + description: "Service name" + ip: + type: "string" + description: "Service IP address for external service only (egress)\n
  • N/A\ + \ for internal services\n" + port: + type: "integer" + description: "Service port number" + externalPort: + type: "integer" + description: "Port used to expose internal service only (ingress)\n
  • Must\ + \ be unique port in range (30000 - 32767)\n
  • N/A for external services\n" + protocol: + type: "string" + description: "Protocol that the application is using (TCP or UDP)" + description: "Mapping of exposed ports to internal or external services" + Event: + type: "object" + properties: + name: + type: "string" + description: "Event name" + type: + type: "string" + description: "Event type" + enum: + - "NETWORK-CHARACTERISTICS-UPDATE" + - "UE-MOBILITY" + - "POAS-IN-RANGE" + - "OTHER" + eventNetworkCharacteristicsUpdate: + $ref: "#/definitions/EventNetworkCharacteristicsUpdate" + eventUeMobility: + $ref: "#/definitions/EventUeMobility" + eventPoasInRange: + $ref: "#/definitions/EventPoasInRange" + eventOther: + $ref: "#/definitions/EventOther" + description: "Event object" + example: + name: "name" + type: "UE-MOBILITY" + eventUeMobility: + ue: "ue" + dest: "dest" + EventNetworkCharacteristicsUpdate: + type: "object" + properties: + elementName: + type: "string" + description: "Name of the network element to be updated" + elementType: + type: "string" + description: "Type of the network element to be updated" + enum: + - "OPERATOR" + - "POA" + - "SCENARIO" + - "ZONE-INTER-EDGE" + - "ZONE-INTER-FOG" + - "ZONE-EDGE-FOG" + latency: + type: "integer" + description: "Latency in ms" + latencyVariation: + type: "integer" + description: "Latency variation in ms" + throughput: + type: "integer" + description: "Throughput limit" + packetLoss: + type: "number" + format: "double" + description: "Packet loss percentage" + description: "Network Characteristics update Event object" + EventUeMobility: + type: "object" + properties: + ue: + type: "string" + description: "UE identifier" + dest: + type: "string" + description: "Destination identifier" + description: "UE Mobility Event object" + example: + ue: "ue" + dest: "dest" + EventPoasInRange: + type: "object" + properties: + ue: + type: "string" + description: "UE identifier" + poasInRange: + type: "array" + items: + type: "string" + description: "POAs visible to UE" + description: "POAs In Range Event object" + example: + ue: "ue" + poasInRange: + - "poa1" + - "poa2" + EventOther: + type: "object" + properties: + event: + type: "string" + description: "Other event string" + description: "Other Event object" + example: + event: "event" +parameters: + Name: + name: "name" + in: "path" + description: "Scenario name" + required: true + type: "string" + Scenario: + in: "body" + name: "scenario" + description: "Scenario to deploy" + required: true + schema: + $ref: "http://localhost:8291/meep-model.yaml#/definitions/Scenario" + x-exportParamName: "Scenario" + EventType: + name: "type" + in: "path" + description: "Event type" + required: true + type: "string" + x-exportParamName: "Type_" + Event: + in: "body" + name: "event" + description: "Event to send to active scenario" + required: true + schema: + $ref: "http://localhost:8291/meep-model.yaml#/definitions/Event" + x-exportParamName: "Event" +responses: + Std200: + description: "OK" + Std201: + description: "Created" + Std202: + description: "Accepted" + Std204: + description: "No content" + Std304: + description: "Not modified" + Std400: + description: "Bad request" + Std401: + description: "Not authorized" + Std403: + description: "Forbidden" + Std404: + description: "Not found" + Std409: + description: "Conflict" + Std416: + description: "Requested range not satisfiable" + Std500: + description: "Internal server error" diff --git a/go-packages/meep-virt-engine-client/api_client.go b/go-packages/meep-virt-engine-client/api_client.go new file mode 100644 index 0000000000000000000000000000000000000000..81735305242b2260e5d2d4cc2426a76438851692 --- /dev/null +++ b/go-packages/meep-virt-engine-client/api_client.go @@ -0,0 +1,426 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "bytes" + "encoding/json" + "encoding/xml" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/url" + "os" + "path/filepath" + "reflect" + "regexp" + "strconv" + "strings" + "time" + "unicode/utf8" + + "golang.org/x/net/context" + "golang.org/x/oauth2" +) + +var ( + jsonCheck = regexp.MustCompile("(?i:[application|text]/json)") + xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)") +) + +// APIClient manages communication with the MEEP Virtualization Engine REST API API v1.0.0 +// In most cases there should be only one, shared, APIClient. +type APIClient struct { + cfg *Configuration + common service // Reuse a single struct instead of allocating one for each service on the heap. + + // API Services + ScenarioDeploymentApi *ScenarioDeploymentApiService + ScenarioExecutionApi *ScenarioExecutionApiService +} + +type service struct { + client *APIClient +} + +// NewAPIClient creates a new API client. Requires a userAgent string describing your application. +// optionally a custom http.Client to allow for advanced features such as caching. +func NewAPIClient(cfg *Configuration) *APIClient { + if cfg.HTTPClient == nil { + cfg.HTTPClient = http.DefaultClient + } + + c := &APIClient{} + c.cfg = cfg + c.common.client = c + + // API Services + c.ScenarioDeploymentApi = (*ScenarioDeploymentApiService)(&c.common) + c.ScenarioExecutionApi = (*ScenarioExecutionApiService)(&c.common) + + return c +} + +func atoi(in string) (int, error) { + return strconv.Atoi(in) +} + +// selectHeaderContentType select a content type from the available list. +func selectHeaderContentType(contentTypes []string) string { + if len(contentTypes) == 0 { + return "" + } + if contains(contentTypes, "application/json") { + return "application/json" + } + return contentTypes[0] // use the first content type specified in 'consumes' +} + +// selectHeaderAccept join all accept types and return +func selectHeaderAccept(accepts []string) string { + if len(accepts) == 0 { + return "" + } + + if contains(accepts, "application/json") { + return "application/json" + } + + return strings.Join(accepts, ",") +} + +// contains is a case insenstive match, finding needle in a haystack +func contains(haystack []string, needle string) bool { + for _, a := range haystack { + if strings.ToLower(a) == strings.ToLower(needle) { + return true + } + } + return false +} + +// Verify optional parameters are of the correct type. +func typeCheckParameter(obj interface{}, expected string, name string) error { + // Make sure there is an object. + if obj == nil { + return nil + } + + // Check the type is as expected. + if reflect.TypeOf(obj).String() != expected { + return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + } + return nil +} + +// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. +func parameterToString(obj interface{}, collectionFormat string) string { + var delimiter string + + switch collectionFormat { + case "pipes": + delimiter = "|" + case "ssv": + delimiter = " " + case "tsv": + delimiter = "\t" + case "csv": + delimiter = "," + } + + if reflect.TypeOf(obj).Kind() == reflect.Slice { + return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") + } + + return fmt.Sprintf("%v", obj) +} + +// callAPI do the request. +func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) { + return c.cfg.HTTPClient.Do(request) +} + +// Change base path to allow switching to mocks +func (c *APIClient) ChangeBasePath(path string) { + c.cfg.BasePath = path +} + +// prepareRequest build the request +func (c *APIClient) prepareRequest( + ctx context.Context, + path string, method string, + postBody interface{}, + headerParams map[string]string, + queryParams url.Values, + formParams url.Values, + fileName string, + fileBytes []byte) (localVarRequest *http.Request, err error) { + + var body *bytes.Buffer + + // Detect postBody type and post. + if postBody != nil { + contentType := headerParams["Content-Type"] + if contentType == "" { + contentType = detectContentType(postBody) + headerParams["Content-Type"] = contentType + } + + body, err = setBody(postBody, contentType) + if err != nil { + return nil, err + } + } + + // add form parameters and file if available. + if len(formParams) > 0 || (len(fileBytes) > 0 && fileName != "") { + if body != nil { + return nil, errors.New("Cannot specify postBody and multipart form at the same time.") + } + body = &bytes.Buffer{} + w := multipart.NewWriter(body) + + for k, v := range formParams { + for _, iv := range v { + if strings.HasPrefix(k, "@") { // file + err = addFile(w, k[1:], iv) + if err != nil { + return nil, err + } + } else { // form value + w.WriteField(k, iv) + } + } + } + if len(fileBytes) > 0 && fileName != "" { + w.Boundary() + //_, fileNm := filepath.Split(fileName) + part, err := w.CreateFormFile("file", filepath.Base(fileName)) + if err != nil { + return nil, err + } + _, err = part.Write(fileBytes) + if err != nil { + return nil, err + } + // Set the Boundary in the Content-Type + headerParams["Content-Type"] = w.FormDataContentType() + } + + // Set Content-Length + headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len()) + w.Close() + } + + // Setup path and query parameters + url, err := url.Parse(path) + if err != nil { + return nil, err + } + + // Adding Query Param + query := url.Query() + for k, v := range queryParams { + for _, iv := range v { + query.Add(k, iv) + } + } + + // Encode the parameters. + url.RawQuery = query.Encode() + + // Generate a new request + if body != nil { + localVarRequest, err = http.NewRequest(method, url.String(), body) + } else { + localVarRequest, err = http.NewRequest(method, url.String(), nil) + } + if err != nil { + return nil, err + } + + // add header parameters, if any + if len(headerParams) > 0 { + headers := http.Header{} + for h, v := range headerParams { + headers.Set(h, v) + } + localVarRequest.Header = headers + } + + // Override request host, if applicable + if c.cfg.Host != "" { + localVarRequest.Host = c.cfg.Host + } + + // Add the user agent to the request. + localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent) + + if ctx != nil { + // add context to the request + localVarRequest = localVarRequest.WithContext(ctx) + + // Walk through any authentication. + + // OAuth2 authentication + if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok { + // We were able to grab an oauth2 token from the context + var latestToken *oauth2.Token + if latestToken, err = tok.Token(); err != nil { + return nil, err + } + + latestToken.SetAuthHeader(localVarRequest) + } + + // Basic HTTP Authentication + if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok { + localVarRequest.SetBasicAuth(auth.UserName, auth.Password) + } + + // AccessToken Authentication + if auth, ok := ctx.Value(ContextAccessToken).(string); ok { + localVarRequest.Header.Add("Authorization", "Bearer "+auth) + } + } + + for header, value := range c.cfg.DefaultHeader { + localVarRequest.Header.Add(header, value) + } + + return localVarRequest, nil +} + +// Add a file to the multipart request +func addFile(w *multipart.Writer, fieldName, path string) error { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + part, err := w.CreateFormFile(fieldName, filepath.Base(path)) + if err != nil { + return err + } + _, err = io.Copy(part, file) + + return err +} + +// Prevent trying to import "fmt" +func reportError(format string, a ...interface{}) error { + return fmt.Errorf(format, a...) +} + +// Set request body from an interface{} +func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) { + if bodyBuf == nil { + bodyBuf = &bytes.Buffer{} + } + + if reader, ok := body.(io.Reader); ok { + _, err = bodyBuf.ReadFrom(reader) + } else if b, ok := body.([]byte); ok { + _, err = bodyBuf.Write(b) + } else if s, ok := body.(string); ok { + _, err = bodyBuf.WriteString(s) + } else if jsonCheck.MatchString(contentType) { + err = json.NewEncoder(bodyBuf).Encode(body) + } else if xmlCheck.MatchString(contentType) { + xml.NewEncoder(bodyBuf).Encode(body) + } + + if err != nil { + return nil, err + } + + if bodyBuf.Len() == 0 { + err = fmt.Errorf("Invalid body type %s\n", contentType) + return nil, err + } + return bodyBuf, nil +} + +// detectContentType method is used to figure out `Request.Body` content type for request header +func detectContentType(body interface{}) string { + contentType := "text/plain; charset=utf-8" + kind := reflect.TypeOf(body).Kind() + + switch kind { + case reflect.Struct, reflect.Map, reflect.Ptr: + contentType = "application/json; charset=utf-8" + case reflect.String: + contentType = "text/plain; charset=utf-8" + default: + if b, ok := body.([]byte); ok { + contentType = http.DetectContentType(b) + } else if kind == reflect.Slice { + contentType = "application/json; charset=utf-8" + } + } + + return contentType +} + +// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go +type cacheControl map[string]string + +func parseCacheControl(headers http.Header) cacheControl { + cc := cacheControl{} + ccHeader := headers.Get("Cache-Control") + for _, part := range strings.Split(ccHeader, ",") { + part = strings.Trim(part, " ") + if part == "" { + continue + } + if strings.ContainsRune(part, '=') { + keyval := strings.Split(part, "=") + cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",") + } else { + cc[part] = "" + } + } + return cc +} + +// CacheExpires helper function to determine remaining time before repeating a request. +func CacheExpires(r *http.Response) time.Time { + // Figure out when the cache expires. + var expires time.Time + now, err := time.Parse(time.RFC1123, r.Header.Get("date")) + if err != nil { + return time.Now() + } + respCacheControl := parseCacheControl(r.Header) + + if maxAge, ok := respCacheControl["max-age"]; ok { + lifetime, err := time.ParseDuration(maxAge + "s") + if err != nil { + expires = now + } + expires = now.Add(lifetime) + } else { + expiresHeader := r.Header.Get("Expires") + if expiresHeader != "" { + expires, err = time.Parse(time.RFC1123, expiresHeader) + if err != nil { + expires = now + } + } + } + return expires +} + +func strlen(s string) int { + return utf8.RuneCountInString(s) +} diff --git a/go-packages/meep-virt-engine-client/api_response.go b/go-packages/meep-virt-engine-client/api_response.go new file mode 100644 index 0000000000000000000000000000000000000000..ab1d3cbb17617261fc5f1629bd93aea1febeb4a8 --- /dev/null +++ b/go-packages/meep-virt-engine-client/api_response.go @@ -0,0 +1,43 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "net/http" +) + +type APIResponse struct { + *http.Response `json:"-"` + Message string `json:"message,omitempty"` + // Operation is the name of the swagger operation. + Operation string `json:"operation,omitempty"` + // RequestURL is the request URL. This value is always available, even if the + // embedded *http.Response is nil. + RequestURL string `json:"url,omitempty"` + // Method is the HTTP method used for the request. This value is always + // available, even if the embedded *http.Response is nil. + Method string `json:"method,omitempty"` + // Payload holds the contents of the response body (which may be nil or empty). + // This is provided here as the raw response.Body() reader will have already + // been drained. + Payload []byte `json:"-"` +} + +func NewAPIResponse(r *http.Response) *APIResponse { + + response := &APIResponse{Response: r} + return response +} + +func NewAPIResponseWithError(errorMessage string) *APIResponse { + + response := &APIResponse{Message: errorMessage} + return response +} diff --git a/go-packages/meep-virt-engine-client/configuration.go b/go-packages/meep-virt-engine-client/configuration.go new file mode 100644 index 0000000000000000000000000000000000000000..41717b2cf206ebc38733e4d5a9947720847ba798 --- /dev/null +++ b/go-packages/meep-virt-engine-client/configuration.go @@ -0,0 +1,72 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "net/http" +) + +// contextKeys are used to identify the type of value in the context. +// Since these are string, it is possible to get a short description of the +// context key for logging and debugging using key.String(). + +type contextKey string + +func (c contextKey) String() string { + return "auth " + string(c) +} + +var ( + // ContextOAuth2 takes a oauth2.TokenSource as authentication for the request. + ContextOAuth2 = contextKey("token") + + // ContextBasicAuth takes BasicAuth as authentication for the request. + ContextBasicAuth = contextKey("basic") + + // ContextAccessToken takes a string oauth2 access token as authentication for the request. + ContextAccessToken = contextKey("accesstoken") + + // ContextAPIKey takes an APIKey as authentication for the request + ContextAPIKey = contextKey("apikey") +) + +// BasicAuth provides basic http authentication to a request passed via context using ContextBasicAuth +type BasicAuth struct { + UserName string `json:"userName,omitempty"` + Password string `json:"password,omitempty"` +} + +// APIKey provides API key based authentication to a request passed via context using ContextAPIKey +type APIKey struct { + Key string + Prefix string +} + +type Configuration struct { + BasePath string `json:"basePath,omitempty"` + Host string `json:"host,omitempty"` + Scheme string `json:"scheme,omitempty"` + DefaultHeader map[string]string `json:"defaultHeader,omitempty"` + UserAgent string `json:"userAgent,omitempty"` + HTTPClient *http.Client +} + +func NewConfiguration() *Configuration { + cfg := &Configuration{ + BasePath: "http://meep-virt-engine/v1", + DefaultHeader: make(map[string]string), + UserAgent: "Swagger-Codegen/1.0.0/go", + } + return cfg +} + +func (c *Configuration) AddDefaultHeader(key string, value string) { + c.DefaultHeader[key] = value +} diff --git a/go-packages/meep-virt-engine-client/deployment.go b/go-packages/meep-virt-engine-client/deployment.go new file mode 100644 index 0000000000000000000000000000000000000000..144cdccfb7b6e3fd2458a017011e9e76c332233d --- /dev/null +++ b/go-packages/meep-virt-engine-client/deployment.go @@ -0,0 +1,28 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Network deployment object +type Deployment struct { + + // Latency in ms between domains + InterDomainLatency int32 `json:"interDomainLatency,omitempty"` + + // Latency variation in ms between domains + InterDomainLatencyVariation int32 `json:"interDomainLatencyVariation,omitempty"` + + // The limit of the traffic supported between domains + InterDomainThroughput int32 `json:"interDomainThroughput,omitempty"` + + // Packet lost (in terms of percentage) between domains + InterDomainPacketLoss float64 `json:"interDomainPacketLoss,omitempty"` + + Domains []Domain `json:"domains,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/docs/Deployment.md b/go-packages/meep-virt-engine-client/docs/Deployment.md new file mode 100644 index 0000000000000000000000000000000000000000..1ffa15070c5d5e35534890dfa800c321d3eb03f3 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/Deployment.md @@ -0,0 +1,14 @@ +# Deployment + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**InterDomainLatency** | **int32** | Latency in ms between domains | [optional] [default to null] +**InterDomainLatencyVariation** | **int32** | Latency variation in ms between domains | [optional] [default to null] +**InterDomainThroughput** | **int32** | The limit of the traffic supported between domains | [optional] [default to null] +**InterDomainPacketLoss** | **float64** | Packet lost (in terms of percentage) between domains | [optional] [default to null] +**Domains** | [**[]Domain**](Domain.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/Domain.md b/go-packages/meep-virt-engine-client/docs/Domain.md new file mode 100644 index 0000000000000000000000000000000000000000..6bdf9f243b0fccc61dfc94a2f9ae92469f809cd9 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/Domain.md @@ -0,0 +1,17 @@ +# Domain + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique domain ID | [optional] [default to null] +**Name** | **string** | Domain name | [optional] [default to null] +**Type_** | **string** | Domain type | [optional] [default to null] +**InterZoneLatency** | **int32** | Latency in ms between zones within domain | [optional] [default to null] +**InterZoneLatencyVariation** | **int32** | Latency variation in ms between zones within domain | [optional] [default to null] +**InterZoneThroughput** | **int32** | The limit of the traffic supported between zones within the domain | [optional] [default to null] +**InterZonePacketLoss** | **float64** | Packet lost (in terms of percentage) between zones within the domain | [optional] [default to null] +**Zones** | [**[]Zone**](Zone.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/Event.md b/go-packages/meep-virt-engine-client/docs/Event.md new file mode 100644 index 0000000000000000000000000000000000000000..33fd474fc8489ffa73eab78be973afea3b3006d9 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/Event.md @@ -0,0 +1,15 @@ +# Event + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Event name | [optional] [default to null] +**Type_** | **string** | Event type | [optional] [default to null] +**EventNetworkCharacteristicsUpdate** | [***EventNetworkCharacteristicsUpdate**](EventNetworkCharacteristicsUpdate.md) | | [optional] [default to null] +**EventUeMobility** | [***EventUeMobility**](EventUeMobility.md) | | [optional] [default to null] +**EventPoasInRange** | [***EventPoasInRange**](EventPoasInRange.md) | | [optional] [default to null] +**EventOther** | [***EventOther**](EventOther.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/EventNetworkCharacteristicsUpdate.md b/go-packages/meep-virt-engine-client/docs/EventNetworkCharacteristicsUpdate.md new file mode 100644 index 0000000000000000000000000000000000000000..29f2be3e32f90351a4462e5851e8f2bec5d08aaf --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/EventNetworkCharacteristicsUpdate.md @@ -0,0 +1,15 @@ +# EventNetworkCharacteristicsUpdate + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**ElementName** | **string** | Name of the network element to be updated | [optional] [default to null] +**ElementType** | **string** | Type of the network element to be updated | [optional] [default to null] +**Latency** | **int32** | Latency in ms | [optional] [default to null] +**LatencyVariation** | **int32** | Latency variation in ms | [optional] [default to null] +**Throughput** | **int32** | Throughput limit | [optional] [default to null] +**PacketLoss** | **float64** | Packet loss percentage | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/EventOther.md b/go-packages/meep-virt-engine-client/docs/EventOther.md new file mode 100644 index 0000000000000000000000000000000000000000..df06c50f6a72108d8cb82cc5f12d78c91565e0ef --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/EventOther.md @@ -0,0 +1,10 @@ +# EventOther + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Event** | **string** | Other event string | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/EventPoasInRange.md b/go-packages/meep-virt-engine-client/docs/EventPoasInRange.md new file mode 100644 index 0000000000000000000000000000000000000000..640a0aec15b81fc6595e5a6cac9f9d3107dc55ee --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/EventPoasInRange.md @@ -0,0 +1,11 @@ +# EventPoasInRange + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Ue** | **string** | UE identifier | [optional] [default to null] +**PoasInRange** | **[]string** | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/EventUeMobility.md b/go-packages/meep-virt-engine-client/docs/EventUeMobility.md new file mode 100644 index 0000000000000000000000000000000000000000..0df09a5791ffc3a7a4829682d84be165e2774f67 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/EventUeMobility.md @@ -0,0 +1,11 @@ +# EventUeMobility + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Ue** | **string** | UE identifier | [optional] [default to null] +**Dest** | **string** | Destination identifier | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/ExternalConfig.md b/go-packages/meep-virt-engine-client/docs/ExternalConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..7a25f4aad9e315036f94794ed3e7f49c14cf451d --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/ExternalConfig.md @@ -0,0 +1,11 @@ +# ExternalConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**IngressServiceMap** | [**[]ServiceMap**](ServiceMap.md) | | [optional] [default to null] +**EgressServiceMap** | [**[]ServiceMap**](ServiceMap.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/NetworkLocation.md b/go-packages/meep-virt-engine-client/docs/NetworkLocation.md new file mode 100644 index 0000000000000000000000000000000000000000..6599c7cd83dc42930bae089da6fb918013addf0d --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/NetworkLocation.md @@ -0,0 +1,17 @@ +# NetworkLocation + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique network location ID | [optional] [default to null] +**Name** | **string** | Network location name | [optional] [default to null] +**Type_** | **string** | Network location type | [optional] [default to null] +**TerminalLinkLatency** | **int32** | Latency in ms for all terminal links within network location | [optional] [default to null] +**TerminalLinkLatencyVariation** | **int32** | Latency variation in ms for all terminal links within network location | [optional] [default to null] +**TerminalLinkThroughput** | **int32** | The limit of the traffic supported for all terminal links within the network location | [optional] [default to null] +**TerminalLinkPacketLoss** | **float64** | Packet lost (in terms of percentage) for all terminal links within the network location | [optional] [default to null] +**PhysicalLocations** | [**[]PhysicalLocation**](PhysicalLocation.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/PhysicalLocation.md b/go-packages/meep-virt-engine-client/docs/PhysicalLocation.md new file mode 100644 index 0000000000000000000000000000000000000000..321343c2471f6bcb457e5deeb43b895526febfb6 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/PhysicalLocation.md @@ -0,0 +1,15 @@ +# PhysicalLocation + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique physical location ID | [optional] [default to null] +**Name** | **string** | Physical location name | [optional] [default to null] +**Type_** | **string** | Physical location type | [optional] [default to null] +**IsExternal** | **bool** | true: Physical location is external to MEEP false: Physical location is internal to MEEP | [optional] [default to null] +**NetworkLocationsInRange** | **[]string** | | [optional] [default to null] +**Processes** | [**[]Process**](Process.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/Process.md b/go-packages/meep-virt-engine-client/docs/Process.md new file mode 100644 index 0000000000000000000000000000000000000000..1e32ea0e21a98b9be00a73c0ec6e4d279f0b92e4 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/Process.md @@ -0,0 +1,23 @@ +# Process + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique process ID | [optional] [default to null] +**Name** | **string** | Process name | [optional] [default to null] +**Type_** | **string** | Process type | [optional] [default to null] +**IsExternal** | **bool** | true: process is external to MEEP false: process is internal to MEEP | [optional] [default to null] +**Image** | **string** | Docker image to deploy inside MEEP | [optional] [default to null] +**Environment** | **string** | Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" | [optional] [default to null] +**CommandArguments** | **string** | Arguments to command executable | [optional] [default to null] +**CommandExe** | **string** | Executable to invoke at container start up | [optional] [default to null] +**ServiceConfig** | [***ServiceConfig**](ServiceConfig.md) | | [optional] [default to null] +**ExternalConfig** | [***ExternalConfig**](ExternalConfig.md) | | [optional] [default to null] +**Status** | **string** | Process status | [optional] [default to null] +**UserChartLocation** | **string** | Chart location for the deployment of the chart provided by the user | [optional] [default to null] +**UserChartAlternateValues** | **string** | Chart values.yaml file location for the deployment of the chart provided by the user | [optional] [default to null] +**UserChartGroup** | **string** | Chart supplemental information related to the group (service) | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/Release.md b/go-packages/meep-virt-engine-client/docs/Release.md new file mode 100644 index 0000000000000000000000000000000000000000..946d7eca0eee2aaef30a4c0f38f9b69c467fb21e --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/Release.md @@ -0,0 +1,11 @@ +# Release + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Release name | [optional] [default to null] +**State** | **string** | Current release state | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/Scenario.md b/go-packages/meep-virt-engine-client/docs/Scenario.md new file mode 100644 index 0000000000000000000000000000000000000000..eb4a453d0fe6ebaddef6f3dfe96279ff643bc8ce --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/Scenario.md @@ -0,0 +1,12 @@ +# Scenario + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Unique scenario name | [optional] [default to null] +**Config** | [***ScenarioConfig**](ScenarioConfig.md) | | [optional] [default to null] +**Deployment** | [***Deployment**](Deployment.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/ScenarioConfig.md b/go-packages/meep-virt-engine-client/docs/ScenarioConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..0f6e1dbeee6174a63026df8c4ffb2e036a371029 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/ScenarioConfig.md @@ -0,0 +1,11 @@ +# ScenarioConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Visualization** | **string** | Visualization configuration | [optional] [default to null] +**Other** | **string** | Other scenario configuration | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/ScenarioDeploymentApi.md b/go-packages/meep-virt-engine-client/docs/ScenarioDeploymentApi.md new file mode 100644 index 0000000000000000000000000000000000000000..15820e75241edf405e5294f208188fa6c311e88a --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/ScenarioDeploymentApi.md @@ -0,0 +1,95 @@ +# \ScenarioDeploymentApi + +All URIs are relative to *http://meep-virt-engine/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**ActivateScenario**](ScenarioDeploymentApi.md#ActivateScenario) | **Post** /scenarios/active | Activate a scenario deployment +[**GetActiveScenario**](ScenarioDeploymentApi.md#GetActiveScenario) | **Get** /scenarios/active/{name} | Retrieve deployed scenarios +[**TerminateScenario**](ScenarioDeploymentApi.md#TerminateScenario) | **Delete** /scenarios/active/{name} | Terminate a scenario deployment + + +# **ActivateScenario** +> ActivateScenario(ctx, scenario) +Activate a scenario deployment + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **scenario** | [**Scenario**](Scenario.md)| Scenario to deploy | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **GetActiveScenario** +> []Release GetActiveScenario(ctx, name) +Retrieve deployed scenarios + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **name** | **string**| Scenario name | + +### Return type + +[**[]Release**](Release.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **TerminateScenario** +> TerminateScenario(ctx, name) +Terminate a scenario deployment + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **name** | **string**| Scenario name | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-virt-engine-client/docs/ScenarioExecutionApi.md b/go-packages/meep-virt-engine-client/docs/ScenarioExecutionApi.md new file mode 100644 index 0000000000000000000000000000000000000000..9b6fd8c6c1707a3b6ec9ca4d09d1e9c01f7f5965 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/ScenarioExecutionApi.md @@ -0,0 +1,38 @@ +# \ScenarioExecutionApi + +All URIs are relative to *http://meep-virt-engine/v1* + +Method | HTTP request | Description +------------- | ------------- | ------------- +[**SendEvent**](ScenarioExecutionApi.md#SendEvent) | **Post** /scenarios/active/events/{type} | Send event to active (deployed) scenario + + +# **SendEvent** +> SendEvent(ctx, type_, event) +Send event to active (deployed) scenario + + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **ctx** | **context.Context** | context for logging, tracing, authentication, etc. + **type_** | **string**| Event type | + **event** | [**Event**](Event.md)| Event to send to active scenario | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/go-packages/meep-virt-engine-client/docs/ServiceConfig.md b/go-packages/meep-virt-engine-client/docs/ServiceConfig.md new file mode 100644 index 0000000000000000000000000000000000000000..6db2202b3aa2fd40150333ca1be13f854a10f7c5 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/ServiceConfig.md @@ -0,0 +1,12 @@ +# ServiceConfig + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Unique service name | [optional] [default to null] +**MeSvcName** | **string** | Multi-Edge service name, if any | [optional] [default to null] +**Ports** | [**[]ServicePort**](ServicePort.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/ServiceMap.md b/go-packages/meep-virt-engine-client/docs/ServiceMap.md new file mode 100644 index 0000000000000000000000000000000000000000..c8ac3a0a957d39752d1af1a792e188d307b9a5d5 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/ServiceMap.md @@ -0,0 +1,14 @@ +# ServiceMap + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | **string** | Service name | [optional] [default to null] +**Ip** | **string** | Service IP address for external service only (egress) <li>N/A for internal services | [optional] [default to null] +**Port** | **int32** | Service port number | [optional] [default to null] +**ExternalPort** | **int32** | Port used to expose internal service only (ingress) <li>Must be unique port in range (30000 - 32767) <li>N/A for external services | [optional] [default to null] +**Protocol** | **string** | Protocol that the application is using (TCP or UDP) | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/ServicePort.md b/go-packages/meep-virt-engine-client/docs/ServicePort.md new file mode 100644 index 0000000000000000000000000000000000000000..6b6c33d586b9c04db79900945f2904fc4eaba286 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/ServicePort.md @@ -0,0 +1,12 @@ +# ServicePort + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Protocol** | **string** | Protocol that the application is using (TCP or UDP) | [optional] [default to null] +**Port** | **int32** | Port number that the service is listening on | [optional] [default to null] +**ExternalPort** | **int32** | External port number on which to expose the application (30000 - 32767) <li>Only one application allowed per external port <li>Scenario builder must configure to prevent conflicts | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/docs/Zone.md b/go-packages/meep-virt-engine-client/docs/Zone.md new file mode 100644 index 0000000000000000000000000000000000000000..5e24dc058eca726e53670004beb9f67eb9588724 --- /dev/null +++ b/go-packages/meep-virt-engine-client/docs/Zone.md @@ -0,0 +1,25 @@ +# Zone + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | **string** | Unique zone ID | [optional] [default to null] +**Name** | **string** | Zone name | [optional] [default to null] +**Type_** | **string** | Zone type | [optional] [default to null] +**InterFogLatency** | **int32** | Latency in ms between fog nodes (or PoAs) within zone | [optional] [default to null] +**InterFogLatencyVariation** | **int32** | Latency variation in ms between fog nodes (or PoAs) within zone | [optional] [default to null] +**InterFogThroughput** | **int32** | The limit of the traffic supported between fog nodes (or PoAs) within the zone | [optional] [default to null] +**InterFogPacketLoss** | **float64** | Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone | [optional] [default to null] +**InterEdgeLatency** | **int32** | Latency in ms between edge nodes within zone | [optional] [default to null] +**InterEdgeLatencyVariation** | **int32** | Latency variation in ms between edge nodes within zone | [optional] [default to null] +**InterEdgeThroughput** | **int32** | The limit of the traffic supported between edge nodes within the zone | [optional] [default to null] +**InterEdgePacketLoss** | **float64** | Packet lost (in terms of percentage) between edge nodes within the zone | [optional] [default to null] +**EdgeFogLatency** | **int32** | Latency in ms between fog nodes (or PoAs) and edge nodes within zone | [optional] [default to null] +**EdgeFogLatencyVariation** | **int32** | Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone | [optional] [default to null] +**EdgeFogThroughput** | **int32** | The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone | [optional] [default to null] +**EdgeFogPacketLoss** | **float64** | Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone | [optional] [default to null] +**NetworkLocations** | [**[]NetworkLocation**](NetworkLocation.md) | | [optional] [default to null] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/go-packages/meep-virt-engine-client/domain.go b/go-packages/meep-virt-engine-client/domain.go new file mode 100644 index 0000000000000000000000000000000000000000..fe8d5b16b7ef4407e0b6eb3d71c1f63ef4f3150d --- /dev/null +++ b/go-packages/meep-virt-engine-client/domain.go @@ -0,0 +1,37 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Operator domain object +type Domain struct { + + // Unique domain ID + Id string `json:"id,omitempty"` + + // Domain name + Name string `json:"name,omitempty"` + + // Domain type + Type_ string `json:"type,omitempty"` + + // Latency in ms between zones within domain + InterZoneLatency int32 `json:"interZoneLatency,omitempty"` + + // Latency variation in ms between zones within domain + InterZoneLatencyVariation int32 `json:"interZoneLatencyVariation,omitempty"` + + // The limit of the traffic supported between zones within the domain + InterZoneThroughput int32 `json:"interZoneThroughput,omitempty"` + + // Packet lost (in terms of percentage) between zones within the domain + InterZonePacketLoss float64 `json:"interZonePacketLoss,omitempty"` + + Zones []Zone `json:"zones,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/event.go b/go-packages/meep-virt-engine-client/event.go new file mode 100644 index 0000000000000000000000000000000000000000..acbed3c658cdfa2b5cee42c8a9d751d377631689 --- /dev/null +++ b/go-packages/meep-virt-engine-client/event.go @@ -0,0 +1,28 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Event object +type Event struct { + + // Event name + Name string `json:"name,omitempty"` + + // Event type + Type_ string `json:"type,omitempty"` + + EventNetworkCharacteristicsUpdate *EventNetworkCharacteristicsUpdate `json:"eventNetworkCharacteristicsUpdate,omitempty"` + + EventUeMobility *EventUeMobility `json:"eventUeMobility,omitempty"` + + EventPoasInRange *EventPoasInRange `json:"eventPoasInRange,omitempty"` + + EventOther *EventOther `json:"eventOther,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/event_network_characteristics_update.go b/go-packages/meep-virt-engine-client/event_network_characteristics_update.go new file mode 100644 index 0000000000000000000000000000000000000000..770d24b8c0036cc80401f4da17191a6308b4dd45 --- /dev/null +++ b/go-packages/meep-virt-engine-client/event_network_characteristics_update.go @@ -0,0 +1,32 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Network Characteristics update Event object +type EventNetworkCharacteristicsUpdate struct { + + // Name of the network element to be updated + ElementName string `json:"elementName,omitempty"` + + // Type of the network element to be updated + ElementType string `json:"elementType,omitempty"` + + // Latency in ms + Latency int32 `json:"latency,omitempty"` + + // Latency variation in ms + LatencyVariation int32 `json:"latencyVariation,omitempty"` + + // Throughput limit + Throughput int32 `json:"throughput,omitempty"` + + // Packet loss percentage + PacketLoss float64 `json:"packetLoss,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/event_other.go b/go-packages/meep-virt-engine-client/event_other.go new file mode 100644 index 0000000000000000000000000000000000000000..7571b0f2519c09eba0f2cb5f0365c41379151049 --- /dev/null +++ b/go-packages/meep-virt-engine-client/event_other.go @@ -0,0 +1,17 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Other Event object +type EventOther struct { + + // Other event string + Event string `json:"event,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/event_poas_in_range.go b/go-packages/meep-virt-engine-client/event_poas_in_range.go new file mode 100644 index 0000000000000000000000000000000000000000..e12061ca1934e7eb7af8e593adf1f73a1a2910ba --- /dev/null +++ b/go-packages/meep-virt-engine-client/event_poas_in_range.go @@ -0,0 +1,19 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// POAs In Range Event object +type EventPoasInRange struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + PoasInRange []string `json:"poasInRange,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/event_ue_mobility.go b/go-packages/meep-virt-engine-client/event_ue_mobility.go new file mode 100644 index 0000000000000000000000000000000000000000..99613c0721bdf96c4202b9527a606a246cdf9feb --- /dev/null +++ b/go-packages/meep-virt-engine-client/event_ue_mobility.go @@ -0,0 +1,20 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// UE Mobility Event object +type EventUeMobility struct { + + // UE identifier + Ue string `json:"ue,omitempty"` + + // Destination identifier + Dest string `json:"dest,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/external_config.go b/go-packages/meep-virt-engine-client/external_config.go new file mode 100644 index 0000000000000000000000000000000000000000..3d7213ba95ad985179944544947e725418c87529 --- /dev/null +++ b/go-packages/meep-virt-engine-client/external_config.go @@ -0,0 +1,17 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// External Process configuration. NOTE: Only valid if 'isExternal' is set. +type ExternalConfig struct { + IngressServiceMap []ServiceMap `json:"ingressServiceMap,omitempty"` + + EgressServiceMap []ServiceMap `json:"egressServiceMap,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/git_push.sh b/go-packages/meep-virt-engine-client/git_push.sh new file mode 100644 index 0000000000000000000000000000000000000000..ae01b182ae9eb047d0999a496b060e62d7b01e5c --- /dev/null +++ b/go-packages/meep-virt-engine-client/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/go-packages/meep-virt-engine-client/go.mod b/go-packages/meep-virt-engine-client/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..00583f54eb9d13d5ff8d4e0d199b43f11e2e1567 --- /dev/null +++ b/go-packages/meep-virt-engine-client/go.mod @@ -0,0 +1,8 @@ +module github.com/InterDigitalInc/AdvantEDGE/go-packages/meep-virt-engine-client + +go 1.12 + +require ( + golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 + golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a +) diff --git a/go-packages/meep-virt-engine-client/go.sum b/go-packages/meep-virt-engine-client/go.sum new file mode 100644 index 0000000000000000000000000000000000000000..9573cb6290c07b96a28ae39d1fef1f0d0c08be06 --- /dev/null +++ b/go-packages/meep-virt-engine-client/go.sum @@ -0,0 +1,13 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679 h1:tzVWzOrXxwAwdSCMrf+mbNrZFxwS0+HLP4m2qxtfdhk= +golang.org/x/net v0.0.0-20190415100556-4a65cf94b679/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA= +golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= diff --git a/go-packages/meep-virt-engine-client/network_location.go b/go-packages/meep-virt-engine-client/network_location.go new file mode 100644 index 0000000000000000000000000000000000000000..ced5f6168cc64f33888a1132b308277ef8172e10 --- /dev/null +++ b/go-packages/meep-virt-engine-client/network_location.go @@ -0,0 +1,37 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Logical network location object +type NetworkLocation struct { + + // Unique network location ID + Id string `json:"id,omitempty"` + + // Network location name + Name string `json:"name,omitempty"` + + // Network location type + Type_ string `json:"type,omitempty"` + + // Latency in ms for all terminal links within network location + TerminalLinkLatency int32 `json:"terminalLinkLatency,omitempty"` + + // Latency variation in ms for all terminal links within network location + TerminalLinkLatencyVariation int32 `json:"terminalLinkLatencyVariation,omitempty"` + + // The limit of the traffic supported for all terminal links within the network location + TerminalLinkThroughput int32 `json:"terminalLinkThroughput,omitempty"` + + // Packet lost (in terms of percentage) for all terminal links within the network location + TerminalLinkPacketLoss float64 `json:"terminalLinkPacketLoss,omitempty"` + + PhysicalLocations []PhysicalLocation `json:"physicalLocations,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/physical_location.go b/go-packages/meep-virt-engine-client/physical_location.go new file mode 100644 index 0000000000000000000000000000000000000000..a7c5909755167b9d20a71db5c3568ef3a4661aec --- /dev/null +++ b/go-packages/meep-virt-engine-client/physical_location.go @@ -0,0 +1,30 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Physical location object +type PhysicalLocation struct { + + // Unique physical location ID + Id string `json:"id,omitempty"` + + // Physical location name + Name string `json:"name,omitempty"` + + // Physical location type + Type_ string `json:"type,omitempty"` + + // true: Physical location is external to MEEP false: Physical location is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + NetworkLocationsInRange []string `json:"networkLocationsInRange,omitempty"` + + Processes []Process `json:"processes,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/process.go b/go-packages/meep-virt-engine-client/process.go new file mode 100644 index 0000000000000000000000000000000000000000..fed2ec86bd742e48aba02df9bace8735a3b3f6b4 --- /dev/null +++ b/go-packages/meep-virt-engine-client/process.go @@ -0,0 +1,54 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Application or service object +type Process struct { + + // Unique process ID + Id string `json:"id,omitempty"` + + // Process name + Name string `json:"name,omitempty"` + + // Process type + Type_ string `json:"type,omitempty"` + + // true: process is external to MEEP false: process is internal to MEEP + IsExternal bool `json:"isExternal,omitempty"` + + // Docker image to deploy inside MEEP + Image string `json:"image,omitempty"` + + // Environment variables using the format NAME=\"value\",NAME=\"value\",NAME=\"value\" + Environment string `json:"environment,omitempty"` + + // Arguments to command executable + CommandArguments string `json:"commandArguments,omitempty"` + + // Executable to invoke at container start up + CommandExe string `json:"commandExe,omitempty"` + + ServiceConfig *ServiceConfig `json:"serviceConfig,omitempty"` + + ExternalConfig *ExternalConfig `json:"externalConfig,omitempty"` + + // Process status + Status string `json:"status,omitempty"` + + // Chart location for the deployment of the chart provided by the user + UserChartLocation string `json:"userChartLocation,omitempty"` + + // Chart values.yaml file location for the deployment of the chart provided by the user + UserChartAlternateValues string `json:"userChartAlternateValues,omitempty"` + + // Chart supplemental information related to the group (service) + UserChartGroup string `json:"userChartGroup,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/release.go b/go-packages/meep-virt-engine-client/release.go new file mode 100644 index 0000000000000000000000000000000000000000..d1e2ba86c938cf04140f6280978ad2267f5fd511 --- /dev/null +++ b/go-packages/meep-virt-engine-client/release.go @@ -0,0 +1,19 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +type Release struct { + + // Release name + Name string `json:"name,omitempty"` + + // Current release state + State string `json:"state,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/scenario.go b/go-packages/meep-virt-engine-client/scenario.go new file mode 100644 index 0000000000000000000000000000000000000000..295cd7436c70cb883b7a26520d828f4cfc81d31c --- /dev/null +++ b/go-packages/meep-virt-engine-client/scenario.go @@ -0,0 +1,21 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Scenario object +type Scenario struct { + + // Unique scenario name + Name string `json:"name,omitempty"` + + Config *ScenarioConfig `json:"config,omitempty"` + + Deployment *Deployment `json:"deployment,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/scenario_config.go b/go-packages/meep-virt-engine-client/scenario_config.go new file mode 100644 index 0000000000000000000000000000000000000000..bb4ef9d61209e86969d85a46b50a1bafc0b734fb --- /dev/null +++ b/go-packages/meep-virt-engine-client/scenario_config.go @@ -0,0 +1,20 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Scenario configuration +type ScenarioConfig struct { + + // Visualization configuration + Visualization string `json:"visualization,omitempty"` + + // Other scenario configuration + Other string `json:"other,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/scenario_deployment_api.go b/go-packages/meep-virt-engine-client/scenario_deployment_api.go new file mode 100644 index 0000000000000000000000000000000000000000..860b19173716dd69f673d7c312c6bd0c2978db56 --- /dev/null +++ b/go-packages/meep-virt-engine-client/scenario_deployment_api.go @@ -0,0 +1,208 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type ScenarioDeploymentApiService service + +/* ScenarioDeploymentApiService Activate a scenario deployment + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param scenario Scenario to deploy +@return */ +func (a *ScenarioDeploymentApiService) ActivateScenario(ctx context.Context, scenario Scenario) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios/active" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &scenario + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} + +/* ScenarioDeploymentApiService Retrieve deployed scenarios + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param name Scenario name +@return []Release*/ +func (a *ScenarioDeploymentApiService) GetActiveScenario(ctx context.Context, name string) ([]Release, *http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Get") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + successPayload []Release + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios/active/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return successPayload, nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return successPayload, localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return successPayload, localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + if err = json.NewDecoder(localVarHttpResponse.Body).Decode(&successPayload); err != nil { + return successPayload, localVarHttpResponse, err + } + + return successPayload, localVarHttpResponse, err +} + +/* ScenarioDeploymentApiService Terminate a scenario deployment + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param name Scenario name +@return */ +func (a *ScenarioDeploymentApiService) TerminateScenario(ctx context.Context, name string) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Delete") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios/active/{name}" + localVarPath = strings.Replace(localVarPath, "{"+"name"+"}", fmt.Sprintf("%v", name), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} diff --git a/go-packages/meep-virt-engine-client/scenario_execution_api.go b/go-packages/meep-virt-engine-client/scenario_execution_api.go new file mode 100644 index 0000000000000000000000000000000000000000..71290160bc9b0abd7b1e0ec0f9fe2c50f4bae0a8 --- /dev/null +++ b/go-packages/meep-virt-engine-client/scenario_execution_api.go @@ -0,0 +1,88 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "golang.org/x/net/context" +) + +// Linger please +var ( + _ context.Context +) + +type ScenarioExecutionApiService service + +/* ScenarioExecutionApiService Send event to active (deployed) scenario + +* @param ctx context.Context for authentication, logging, tracing, etc. +@param type_ Event type +@param event Event to send to active scenario +@return */ +func (a *ScenarioExecutionApiService) SendEvent(ctx context.Context, type_ string, event Event) (*http.Response, error) { + var ( + localVarHttpMethod = strings.ToUpper("Post") + localVarPostBody interface{} + localVarFileName string + localVarFileBytes []byte + ) + + // create path and map variables + localVarPath := a.client.cfg.BasePath + "/scenarios/active/events/{type}" + localVarPath = strings.Replace(localVarPath, "{"+"type"+"}", fmt.Sprintf("%v", type_), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHttpContentTypes := []string{} + + // set Content-Type header + localVarHttpContentType := selectHeaderContentType(localVarHttpContentTypes) + if localVarHttpContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHttpContentType + } + + // to determine the Accept header + localVarHttpHeaderAccepts := []string{ + "application/json", + } + + // set Accept header + localVarHttpHeaderAccept := selectHeaderAccept(localVarHttpHeaderAccepts) + if localVarHttpHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHttpHeaderAccept + } + // body params + localVarPostBody = &event + r, err := a.client.prepareRequest(ctx, localVarPath, localVarHttpMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, localVarFileName, localVarFileBytes) + if err != nil { + return nil, err + } + + localVarHttpResponse, err := a.client.callAPI(r) + if err != nil || localVarHttpResponse == nil { + return localVarHttpResponse, err + } + defer localVarHttpResponse.Body.Close() + if localVarHttpResponse.StatusCode >= 300 { + bodyBytes, _ := ioutil.ReadAll(localVarHttpResponse.Body) + return localVarHttpResponse, reportError("Status: %v, Body: %s", localVarHttpResponse.Status, bodyBytes) + } + + return localVarHttpResponse, err +} diff --git a/go-packages/meep-virt-engine-client/service_config.go b/go-packages/meep-virt-engine-client/service_config.go new file mode 100644 index 0000000000000000000000000000000000000000..95ae83fb5a996db1e7c387988a596b58d4cd0824 --- /dev/null +++ b/go-packages/meep-virt-engine-client/service_config.go @@ -0,0 +1,22 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Service object +type ServiceConfig struct { + + // Unique service name + Name string `json:"name,omitempty"` + + // Multi-Edge service name, if any + MeSvcName string `json:"meSvcName,omitempty"` + + Ports []ServicePort `json:"ports,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/service_map.go b/go-packages/meep-virt-engine-client/service_map.go new file mode 100644 index 0000000000000000000000000000000000000000..d15db1fb675d37f5ad765f00c664b72fa1848e54 --- /dev/null +++ b/go-packages/meep-virt-engine-client/service_map.go @@ -0,0 +1,29 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Mapping of exposed ports to internal or external services +type ServiceMap struct { + + // Service name + Name string `json:"name,omitempty"` + + // Service IP address for external service only (egress)
  • N/A for internal services + Ip string `json:"ip,omitempty"` + + // Service port number + Port int32 `json:"port,omitempty"` + + // Port used to expose internal service only (ingress)
  • Must be unique port in range (30000 - 32767)
  • N/A for external services + ExternalPort int32 `json:"externalPort,omitempty"` + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/service_port.go b/go-packages/meep-virt-engine-client/service_port.go new file mode 100644 index 0000000000000000000000000000000000000000..83383fd1958fd0bcd4cec6c49b3386c628855df5 --- /dev/null +++ b/go-packages/meep-virt-engine-client/service_port.go @@ -0,0 +1,23 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Service port object +type ServicePort struct { + + // Protocol that the application is using (TCP or UDP) + Protocol string `json:"protocol,omitempty"` + + // Port number that the service is listening on + Port int32 `json:"port,omitempty"` + + // External port number on which to expose the application (30000 - 32767)
  • Only one application allowed per external port
  • Scenario builder must configure to prevent conflicts + ExternalPort int32 `json:"externalPort,omitempty"` +} diff --git a/go-packages/meep-virt-engine-client/zone.go b/go-packages/meep-virt-engine-client/zone.go new file mode 100644 index 0000000000000000000000000000000000000000..8a94287c727ca53edd4c4da9de77091fb1e66c10 --- /dev/null +++ b/go-packages/meep-virt-engine-client/zone.go @@ -0,0 +1,61 @@ +/* + * MEEP Virtualization Engine REST API + * + * Copyright (c) 2019 InterDigital Communications, Inc. All rights reserved. The information provided herein is the proprietary and confidential information of InterDigital Communications, Inc. + * + * API version: 1.0.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package client + +// Logical zone (MEC network) object +type Zone struct { + + // Unique zone ID + Id string `json:"id,omitempty"` + + // Zone name + Name string `json:"name,omitempty"` + + // Zone type + Type_ string `json:"type,omitempty"` + + // Latency in ms between fog nodes (or PoAs) within zone + InterFogLatency int32 `json:"interFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) within zone + InterFogLatencyVariation int32 `json:"interFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) within the zone + InterFogThroughput int32 `json:"interFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone + InterFogPacketLoss float64 `json:"interFogPacketLoss,omitempty"` + + // Latency in ms between edge nodes within zone + InterEdgeLatency int32 `json:"interEdgeLatency,omitempty"` + + // Latency variation in ms between edge nodes within zone + InterEdgeLatencyVariation int32 `json:"interEdgeLatencyVariation,omitempty"` + + // The limit of the traffic supported between edge nodes within the zone + InterEdgeThroughput int32 `json:"interEdgeThroughput,omitempty"` + + // Packet lost (in terms of percentage) between edge nodes within the zone + InterEdgePacketLoss float64 `json:"interEdgePacketLoss,omitempty"` + + // Latency in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatency int32 `json:"edgeFogLatency,omitempty"` + + // Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone + EdgeFogLatencyVariation int32 `json:"edgeFogLatencyVariation,omitempty"` + + // The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogThroughput int32 `json:"edgeFogThroughput,omitempty"` + + // Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone + EdgeFogPacketLoss float64 `json:"edgeFogPacketLoss,omitempty"` + + NetworkLocations []NetworkLocation `json:"networkLocations,omitempty"` +} diff --git a/interfaces/README.md b/interfaces/README.md deleted file mode 100644 index a4b82c2535b249ac3b338bb13cb2b03fb9e60483..0000000000000000000000000000000000000000 --- a/interfaces/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# AdvantEDGE Interfaces -This folder contains AdvantEDGE Interfaces diff --git a/interfaces/meep-mg-manager-model.yaml b/interfaces/meep-mg-manager-model.yaml deleted file mode 100644 index 327abcead9b8ad5e67e4adfeaba3459ffa9d28a3..0000000000000000000000000000000000000000 --- a/interfaces/meep-mg-manager-model.yaml +++ /dev/null @@ -1,119 +0,0 @@ -swagger: '2.0' -info: - description: MEEP Mobility Group Manager Model - version: 1.0.0 - title: EEP Mobility Group Manager Model -definitions: - MobilityGroup: - type: object - properties: - name: - type: string - description: Mobility Group name - stateTransferMode: - type: string - description: State Transfer mode - enum: - - STATE-DIRECT - - STATE-MANAGED - - INSTANCE-DIRECT - - INSTANCE-MANAGED - - NONE - stateTransferTrigger: - type: string - description: State Transfer trigger - enum: - - NET-LOC-IN-RANGE - - NET-LOC-CHANGE - - GPS-PROXIMITY - - NONE - sessionTransferMode: - type: string - description: Session Transfer mode - enum: - - GRACEFUL - - FORCED - loadBalancingAlgorithm: - type: string - description: Load Balancing Algorithm - enum: - - HOP-COUNT - - LATENCY - - DISTANCE - description: Mobility Group - MobilityGroupApp: - type: object - properties: - id: - type: string - description: Mobility Group Application Identifier - url: - type: string - description: Event handler url - description: Mobility Group Application instance - MobilityGroupAppState: - type: object - properties: - ueId: - type: string - description: Mobility Group UE Identifier - ueState: - type: string - description: Mobility Group Application State for provided UE - description: Mobility Group Application State - MobilityGroupUE: - type: object - properties: - id: - type: string - description: Mobility Group UE Identifier - description: Mobility Group UE instance - MobilityGroupEvent: - type: object - properties: - name: - type: string - description: Mobility Group event name - type: - type: string - description: Mobility Group event type - enum: - - STATE-UPDATE - - STATE-TRANSFER-START - - STATE-TRANSFER-COMPLETE - - STATE-TRANSFER-CANCEL - ueId: - type: string - description: Mobility Group UE identifier - appState: - $ref: '#/definitions/MobilityGroupAppState' - description: Event object - MobilityGroupServiceMap: - type: object - properties: - mgSvcName: - type: string - description: Mobility group service name - lbSvcName: - type: string - description: Load balanced service instance name - description: Mobility group service mapping - NetworkElementList: - type: object - properties: - networkElements: - type: array - items: - $ref: '#/definitions/NetworkElement' - description: List of network element - NetworkElement: - type: object - properties: - name: - type: string - description: Network element name - serviceMaps: - type: array - items: - $ref: '#/definitions/MobilityGroupServiceMap' - description: Network element service mappings diff --git a/interfaces/meep-model.yaml b/interfaces/meep-model.yaml deleted file mode 100644 index 26420d5a617517070c86d8ceb98836bb376c8f7b..0000000000000000000000000000000000000000 --- a/interfaces/meep-model.yaml +++ /dev/null @@ -1,2082 +0,0 @@ -swagger: '2.0' -info: - description: MEEP Controller REST API - version: 1.0.0 - title: MEEP Controller REST API -definitions: - ClientServiceMap: - type: object - properties: - client: - type: string - description: Unique external client identifier - serviceMap: - type: array - items: - $ref: '#/definitions/ServiceMap' - description: Client-specific list of mappings of exposed port to internal service - Deployment: - type: object - properties: - interDomainLatency: - type: integer - description: Latency in ms between domains - interDomainLatencyVariation: - type: integer - description: Latency variation in ms between domains - interDomainThroughput: - type: integer - description: The limit of the traffic supported between domains - interDomainPacketLoss: - type: number - format: double - description: Packet lost (in terms of percentage) between domains - domains: - type: array - items: - $ref: '#/definitions/Domain' - description: Network deployment object - example: - domains: - - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - Domain: - type: object - properties: - id: - type: string - description: Unique domain ID - name: - type: string - description: Domain name - type: - type: string - description: Domain type - enum: - - OPERATOR - - PUBLIC - interZoneLatency: - type: integer - description: Latency in ms between zones within domain - interZoneLatencyVariation: - type: integer - description: Latency variation in ms between zones within domain - interZoneThroughput: - type: integer - description: The limit of the traffic supported between zones within the domain - interZonePacketLoss: - type: number - format: double - description: Packet lost (in terms of percentage) between zones within the domain - zones: - type: array - items: - $ref: '#/definitions/Zone' - description: Operator domain object - example: - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - Event: - type: object - properties: - name: - type: string - description: Event name - type: - type: string - description: Event type - enum: - - NETWORK-CHARACTERISTICS-UPDATE - - UE-MOBILITY - - POAS-IN-RANGE - - OTHER - eventNetworkCharacteristicsUpdate: - $ref: '#/definitions/EventNetworkCharacteristicsUpdate' - eventUeMobility: - $ref: '#/definitions/EventUeMobility' - eventPoasInRange: - $ref: '#/definitions/EventPoasInRange' - eventOther: - $ref: '#/definitions/EventOther' - description: Event object - example: - name: name - type: UE-MOBILITY - eventUeMobility: - ue: ue - dest: dest - EventList: - type: object - properties: - events: - type: array - items: - $ref: '#/definitions/Event' - description: Event list object - example: - events: - - name: name - type: NETWORK-CHARACTERISTICS-UPDATE - eventNetworkCharacteristicsUpdate: - elementName: poa1 - elementType: poa - terminalLinkLatency: 10 - terminalLinkLatencyVariation: 1 - terminalLinkThroughput: 2000 - terminalLinkPacketLoss: 1 - - name: name - type: UE-MOBILITY - eventUeMobility: - ue: ue - dest: dest - - name: name - type: OTHER - eventOther: - event: event - EventNetworkCharacteristicsUpdate: - type: object - properties: - elementName: - type: string - description: Name of the network element to be updated - elementType: - type: string - description: Type of the network element to be updated - enum: - - OPERATOR - - POA - - SCENARIO - - ZONE-INTER-EDGE - - ZONE-INTER-FOG - - ZONE-EDGE-FOG - latency: - type: integer - description: Latency in ms - latencyVariation: - type: integer - description: Latency variation in ms - throughput: - type: integer - description: Throughput limit - packetLoss: - type: number - format: double - description: Packet loss percentage - description: Network Characteristics update Event object - EventPoasInRange: - type: object - properties: - ue: - type: string - description: UE identifier - poasInRange: - type: array - items: - type: string - description: POAs visible to UE - description: POAs In Range Event object - example: - ue: ue - poasInRange: - - poa1 - - poa2 - EventUeMobility: - type: object - properties: - ue: - type: string - description: UE identifier - dest: - type: string - description: Destination identifier - description: UE Mobility Event object - example: - ue: ue - dest: dest - EventOther: - type: object - properties: - event: - type: string - description: Other event string - description: Other Event object - example: - event: event - ExternalConfig: - type: object - properties: - ingressServiceMap: - type: array - items: - $ref: '#/definitions/ServiceMap' - egressServiceMap: - type: array - items: - $ref: '#/definitions/ServiceMap' - description: |- - External Process configuration. - NOTE: Only valid if 'isExternal' is set. - NetworkLocation: - type: object - properties: - id: - type: string - description: Unique network location ID - name: - type: string - description: Network location name - type: - type: string - description: Network location type - enum: - - POA - - DEFAULT - terminalLinkLatency: - type: integer - description: Latency in ms for all terminal links within network location - terminalLinkLatencyVariation: - type: integer - description: Latency variation in ms for all terminal links within network location - terminalLinkThroughput: - type: integer - description: The limit of the traffic supported for all terminal links within the network location - terminalLinkPacketLoss: - type: number - format: double - description: Packet lost (in terms of percentage) for all terminal links within the network location - physicalLocations: - type: array - items: - $ref: '#/definitions/PhysicalLocation' - description: Logical network location object - example: - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - PhysicalLocation: - type: object - properties: - id: - type: string - description: Unique physical location ID - name: - type: string - description: Physical location name - type: - type: string - description: Physical location type - enum: - - UE - - FOG - - EDGE - - CN - - DC - isExternal: - type: boolean - description: |- - true: Physical location is external to MEEP - false: Physical location is internal to MEEP - networkLocationsInRange: - type: array - items: - type: string - description: Names of network locations within range of physical location - processes: - type: array - items: - $ref: '#/definitions/Process' - description: Physical location object - example: - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - PodStatus: - type: object - properties: - name: - type: string - description: Pod name - namespace: - type: string - description: Pod namespace - meepApp: - type: string - description: Pod process name - meepOrigin: - type: string - description: 'Pod origin(core, scenario)' - meepScenario: - type: string - description: Pod scenario name - phase: - type: string - description: Pod phase - podInitialized: - type: string - description: Pod initialized (true/false) - podReady: - type: string - description: Pod ready (true/false) - podScheduled: - type: string - description: Pod scheduled (true/false) - podUnschedulable: - type: string - description: Pod unschedulable (true/false) - podConditionError: - type: string - description: Pod error message - containerStatusesMsg: - type: string - description: Failed container error message - nbOkContainers: - type: string - description: Number of containers that are up - nbTotalContainers: - type: string - description: Number of total containers in the pod - nbPodRestart: - type: string - description: Number of container failures leading to pod restarts - logicalState: - type: string - description: State that is mapping the kubernetes api state - startTime: - type: string - description: Pod creation time - example: - podStatus: - - podName: mypod - namespace: default - meepApp: pod1 - meepOrigin: scenario - meepScenario: myScenario - phase: Running - podInitialized: 'True' - podReady: 'False' - podScheduled: 'True' - podUnschedulable: 'False' - podConditionError: 'containers with unready status: [myshel]' - containerStatusesMsg: null - nbOkContainers: '0' - nbTotalContainers: '1' - nbPodRestart: '15005' - startTime: '2018-09-10 14:24:00 +0000 UTC' - PodsStatus: - type: object - properties: - podStatus: - type: array - items: - $ref: '#/definitions/PodStatus' - description: List of all pods status - example: - podStatus: - - podName: mypod - namespace: default - meepApp: pod1 - meepOrigin: scenario - meepScenario: myScenario - phase: Running - podInitialized: 'True' - podReady: 'False' - podScheduled: 'True' - podUnschedulable: 'False' - podConditionError: 'containers with unready status: [myshel]' - containerStatusesMsg: null - nbOkContainers: '0' - nbTotalContainers: '1' - nbPodRestart: '15005' - logicalState: "Terminating" - startTime: '2018-09-10 14:24:00 +0000 UTC' - - podName: mypod2 - namespace: default - meepApp: pod1 - meepOrigin: scenario - meepScenario: myScenario - phase: Running - podInitialized: 'True' - podReady: 'False' - podScheduled: 'True' - podUnschedulable: 'False' - podConditionError: 'containers with unready status: [myshel]' - containerStatusesMsg: null - nbOkContainers: '0' - nbTotalContainers: '1' - nbPodRestart: '1' - logicalState: "Running" - startTime: '2018-09-10 14:25:00 +0000 UTC' - Process: - type: object - properties: - id: - type: string - description: Unique process ID - name: - type: string - description: Process name - type: - type: string - description: Process type - enum: - - UE-APP - - EDGE-APP - - MEC-SVC - - CLOUD-APP - isExternal: - type: boolean - description: |- - true: process is external to MEEP - false: process is internal to MEEP - image: - type: string - description: Docker image to deploy inside MEEP - environment: - type: string - description: 'Environment variables using the format NAME="value",NAME="value",NAME="value"' - commandArguments: - type: string - description: Arguments to command executable - commandExe: - type: string - description: Executable to invoke at container start up - serviceConfig: - $ref: '#/definitions/ServiceConfig' - externalConfig: - $ref: '#/definitions/ExternalConfig' - status: - type: string - description: Process status - userChartLocation: - type: string - description: Chart location for the deployment of the chart provided by the user - userChartAlternateValues: - type: string - description: Chart values.yaml file location for the deployment of the chart provided by the user - userChartGroup: - type: string - description: Chart supplemental information related to the group (service) - description: Application or service object - Release: - type: object - properties: - name: - type: string - description: Release name - state: - type: string - description: Current release state - example: - name: name - state: state - Scenario: - type: object - properties: - name: - type: string - description: Unique scenario name - config: - $ref: '#/definitions/ScenarioConfig' - deployment: - $ref: '#/definitions/Deployment' - description: Scenario object - example: - name: name - config: - visualization: visualization - other: other - deployment: - domains: - - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - ScenarioConfig: - type: object - properties: - visualization: - type: string - description: Visualization configuration - other: - type: string - description: Other scenario configuration - description: Scenario configuration - example: - visualization: visualization - other: other - ScenarioList: - type: object - properties: - scenarios: - type: array - items: - $ref: '#/definitions/Scenario' - description: Scenario list object - example: - scenarios: - - name: name - config: - visualization: visualization - other: other - deployment: - domains: - - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - config: - visualization: visualization - other: other - deployment: - domains: - - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: OPERATOR - zones: - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - ServiceConfig: - type: object - properties: - name: - type: string - description: Unique service name - meSvcName: - type: string - description: 'Multi-Edge service name, if any' - ports: - type: array - items: - $ref: '#/definitions/ServicePort' - description: Service object - ServiceMap: - type: object - properties: - name: - type: string - description: Service name - ip: - type: string - description: | - Service IP address for external service only (egress) -
  • N/A for internal services - port: - type: integer - description: Service port number - externalPort: - type: integer - description: | - Port used to expose internal service only (ingress) -
  • Must be unique port in range (30000 - 32767) -
  • N/A for external services - protocol: - type: string - description: Protocol that the application is using (TCP or UDP) - description: Mapping of exposed ports to internal or external services - ServicePort: - type: object - properties: - protocol: - type: string - description: Protocol that the application is using (TCP or UDP) - port: - type: integer - description: Port number that the service is listening on - externalPort: - type: integer - description: | - External port number on which to expose the application (30000 - 32767)
  • Only one application allowed per external port
  • Scenario builder must configure to prevent conflicts - description: Service port object - Settings: - type: string - description: MEEP settings - Zone: - type: object - properties: - id: - type: string - description: Unique zone ID - name: - type: string - description: Zone name - type: - type: string - description: Zone type - enum: - - ZONE - - COMMON - interFogLatency: - type: integer - description: Latency in ms between fog nodes (or PoAs) within zone - interFogLatencyVariation: - type: integer - description: Latency variation in ms between fog nodes (or PoAs) within zone - interFogThroughput: - type: integer - description: The limit of the traffic supported between fog nodes (or PoAs) within the zone - interFogPacketLoss: - type: number - format: double - description: Packet lost (in terms of percentage) between fog nodes (or PoAs) within the zone - interEdgeLatency: - type: integer - description: Latency in ms between edge nodes within zone - interEdgeLatencyVariation: - type: integer - description: Latency variation in ms between edge nodes within zone - interEdgeThroughput: - type: integer - description: The limit of the traffic supported between edge nodes within the zone - interEdgePacketLoss: - type: number - format: double - description: Packet lost (in terms of percentage) between edge nodes within the zone - edgeFogLatency: - type: integer - description: Latency in ms between fog nodes (or PoAs) and edge nodes within zone - edgeFogLatencyVariation: - type: integer - description: Latency variation in ms between fog nodes (or PoAs) and edge nodes within zone - edgeFogThroughput: - type: integer - description: The limit of the traffic supported between fog nodes (or PoAs) and edge nodes within the zone - edgeFogPacketLoss: - type: number - format: double - description: Packet lost (in terms of percentage) between fog nodes (or PoAs) and edge nodes within the zone - networkLocations: - type: array - items: - $ref: '#/definitions/NetworkLocation' - description: Logical zone (MEC network) object - example: - name: name - id: id - type: ZONE - networkLocations: - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA - - physicalLocations: - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - - processes: - - isExternal: true - name: name - id: id - type: UE-APP - status: status - - isExternal: true - name: name - id: id - type: UE-APP - status: status - isExternal: true - name: name - id: id - type: UE - name: name - id: id - type: POA diff --git a/js-apps/meep-frontend/.babelrc b/js-apps/meep-frontend/.babelrc new file mode 100644 index 0000000000000000000000000000000000000000..ddd8fbbad4c474aa699147d9bc41678c216c6bce --- /dev/null +++ b/js-apps/meep-frontend/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@babel/preset-env", "@babel/preset-react"] +} + diff --git a/js-apps/meep-frontend/.eslintrc.js b/js-apps/meep-frontend/.eslintrc.js new file mode 100644 index 0000000000000000000000000000000000000000..6a6a2f60c134cef7db35fb3f76da80725f56478e --- /dev/null +++ b/js-apps/meep-frontend/.eslintrc.js @@ -0,0 +1,73 @@ +module.exports = { + 'env': { + 'browser': true, + 'es6': true + }, + 'extends': 'eslint:recommended', + 'globals': { + 'Atomics': 'readonly', + 'SharedArrayBuffer': 'readonly' + }, + 'parserOptions': { + 'ecmaFeatures': { + 'jsx': true + }, + 'ecmaVersion': 2018, + 'sourceType': 'module' + }, + 'plugins': [ + 'react' + ], + "settings": { + "react": { + "createClass": "createReactClass", // Regex for Component Factory to use, + // default to "createReactClass" + "pragma": "React", // Pragma to use, default to "React" + "version": "15.0", // React version, default to the latest React stable release + "flowVersion": "0.53" // Flow version + }, + "propWrapperFunctions": [ + // The names of any function used to wrap propTypes, e.g. `forbidExtraProps`. If this isn't set, any propTypes wrapped in a function will be skipped. + "forbidExtraProps", + {"property": "freeze", "object": "Object"}, + {"property": "myFavoriteWrapper"} + ] + }, + 'rules': { + 'indent': [ + 'error', + 2 + ], + 'linebreak-style': [ + 'error', + 'unix' + ], + 'curly': [ + "error", + "all" + ], + 'comma-dangle': [ + "error", + "never" + ], + 'eqeqeq': [ + "error", + "always" + ], + 'quotes': [ + 'error', + 'single' + ], + 'semi': [ + 'error', + 'always' + ], + 'extends': [ + 'eslint:recommended', + 'plugin:react/recommended' + ], + "react/jsx-uses-vars": 2, + "react/jsx-uses-react": "error", + // "react/jsx-uses-vars": "error", + } +}; \ No newline at end of file diff --git a/js-apps/meep-frontend/.gitignore b/js-apps/meep-frontend/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..4ae45c82c35890c6ee7f76026d71fda3f1dd7f6c --- /dev/null +++ b/js-apps/meep-frontend/.gitignore @@ -0,0 +1,3 @@ +cypress/screenshots +cypress/videos +coverage \ No newline at end of file diff --git a/js-apps/meep-frontend/package-lock.json b/js-apps/meep-frontend/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..25c0ab0c83cdf0978666dcb34ad81b01b7342842 --- /dev/null +++ b/js-apps/meep-frontend/package-lock.json @@ -0,0 +1,18720 @@ +{ + "name": "meep-controller-web-ui-js", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.3.4.tgz", + "integrity": "sha512-jRsuseXBo9pN197KnDwhhaaBzyZr2oIcLHHTt2oDdQrej5Qp57dCCJafWx5ivU8/alEYDpssYqv1MUqcxwQlrA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helpers": "^7.2.0", + "@babel/parser": "^7.3.4", + "@babel/template": "^7.2.2", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "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" + } + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.3.4.tgz", + "integrity": "sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-react-jsx": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.3.0.tgz", + "integrity": "sha512-MjA9KgwCuPEkQd9ncSXvSyJ5y+j2sICHyrI0M3L+6fnS4wMSNDc1ARXsbTfbb2cXHn17VisSnU/sHFTCxVxSMw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0", + "esutils": "^2.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz", + "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-define-map": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz", + "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz", + "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", + "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz", + "integrity": "sha512-YRD7I6Wsv+IHuTPkAmAS4HhY0dkPobgLftHp0cRGZSdrRvmZY8rFvae/GVu3bD00qscuvK3WPHB3YdNpBXUqrA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/template": "^7.2.2", + "@babel/types": "^7.2.2", + "lodash": "^4.17.10" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz", + "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz", + "integrity": "sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.3.4", + "@babel/types": "^7.3.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.3.1.tgz", + "integrity": "sha512-Q82R3jKsVpUV99mgX50gOPCWwco9Ec5Iln/8Vyu4osNIOQgSrd9RFrQeUvmvddFNoLwMyOUWU+5ckioEKpDoGA==", + "dev": true, + "requires": { + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.3.0" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.3.4.tgz", + "integrity": "sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz", + "integrity": "sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.2.0.tgz", + "integrity": "sha512-LvRVYb7kikuOtIoUeWTkOxQEV1kYvL5B6U3iWEGCzPNRus1MzJweFqORTj+0jkxozkTSYNJozPOddxmqdqsRpw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.2.0" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.2.0.tgz", + "integrity": "sha512-VyN4QANJkRW6lDBmENzRszvZf3/4AXaj9YR7GwrWeeN9tEBPuXbmDYVU9bYBN0D70zCWVwUy0HWq2553VCb6Hw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz", + "integrity": "sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz", + "integrity": "sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.11" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz", + "integrity": "sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.1.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.3.4", + "@babel/helper-split-export-declaration": "^7.0.0", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.3.2.tgz", + "integrity": "sha512-Lrj/u53Ufqxl/sGxyjsJ2XNtNuEjDyjpqdhMNh5aZ+XFOdThL46KBj27Uem4ggoezSYBxKWAil6Hu8HtwqesYw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz", + "integrity": "sha512-sKxnyHfizweTgKZf7XsXu/CNupKhzijptfTM+bozonIuyVrLWVUvYjE2bhuSBML8VQeMxq4Mm63Q9qvcvUcciQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", + "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.2.0.tgz", + "integrity": "sha512-Kz7Mt0SsV2tQk6jG5bBv5phVbkd0gd27SgYD4hH1aLMJRchM0dzHaXvrWhVZ+WxAlDoAKZ7Uy3jVTW2mKXQ1WQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.2.0.tgz", + "integrity": "sha512-kWgksow9lHdvBC2Z4mxTsvc7YdY7w/V6B2vy9cTIPtLEE9NhwoWivaxdNM/S37elu5bqlLP/qOY906LukO9lkQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", + "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.2.0.tgz", + "integrity": "sha512-V6y0uaUQrQPXUrmj+hgnks8va2L0zcZymeU7TtWEgdRLNkceafKXEduv7QzgQAE4lT+suwooG9dC7LFhdRAbVQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz", + "integrity": "sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.3.0.tgz", + "integrity": "sha512-NxIoNVhk9ZxS+9lSoAQ/LM0V2UEvARLttEHUrRDGKFaAxOYQcrkN/nLRE+BbbicCAvZPl7wMP0X60HsHE5DtQw==", + "dev": true, + "requires": { + "regexp-tree": "^0.1.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz", + "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", + "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.3.3.tgz", + "integrity": "sha512-IrIP25VvXWu/VlBWTpsjGptpomtIkYrN/3aDp4UKm7xK6UxZY88kcJ1UwETbzHAlwN21MnNfwlar0u8y3KpiXw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.1.0", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-react-display-name": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.2.0.tgz", + "integrity": "sha512-Htf/tPa5haZvRMiNSQSFifK12gtr/8vwfr+A9y69uF0QcU77AVu4K7MiHEkTxF7lQoHOL0F9ErqgfNEAKgXj7A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-react-jsx": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.3.0.tgz", + "integrity": "sha512-a/+aRb7R06WcKvQLOu4/TpjKOdvVEKRLWFpKcNuHhiREPgGRB4TQJxq07+EZLS8LFVYpfq1a5lDUnuMdcCpBKg==", + "dev": true, + "requires": { + "@babel/helper-builder-react-jsx": "^7.3.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@babel/plugin-transform-react-jsx-self": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.2.0.tgz", + "integrity": "sha512-v6S5L/myicZEy+jr6ielB0OR8h+EH/1QFx/YJ7c7Ua+7lqsjj/vW6fD5FR9hB/6y7mGbfT4vAURn3xqBxsUcdg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@babel/plugin-transform-react-jsx-source": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.2.0.tgz", + "integrity": "sha512-A32OkKTp4i5U6aE88GwwcuV4HAprUgHcTq0sSafLxjr6AW0QahrCRCjxogkbbcdtpbXkuTOlgpjophCxb6sh5g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-jsx": "^7.2.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz", + "integrity": "sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.13.4" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", + "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.2.0.tgz", + "integrity": "sha512-FkPix00J9A/XWXv4VoKJBMeSkyY9x/TqIh76wzcdfl57RJJcf8CehQ08uwfhCDNtRQYtHQKBTwKZDEyjE13Lwg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.2.0.tgz", + "integrity": "sha512-m48Y0lMhrbXEJnVUaYly29jRXbQ3ksxPrS1Tg8t+MHqzXhtBYAvI51euOBaoAlZLPHsieY9XPVMf80a5x0cPcA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } + }, + "@babel/preset-env": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.3.4.tgz", + "integrity": "sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.3.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.2.0", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.3.4", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.3.4", + "@babel/plugin-transform-classes": "^7.3.4", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.2.0", + "@babel/plugin-transform-dotall-regex": "^7.2.0", + "@babel/plugin-transform-duplicate-keys": "^7.2.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.2.0", + "@babel/plugin-transform-function-name": "^7.2.0", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.2.0", + "@babel/plugin-transform-modules-systemjs": "^7.3.4", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.3.0", + "@babel/plugin-transform-new-target": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.2.0", + "@babel/plugin-transform-parameters": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.3.4", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.2.0", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.2.0", + "browserslist": "^4.3.4", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.3.0" + } + }, + "@babel/preset-react": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz", + "integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0" + } + }, + "@babel/runtime": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.3.4.tgz", + "integrity": "sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g==", + "requires": { + "regenerator-runtime": "^0.12.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, + "@babel/template": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.2.2.tgz", + "integrity": "sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.2.2", + "@babel/types": "^7.2.2" + } + }, + "@babel/traverse": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.3.4.tgz", + "integrity": "sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.3.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.3.4", + "@babel/types": "^7.3.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + }, + "dependencies": { + "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" + } + }, + "globals": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz", + "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.3.4.tgz", + "integrity": "sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, + "@material-ui/core": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-1.5.1.tgz", + "integrity": "sha512-hGT0JelWZGZqgWZzRbON/uqFCgWa4XhmEFG/IEd9SBwCU4sWC99Kv1KpywLhYYWecobqT4Dh7ijO1ZaIAk8HyA==", + "requires": { + "@babel/runtime": "7.0.0-rc.1", + "@types/jss": "^9.5.3", + "@types/react-transition-group": "^2.0.8", + "brcast": "^3.0.1", + "classnames": "^2.2.5", + "csstype": "^2.5.2", + "debounce": "^1.1.0", + "deepmerge": "^2.0.1", + "dom-helpers": "^3.2.1", + "hoist-non-react-statics": "^2.5.0", + "is-plain-object": "^2.0.4", + "jss": "^9.3.3", + "jss-camel-case": "^6.0.0", + "jss-default-unit": "^8.0.2", + "jss-global": "^3.0.0", + "jss-nested": "^6.0.1", + "jss-props-sort": "^6.0.0", + "jss-vendor-prefixer": "^7.0.0", + "keycode": "^2.1.9", + "normalize-scroll-left": "^0.1.2", + "popper.js": "^1.14.1", + "prop-types": "^15.6.0", + "react-event-listener": "^0.6.2", + "react-jss": "^8.1.0", + "react-transition-group": "^2.2.1", + "recompose": "^0.28.0", + "warning": "^4.0.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-rc.1.tgz", + "integrity": "sha512-Nifv2kwP/nwR39cAOasNxzjYfpeuf/ZbZNtQz5eYxWTC9yHARU9wItFnAwz1GTZ62MU+AtSjzZPMbLK5Q9hmbg==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, + "@material-ui/icons": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-1.1.1.tgz", + "integrity": "sha512-d7I2P1Td4S/1zMAYCIrVQVf+6NUZC5fcIuo0wTrKe/mKxYo9eQ+83lPesI9aBAh+ZTQTjPTqoIvm0WD5e+0uKQ==", + "requires": { + "@babel/runtime": "7.0.0-beta.42", + "recompose": "^0.26.0 || ^0.27.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0-beta.42", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.42.tgz", + "integrity": "sha512-iOGRzUoONLOtmCvjUsZv3mZzgCT6ljHQY5fr1qG1QIiJQwtM7zbPWGGpa3QWETq+UqwWyJnoi5XZDZRwZDFciQ==", + "requires": { + "core-js": "^2.5.3", + "regenerator-runtime": "^0.11.1" + } + }, + "recompose": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.27.1.tgz", + "integrity": "sha512-p7xsyi/rfNjHfdP7vPU02uSFa+Q1eHhjKrvO+3+kRP4Ortj+MxEmpmd+UQtBGM2D2iNAjzNI5rCyBKp9Ob5McA==", + "requires": { + "babel-runtime": "^6.26.0", + "change-emitter": "^0.1.2", + "fbjs": "^0.8.1", + "hoist-non-react-statics": "^2.3.1", + "react-lifecycles-compat": "^3.0.2", + "symbol-observable": "^1.0.4" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "@material/animation": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.34.0.tgz", + "integrity": "sha512-HKWU+pHda+xSIV0lwrTMOb/N005NIAV7+tvEEjTiLrQx74eO6J9nIjfCpZ0W4D8Kb9K90lgHFo0ZRC6yDTjizQ==" + }, + "@material/auto-init": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-0.38.0.tgz", + "integrity": "sha512-s3p5ww4BhCI/ySUulV0TxlAUg9R4PMcFYNGa7Kx4SUoD8k+rai61pgFiJW16YfWbtaI+wCQ25zDFB7Ek3bdpuw==" + }, + "@material/base": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.35.0.tgz", + "integrity": "sha512-PYuluVzcH8hxtionVvpTSygTENlgyOHvJ5ka7JfbCRQfXlxjV8zKYwhh9u/1HqA6y1OonG1oGFCaBHopbdsNEQ==" + }, + "@material/button": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/button/-/button-0.38.1.tgz", + "integrity": "sha512-ceib9rvFIpUTe0/3crfmR/y4OTOQibj6OlHGedA5H/sh2d9ie+btQLP4Xe8I6UKZdzcy6IiLvmlRWR0YdABmZw==", + "requires": { + "@material/elevation": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/card": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/card/-/card-0.38.1.tgz", + "integrity": "sha512-IAJsjD6DNjCUqH7Kk4+Xbehs8VVIqtyFKk4hgAC9poiMWi1gHs9M0H5KRforMlb6lXDAJ9b5t/7QvQodC++Fbg==", + "requires": { + "@material/elevation": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0" + } + }, + "@material/checkbox": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-0.38.1.tgz", + "integrity": "sha512-YJYrE1JCFbGhSjkE3vv9o+u7JKzQx0B+feGsalZ7YDVfKfQyvgJOt5c0ILkKWshzI3QMTRUjzIQfYo8GlFACqg==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/selection-control": "^0.38.1", + "@material/theme": "^0.38.0" + } + }, + "@material/chips": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/chips/-/chips-0.38.1.tgz", + "integrity": "sha512-l6fAl5DNdT1b3Gu0nJsYtdg++M/srtu9KyVTShH2nvXvvWlnRi2yxXp3mZJ1H7HTMk4vtlcDPRtaxaUDKXxLwg==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/checkbox": "^0.38.1", + "@material/ripple": "^0.38.1", + "@material/typography": "^0.38.0" + } + }, + "@material/dialog": { + "version": "0.38.2", + "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-0.38.2.tgz", + "integrity": "sha512-GshVpL1TTlM3WwBFTg+o3Kxomlu8tKj8RuaAyB3rlu19TtegepjfDzQvp8yz0uCrOb66a1QRWGEzGFoNv8Th3Q==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/elevation": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0", + "focus-trap": "^2.3.0" + } + }, + "@material/dom": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/dom/-/dom-0.41.0.tgz", + "integrity": "sha512-wOJrMwjPddYXpQFZAIaCLWI3TO/6KU1lxESTBzunni8A4FHQVWhokml5Xt85GqZwmPFeIF2s+D0wfbWyrGBuKQ==" + }, + "@material/drawer": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-0.38.0.tgz", + "integrity": "sha512-fs+AVly2IUuuwjJWU/luXp/g1zacunLYz5635DWlomK8NkyBjPVnbjUhpdyF1sfDq+Rl1PT933jVPLWOi7VFXg==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/elevation": "^0.38.0", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/elevation": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.38.0.tgz", + "integrity": "sha512-uceP/4qL6U1cyY4mc/CHF6msceQwICAt2LD+hTAEKFTTFSLNsvZxqB+Oa7Yq7O5Wl9iBt2RAHtCiT5R/ACUa2Q==", + "requires": { + "@material/animation": "^0.34.0", + "@material/theme": "^0.38.0" + } + }, + "@material/fab": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/fab/-/fab-0.38.1.tgz", + "integrity": "sha512-4natB43w8KO5dQeT6FeC+IKV23W+2Otap9GQ1/sZBjEQf2bz4XvS2fQqW2RhJvNhQmNMEC6PiuYVFyh2t8Hw6A==", + "requires": { + "@material/animation": "^0.34.0", + "@material/elevation": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/floating-label": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-0.38.0.tgz", + "integrity": "sha512-ga+7ELYrkiRYMHqkLOnCKaQUvGowMYXqML3I7hBhs3eEchTjx42U7bfTSqbfdiNG1F9+cOcSOWTKug2VOkYlkg==", + "requires": { + "@material/base": "^0.35.0", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/form-field": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-0.38.1.tgz", + "integrity": "sha512-pJaTRh3YvioU4hdIigy8hE+YibRt23kS40gPq5i6qRZyWX1LQcfxqsJBNqmFDz+LooLiKhSs3m9mAPNz7APNUg==", + "requires": { + "@material/base": "^0.35.0", + "@material/rtl": "^0.36.0", + "@material/selection-control": "^0.38.1", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/grid-list": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/grid-list/-/grid-list-0.38.0.tgz", + "integrity": "sha512-F8hwlIIRlhGj93AWTPYOYT84YPDH6Z/3BB46tTI7SkLfmUns4klZmOKq/pY07PCHmDeg/6gyk9BKl1QTYT4tYA==", + "requires": { + "@material/base": "^0.35.0", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/icon-button": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-0.38.1.tgz", + "integrity": "sha512-ejMbhthSgC0QO0fvk7Cnw55+Pvo6onxVOtOjctLFaPTG8gPGRqbogsESN3VxGHe42ho+YDINxF5ELIoy1yjAhw==", + "requires": { + "@material/base": "^0.35.0", + "@material/ripple": "^0.38.1", + "@material/theme": "^0.38.0" + } + }, + "@material/icon-toggle": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/icon-toggle/-/icon-toggle-0.38.1.tgz", + "integrity": "sha512-kscaeuLahGXnEquIJ77Ey7XR4zfPNJnzNkSoSVWD5G5LdxfL5vAKE4Cbb/NEK6/kJ3eB0uDOTAFTrxCm7TEV8Q==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/ripple": "^0.38.1", + "@material/theme": "^0.38.0" + } + }, + "@material/image-list": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-0.38.0.tgz", + "integrity": "sha512-x/28ydtNaSnVK/Sdn/5KV9FktYLRahgXk6nhxvHcWTqo12rJ3hXbqImzGL1lUZPzCPQ/tCmqLfJGk3BxQL0M9w==", + "requires": { + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/layout-grid": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-0.34.0.tgz", + "integrity": "sha512-LJ3LHCumfGftl1ihO0LW9JKsnR71nnlvpzhHdUlK6o1GPul+EEUUdOFN1zxI+Ik9iS++1na/Dg8f/1sdQUxj6w==" + }, + "@material/line-ripple": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-0.38.0.tgz", + "integrity": "sha512-HdfU0J1Q3CT2Z/H4aBEKGRTd7K33WhhQkieI4NGGyKSx4uwiRyr61i44Oo+YHK+fVqPjh+aMSjQU3wAfu3vSvA==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/theme": "^0.38.0" + } + }, + "@material/linear-progress": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-0.38.0.tgz", + "integrity": "sha512-fu9w3RjoFrEJ3Ky9tz/E1wkL9bfh2zVRHJWPHDLIx/uos49994OV8BbvefqtS1//Poi25KfXx9GKiXQteOO02Q==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/theme": "^0.38.0" + } + }, + "@material/list": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/list/-/list-0.38.1.tgz", + "integrity": "sha512-by19/KoEqAESGLTC8FuiClsHz7SUUCk9u7vWaQ23NSznMfabG/kBpf82WZfgJcUvCodNQyNSmFuxVkFttd6crg==", + "requires": { + "@material/base": "^0.35.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/menu": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-0.38.0.tgz", + "integrity": "sha512-dq+ZoyxaBBk/J+TCQJ5GQM73GEYLiKJD+M+Ub1WMbgKUb7WQhQuhgVB51YJEcCL8grzEosnbK51SgnyuXODKKg==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/elevation": "^0.38.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/menu-surface": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-0.41.0.tgz", + "integrity": "sha512-HiGFrEIF8DCfEtS8mRtc6MCcK2CJNCh0U6KWWeSIXv+9nW2oiN09piuULXM7aU46wETvfweVcgvHNJvBAXnXjQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@material/notched-outline": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-0.38.0.tgz", + "integrity": "sha512-XDTVXyQ2TR/9Qa66F1UYBSbf5f0IVFJFjiF8TXyIkoqrP6l7Wauj+UvJpinwCPk/6KoZtj29sh6ToGQiHdVIJA==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/theme": "^0.38.0" + } + }, + "@material/radio": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/radio/-/radio-0.38.1.tgz", + "integrity": "sha512-zvD7xlzsAusihP3EbRyzf0mH8dy1qCDLMpjZvlwKimgOJNlua87dlbW0c14PwKSoJaS87vFR4v5rMa6+94C0SA==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/ripple": "^0.38.1", + "@material/selection-control": "^0.38.1", + "@material/theme": "^0.38.0" + } + }, + "@material/ripple": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.38.1.tgz", + "integrity": "sha512-Y7fmJCEJMfJFkyDCEHkBR66tHqy4JAlG49rk0cI0/xdAFmAKyqUcpJiVwhF+pC8Fad90Wi3G93xu/ig7dvz1bA==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/theme": "^0.38.0" + } + }, + "@material/rtl": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.36.0.tgz", + "integrity": "sha512-uCMwWGdKG0ooYh1kVINz7vTgSY++9wnvU3kOqjRdfOY+PZHWSa/X/EqRdE9Q1pUFwYlQeU2PXE/Z2dTK/nlziw==" + }, + "@material/select": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/select/-/select-0.38.1.tgz", + "integrity": "sha512-42eaR3CkK6DU011BBUG10dG0MsTf01dGtGaJ4Mu4fA2y/XqY1Au9/fLVOWLHWVEPCJNNXytYyNY6D83u7joqZg==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/floating-label": "^0.38.0", + "@material/line-ripple": "^0.38.0", + "@material/notched-outline": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/selection-control": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.38.1.tgz", + "integrity": "sha512-EUTHx323geAqbPXgMrtu9TCq/IstPma3eJtU50xdpuX/aOVviFIcBzDtK1LBc5czprcuo4wowdfIDvcD+lafxQ==", + "requires": { + "@material/ripple": "^0.38.1" + } + }, + "@material/shape": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.35.0.tgz", + "integrity": "sha512-WMmGLWrqRymMn8gaPybDWRIx7zNurUmaUa/OoxB++HSiLdLZf8hdEffiWLgqc5u97eRpb4IRaIi/jzcPbWxiUw==" + }, + "@material/slider": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/slider/-/slider-0.38.0.tgz", + "integrity": "sha512-HF0XPteiS8IpT1xyGi1dYLd5CW3FxXlDKteNsuhroSFXON2CNH+voHdfT+jW1WfkWcDKSthmSTB1iabD8+9xDg==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0" + } + }, + "@material/snackbar": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-0.38.0.tgz", + "integrity": "sha512-YvQJTxcd8SkCejI2NiZtAiIzvA097zm0qLQr1bD8j3uAuuuenK3BllNKO8K9nPAmvLmOGS5GRaeRUfsmWcwzTA==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/switch": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/switch/-/switch-0.38.1.tgz", + "integrity": "sha512-8Azym74vsSv0EGXo4hKSagaPYqme0hw5cxzuXIVjmHojVAZhOLzUXTiSBXDwi3Lq8cyGvfqBebH7fEpZQ8II2A==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/elevation": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/selection-control": "^0.38.1", + "@material/theme": "^0.38.0" + } + }, + "@material/tab": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/tab/-/tab-0.38.1.tgz", + "integrity": "sha512-LrTEO8CCBkchYEymcLNthwLONnjpZRUt4YXkHi0X6nnTaT+l+GjWAwZer1SLFANOCfBJ5vy49IRfMFPlpUfVjA==", + "requires": { + "@material/base": "^0.35.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/tab-indicator": "^0.38.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/tab-bar": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-0.38.1.tgz", + "integrity": "sha512-tfQKK60ZHNt3tsRy6M6x09J1zw4BfaP2lftuCFxmvE/3VWpGurKIyttj69uuSjfOPQRTVWlK5NF2hmOQMZBXgQ==", + "requires": { + "@material/base": "^0.35.0", + "@material/elevation": "^0.38.0", + "@material/tab": "^0.38.1", + "@material/tab-scroller": "^0.38.1" + } + }, + "@material/tab-indicator": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-0.38.0.tgz", + "integrity": "sha512-Bf094KEhVImPSX9Rob1a8v8MrrbcBa71/p4UHbXcjrheqdoS4jtW3kuh3UzVmdLjVVOmalUwlKtD4HE3lCmPLA==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/theme": "^0.38.0" + } + }, + "@material/tab-scroller": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-0.38.1.tgz", + "integrity": "sha512-tEIyn34yn50d63yuYUC8dU6zZaAL/hsdFiavJx2FOkWT0irgrRZEXea8BepR7EzbbvgzRjnKHOddxyj2R90WcA==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/tab": "^0.38.1" + } + }, + "@material/textfield": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-0.38.1.tgz", + "integrity": "sha512-ymgDVc1W0ToMVnzfjlhATXHgVDST3zqMKfrI7u4eHkXm5v4eaH2SWlIUDBJDUAKtvcHq1BmAhzB3CcWweLw0qw==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/floating-label": "^0.38.0", + "@material/line-ripple": "^0.38.0", + "@material/notched-outline": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/theme": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.38.0.tgz", + "integrity": "sha512-mP5+qgICPm/0dD3hKa/hMd8AHerkAaLJgEsvBwTXi+N/kpPo9LIrHg40DvUGPs5w6KD9PUuskb3WGBvYcToHvA==" + }, + "@material/toolbar": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/toolbar/-/toolbar-0.38.1.tgz", + "integrity": "sha512-EkBC8UcO8DHuM8qPlmSome7w0k+qiwUsliB/orHVhg8zdC9Ikq1FhK6wTK9oKFsJHbJZS49JfaAXh8VhpzybSQ==", + "requires": { + "@material/base": "^0.35.0", + "@material/elevation": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/top-app-bar": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-0.38.1.tgz", + "integrity": "sha512-rnjYLgzPVpTwsBSQiimZt5YvxuN/+D+rRm00gJmlvUCmkYyq63ItycHkydSf4vCIo0tzuoyHoQS9dgVq1UUCqQ==", + "requires": { + "@material/animation": "^0.34.0", + "@material/base": "^0.35.0", + "@material/elevation": "^0.38.0", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/theme": "^0.38.0", + "@material/typography": "^0.38.0" + } + }, + "@material/typography": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.38.0.tgz", + "integrity": "sha512-g2wigBZXSXwrZtibt6sbPO1eM2IROdo9Jk7ffGIb7GuYGLD92hWWzxusaOg4W/rcsBkWMdfquydRL3Q4HFnS2g==" + }, + "@rmwc/base": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/base/-/base-4.0.6.tgz", + "integrity": "sha512-rO/ZQCUuo9DjIovlNwPO4pYvewmBoCDmGF4k3HH3jxXCo5zT2v6MGU9CBHJq1EZxQrYtRAX9tfuCPSf4vSwGPg==", + "requires": { + "classnames": "^2.2.5", + "hyperform": "^0.9.9", + "mutation-observer": "^1.0.3", + "prop-types": "^15.6.1" + } + }, + "@rmwc/button": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/button/-/button-4.0.6.tgz", + "integrity": "sha512-a6J8Zriufigm5EO7WVVsdLAujEohbYK+jqbJBMJzzt3oOa89RQMkWGkipo83J8feuP0kij/7lSlEjuxIRW26bA==", + "requires": { + "@material/button": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6", + "@rmwc/provider": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/button": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/button/-/button-0.41.0.tgz", + "integrity": "sha512-9mA/7P8yD3YPJ8ijwu0oOiT65OCa8Km3M9OF6VAsBE+XJS9Wo5hWDMgkv16raeOFeXj+1ALsjvuTz31JdcSkgQ==", + "requires": { + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/card": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/card/-/card-4.0.6.tgz", + "integrity": "sha512-dV14BZbodP/ypl4ZJ6b4S+vc5c27wsufNiHhnAnDvUES5XeChJQKHjFEUTACZXgT0p0OGtk3sRhnS4eDkkTnJg==", + "requires": { + "@material/card": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/button": "^4.0.6", + "@rmwc/icon-button": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/card": { + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/@material/card/-/card-0.41.1.tgz", + "integrity": "sha512-0L3BkkHK9qRXNh9MOK4XkCYHmZcqwLK5gACIWSLDOjEefmifBeahJeDJSYLVHS9KWl43glIGSrpNGjyXs19mCQ==", + "requires": { + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/checkbox": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/checkbox/-/checkbox-4.0.6.tgz", + "integrity": "sha512-saSJ5SIzdGvJpGjaAg//7HIKniyWWU8ZgWQxYZs3OaZfxkwriqO4ga0JaVuA1jBmrsxd+eifI4MYraJcXassOQ==", + "requires": { + "@material/animation": "~0.41.0", + "@material/checkbox": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/formfield": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/checkbox": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-0.41.0.tgz", + "integrity": "sha512-Zz6e5WRpziO7Z+4rbEs8GHNNBf1UuttniLp6/RvwPSQRaD8G04sdg4HcP/aDCY1KGMwivkuDPc2Bsgs6j+rD7Q==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/selection-control": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.41.0.tgz", + "integrity": "sha512-rRHGiZVPoP4nxAAoeqsgTsxz9GwInGs7HIlEhPfMFygmSZVUHHsuOJXSTpOKYi8GCoKHpB0RKZsAtxM0BYAelw==", + "requires": { + "@material/ripple": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/chip": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/chip/-/chip-4.0.6.tgz", + "integrity": "sha512-iac+1m1ObQ/ol2vrGD77ql+lEIWBwBiXihr0RuacLa9EBjZGfQuXlSmrrfyp2r/3XFOGVIREIw4qJFw8PukEQw==", + "requires": { + "@material/chips": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/checkbox": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-0.41.0.tgz", + "integrity": "sha512-Zz6e5WRpziO7Z+4rbEs8GHNNBf1UuttniLp6/RvwPSQRaD8G04sdg4HcP/aDCY1KGMwivkuDPc2Bsgs6j+rD7Q==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/chips": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/chips/-/chips-0.41.0.tgz", + "integrity": "sha512-Z2q01n4JdRR2f2fdYNCftmgu0M8wu8PZUeQTK3e3zVkQyRdmXcbqMbLHRawVWuXORC8/mIA6tuTtOEqle/Qj9w==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/checkbox": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/selection-control": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.41.0.tgz", + "integrity": "sha512-rRHGiZVPoP4nxAAoeqsgTsxz9GwInGs7HIlEhPfMFygmSZVUHHsuOJXSTpOKYi8GCoKHpB0RKZsAtxM0BYAelw==", + "requires": { + "@material/ripple": "^0.41.0" + } + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/circular-progress": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/circular-progress/-/circular-progress-4.0.6.tgz", + "integrity": "sha512-ZJPfybnhSKzbcUGtqnLdlSbM2o+YfuCCdyMfnQnT2l4FAnPt5Ei7p7CzdfEnnzXWsFeMF9APR35yTR4+B1bBZA==", + "requires": { + "@rmwc/base": "^4.0.6" + } + }, + "@rmwc/data-table": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/data-table/-/data-table-4.0.6.tgz", + "integrity": "sha512-PKyy4oP4DbdZ8ycGOvIMHYj9Aa4u5hcyPArT141SDJLOUE2uz4EK37Uw4sLqIAnhN/MOPzyACusXTRMscq6ecQ==", + "requires": { + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6" + } + }, + "@rmwc/dialog": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/dialog/-/dialog-4.0.6.tgz", + "integrity": "sha512-3h7jUS2fF6sc4UAbAKZXAm4wxvsEEvI7TM//knlyA/hxjoSN2eVyZbwtiql2hxQ3yisYr1xAVq1e/Cc/XnZ6Qw==", + "requires": { + "@material/dialog": "~0.41.0", + "@material/dom": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/button": "^4.0.6", + "focus-trap": "^2.3.0" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/dialog": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-0.41.0.tgz", + "integrity": "sha512-IhRMGTr/41/D0lhagvshCtzI4d9+ynE7FFjpQXc6GU81pHHGt0eYt5vQl3Z/DsatOCdBd+Nc3YDTyJX8OA+8CQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/dom": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0", + "focus-trap": "^2.3.0" + } + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/drawer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/drawer/-/drawer-4.0.6.tgz", + "integrity": "sha512-gq5ikQ999AARCV+Oge7mEioh9ZMMuDNffCLiuolvdD2KAZJ1Yp/kewwtnDTnFXBT87p/Hm5YZBbGgKIydQocDQ==", + "requires": { + "@material/drawer": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/drawer": { + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-0.41.1.tgz", + "integrity": "sha512-4t9ARGaIg8jpXIqD8hy4kcZ0hsF7y25gk2jNQAYG8ukQuDgbenjydlNFnC+I/eWBVIKqnVBlens+4ZUns+n3hg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/list": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0", + "focus-trap": "^3.0.0" + } + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-0.41.0.tgz", + "integrity": "sha512-HhYN0I02CTT8j91c1eeeI+L2KXVKdfzj0Zuapp2SdeCmQZLJO2tu2NYj0W6REBDTVBWBccr12Sn8o71CodEScQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/dom": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + }, + "focus-trap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-3.0.0.tgz", + "integrity": "sha512-jTFblf0tLWbleGjj2JZsAKbgtZTdL1uC48L8FcmSDl4c2vDoU4NycN1kgV5vJhuq1mxNFkw7uWZ1JAGlINWvyw==", + "requires": { + "tabbable": "^3.1.0", + "xtend": "^4.0.1" + } + }, + "tabbable": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-3.1.2.tgz", + "integrity": "sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==" + } + } + }, + "@rmwc/elevation": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/elevation/-/elevation-4.0.6.tgz", + "integrity": "sha512-tdmvvvJK9TGw5FaZdXb2ojXnxLtmA2DqcCIEyak5zfwTwOx4oywXLDwRuAx/IrCBv1laNOYtYnn7u0gph5Hnwg==", + "requires": { + "@material/elevation": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/fab": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/fab/-/fab-4.0.6.tgz", + "integrity": "sha512-PMkHEcDaZRenV+JJ9VSojvrwPwMS4uMXKBQgIhYiS6AUa54ZDEMRl0RSJsXNQMzPzPLK44tVCkuk32i2shVo1w==", + "requires": { + "@material/fab": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6", + "@rmwc/provider": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/fab": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/fab/-/fab-0.41.0.tgz", + "integrity": "sha512-SY/XhkFqlbT8byz0wVJF6vPoGQQRwcTpA7toK1WexW87tSme8KE17yAGJxsZYzIOOFZqW1xF+aDajWdaWyDZdQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/floating-label": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/floating-label/-/floating-label-4.0.6.tgz", + "integrity": "sha512-2tVhxGYEjEfDwkLBvDV8bopswXoc1Q/GNg3GuppuNKQEUucYKuvoQtsgydJU3SpxHNappkffYqOQTIWrVVGYiw==", + "requires": { + "@material/floating-label": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/floating-label": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-0.41.0.tgz", + "integrity": "sha512-qI6f1nZU3crXxWAI9fw3U5fHw2qOzEor49EvskbcaV5KSRW5qO+jtfUQ3ib/Vhki7lqhgwNHB/0n7KYhvhjRHQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/formfield": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/formfield/-/formfield-4.0.6.tgz", + "integrity": "sha512-dsdddmjCkrG8SCsob1VTXLrVmpHfoHuEIf9Ev/rXfUm266LYzCACiIZURdvFqZJS3s/Y/LOMkudbayXcAWbr7g==", + "requires": { + "@material/form-field": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/form-field": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-0.41.0.tgz", + "integrity": "sha512-vNduTfxS1KHCt/NATfX56m7iSXqcemrDq3NMX0txijUQyZ3Sr4xdUQdys+2ky/rBuQTVqBBsc9ixIyHehECaoQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/selection-control": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.41.0.tgz", + "integrity": "sha512-rRHGiZVPoP4nxAAoeqsgTsxz9GwInGs7HIlEhPfMFygmSZVUHHsuOJXSTpOKYi8GCoKHpB0RKZsAtxM0BYAelw==", + "requires": { + "@material/ripple": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/grid": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/grid/-/grid-4.0.6.tgz", + "integrity": "sha512-i4bZYFNv62LST27xbl01RKVoM/mihxshePokMCO5+xy1EBYE6SR1GlI8gKmSfhoGV9TBFpG+NsnkSBqdAuNZng==", + "requires": { + "@material/layout-grid": "~0.39.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/layout-grid": { + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-0.39.0.tgz", + "integrity": "sha512-F2V7cf7pJtlDyHKJJ1u7Xn6JWfiY7bFbg33QnhRXYTAhDF5aEcFPeSh9CK8ZZZ4Bom9gzfms2VXWXClbfQgE2Q==" + } + } + }, + "@rmwc/grid-list": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/grid-list/-/grid-list-4.0.6.tgz", + "integrity": "sha512-uIKnWgZK3aMaR7Yhsbtk7S7Vj+Pu7kRRzdlvZ0bVoFwspSz0exAIciWKWqyT9urhRYzRtVX5Igf5LLOvMq54fQ==", + "requires": { + "@material/grid-list": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6" + }, + "dependencies": { + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/grid-list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/grid-list/-/grid-list-0.41.0.tgz", + "integrity": "sha512-vs0UyvfswW/nyPAoYLRIWEvMmfZUSKVOUSTnHC+PsZ5aXTwGCiCdUugMZdQVhPp9NkxW5mqmCCVroD5eH/yd4g==", + "requires": { + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/icon": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/icon/-/icon-4.0.6.tgz", + "integrity": "sha512-MEmWQyHJFNKCTn4DuHBFcagkmsvZzCqfdqag2n0LEZdwaQ3TCvWehMxPfhlMh44+N8QNPnkE7tgzsDTfkyznIQ==", + "requires": { + "@rmwc/base": "^4.0.6", + "@rmwc/provider": "^4.0.6" + } + }, + "@rmwc/icon-button": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/icon-button/-/icon-button-4.0.6.tgz", + "integrity": "sha512-gKaLn/FWj/fax8IIPA3ILL/YVobH89BM4vYzh8RJoN++wyuxsc6imALQKYUdEpTkJKyyNAoJ2whhROd4YdZV+g==", + "requires": { + "@material/icon-button": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/icon-button": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-0.41.0.tgz", + "integrity": "sha512-RzGSH97aUcTW4he+uU8ahT75DEn6+29L0hH4PBKe03/R/qHFfOrWfjfd03PPiCkaT5SNkPkt1YnfEPqKolnH1Q==", + "requires": { + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/image-list": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/image-list/-/image-list-4.0.6.tgz", + "integrity": "sha512-JD/GJ6BmOXMfwZ7Rjkzg1FTbupkpyFTrgQ3p1Mx1/RKQMw2b1FI9JOVn9lN1FgXOaD52W/Mdd3mRxeeeE1BDdw==", + "requires": { + "@material/image-list": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/image-list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-0.41.0.tgz", + "integrity": "sha512-j3V51PYdfhHB6CWfy076BYT4jHJMqQ86zOpv2OtsjexDc3JPQImB/v/+y018tyDCGOuwjWLoCUi+szTbtzCeQA==", + "requires": { + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/line-ripple": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/line-ripple/-/line-ripple-4.0.6.tgz", + "integrity": "sha512-XIQ+NXz2QJLgxnp/m9W11tEZOSOST1CwcRSOpJX9vNgBfVafJTbMMK8H/Hr8ucYCTtFVMIpTksOJlIg0ME+emA==", + "requires": { + "@material/line-ripple": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/line-ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-0.41.0.tgz", + "integrity": "sha512-5DDIoC3d78fCLhNgle7DRFojT3D2SF+XVpUd3g6yLZmybHB7832p4bgl/qGpbIXwk1wAQA1dkUgKH5foxorjNQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/linear-progress": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/linear-progress/-/linear-progress-4.0.6.tgz", + "integrity": "sha512-cOb0zEFbhFDGyOg/iA60WsnNjknyCZI+KNkr6eiONSiL4yhauwOBqkAHQqgqP4isIQ6O+qD0V3iXnuZQZ3qXYg==", + "requires": { + "@material/linear-progress": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/linear-progress": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-0.41.0.tgz", + "integrity": "sha512-yWnJK58QfovYNJXANGfKWcyC5k9IqBFvygYa2EYQSH/MZbIvd84+MIn0fJO9xsRza79BA8Xh2tFIdTFy4+2Ctg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/list": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/list/-/list-4.0.6.tgz", + "integrity": "sha512-uR8IE0Rme82GqfRAS17r/MK8NgBDT/e2Ku3yM64ww2ic+eXtHJ9Kt1rLc38sl6ID2MvSRauVUaxG3YCS/r2YYw==", + "requires": { + "@material/list": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6", + "@rmwc/provider": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-0.41.0.tgz", + "integrity": "sha512-HhYN0I02CTT8j91c1eeeI+L2KXVKdfzj0Zuapp2SdeCmQZLJO2tu2NYj0W6REBDTVBWBccr12Sn8o71CodEScQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/dom": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/menu": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/menu/-/menu-4.0.6.tgz", + "integrity": "sha512-0fkMKxSqQCdqQAn6bIOzMxct0yhvDsQWlco6Gy0v/4fz2mlAt2Dosjy7blBwv3zCWGf7S32DW8p1K8awH4YWIQ==", + "requires": { + "@material/menu": "~0.41.0", + "@material/menu-surface": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/list": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-0.41.0.tgz", + "integrity": "sha512-HhYN0I02CTT8j91c1eeeI+L2KXVKdfzj0Zuapp2SdeCmQZLJO2tu2NYj0W6REBDTVBWBccr12Sn8o71CodEScQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/dom": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/menu": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-0.41.0.tgz", + "integrity": "sha512-w8UFEnTWzOWl1hRx06tFBqAY4I0vYmbDIVwxO8g1CIgQkfG2dIXjJUfVvlYf9NzZ0VOyyKMh69MmMA5KP+HgAw==", + "requires": { + "@material/base": "^0.41.0", + "@material/list": "^0.41.0", + "@material/menu-surface": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/notched-outline": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/notched-outline/-/notched-outline-4.0.6.tgz", + "integrity": "sha512-LWC2F0e1/XPuvuXPXuENCIscnnswN1LIos+dl+1PZMbG26zuaG5lLUGV8/IerK+WWYgLsk6bohOnzCAKHpHIHw==", + "requires": { + "@material/notched-outline": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/notched-outline": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-0.41.0.tgz", + "integrity": "sha512-nQBkOXvkd5G9FeJ9UuecZh88WRgTsnGVvfj7UFJZEkvkzZwLBGUiJS6fF9FYraih3ZFgmphdbJxXEd9af3cqyQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/provider": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/provider/-/provider-4.0.6.tgz", + "integrity": "sha512-9HmaLdk9IHRHd3V6u0o2o2pICogSRrUpIlbsVOfW8ccG5hTpsOUbReGHTZxfIE/rFdcbU600wLZZa1PXKXfZAA==", + "requires": { + "@rmwc/base": "^4.0.6" + } + }, + "@rmwc/radio": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/radio/-/radio-4.0.6.tgz", + "integrity": "sha512-cii/0gvPDT1RVG8iWxxSTA8DHFHD1o9fBzm6i82MJbeXqe6XwQBNiJo665xYw4UqRhkBW8xc6/pfPOH/ugbbRQ==", + "requires": { + "@material/radio": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/formfield": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/radio": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/radio/-/radio-0.41.0.tgz", + "integrity": "sha512-nJvVVu2x2lAttUNnJczpZzKWK+3lEw/BOYsSLVSYp1qUlIQsOfQ6aItI7URokbLkQDqDqlsNmvGP5JJv/Cpksw==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/selection-control": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.41.0.tgz", + "integrity": "sha512-rRHGiZVPoP4nxAAoeqsgTsxz9GwInGs7HIlEhPfMFygmSZVUHHsuOJXSTpOKYi8GCoKHpB0RKZsAtxM0BYAelw==", + "requires": { + "@material/ripple": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/ripple": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/ripple/-/ripple-4.0.6.tgz", + "integrity": "sha512-RH4e5oyErFd16jIPQHQRIRQIypX3AmhnNsuc6sfbs9LNyqME6ARP2nxWqPlGdN6ttnAb71uDXYUaD03sAEap3g==", + "requires": { + "@material/ripple": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/select": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/select/-/select-4.0.6.tgz", + "integrity": "sha512-KOdT6Knhahq2L+/6gOkVpjYDhIYHcL5QQoIa8fOxKiQMjbS1HaN6sF58pdiAXT1udWYl2P1AqnjMuBURhOjA9Q==", + "requires": { + "@material/select": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/floating-label": "^4.0.6", + "@rmwc/icon": "^4.0.6", + "@rmwc/line-ripple": "^4.0.6", + "@rmwc/list": "^4.0.6", + "@rmwc/menu": "^4.0.6", + "@rmwc/notched-outline": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/floating-label": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-0.41.0.tgz", + "integrity": "sha512-qI6f1nZU3crXxWAI9fw3U5fHw2qOzEor49EvskbcaV5KSRW5qO+jtfUQ3ib/Vhki7lqhgwNHB/0n7KYhvhjRHQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/line-ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-0.41.0.tgz", + "integrity": "sha512-5DDIoC3d78fCLhNgle7DRFojT3D2SF+XVpUd3g6yLZmybHB7832p4bgl/qGpbIXwk1wAQA1dkUgKH5foxorjNQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-0.41.0.tgz", + "integrity": "sha512-HhYN0I02CTT8j91c1eeeI+L2KXVKdfzj0Zuapp2SdeCmQZLJO2tu2NYj0W6REBDTVBWBccr12Sn8o71CodEScQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/dom": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/menu": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-0.41.0.tgz", + "integrity": "sha512-w8UFEnTWzOWl1hRx06tFBqAY4I0vYmbDIVwxO8g1CIgQkfG2dIXjJUfVvlYf9NzZ0VOyyKMh69MmMA5KP+HgAw==", + "requires": { + "@material/base": "^0.41.0", + "@material/list": "^0.41.0", + "@material/menu-surface": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1" + } + }, + "@material/notched-outline": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-0.41.0.tgz", + "integrity": "sha512-nQBkOXvkd5G9FeJ9UuecZh88WRgTsnGVvfj7UFJZEkvkzZwLBGUiJS6fF9FYraih3ZFgmphdbJxXEd9af3cqyQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/select": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/select/-/select-0.41.0.tgz", + "integrity": "sha512-MAU/EHGT1QmBlDvvKI1X7M0ua9w8RqP0UjDMkFxhyfA9tv7ZBS7u/z2/GBb9DUzFu2rKu9DCQ5B+GLBglukfAg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/floating-label": "^0.41.0", + "@material/line-ripple": "^0.41.0", + "@material/menu": "^0.41.0", + "@material/menu-surface": "^0.41.0", + "@material/notched-outline": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/slider": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/slider/-/slider-4.0.6.tgz", + "integrity": "sha512-s5umkOqflSsrDLB99C2U3eDL5MBDcEL1V5X6h66vJSUQ8LTG53tzLMPugOel43pWyTYOAzGtww1HFnSeTn1HRw==", + "requires": { + "@material/slider": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/slider": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/slider/-/slider-0.41.0.tgz", + "integrity": "sha512-u+riWFMeEiczu9bv+Am+28ICX6ba8S55Z+c5JUFtegZNILC76DAuYe++jy0huZw4j/RJXq8hDtj4wJQwvaFTyw==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/snackbar": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/snackbar/-/snackbar-4.0.6.tgz", + "integrity": "sha512-N882OH7g16nLiQe6VWb4AOgYpUvKEdAnJfBD0+PiYeX5vUE1TGg87pxhLgTGergE/+o/Jk05cnhyDDxHC3Jhaw==", + "requires": { + "@material/animation": "~0.39.0", + "@material/snackbar": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/button": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.39.0.tgz", + "integrity": "sha512-f3BGCba0GdYY+eGFnK0L08HLyljgEyBvMLoJoutP225IpvzsLLTqumL/796nFCsouWn6E3G+8BUVjAtzTjU2lA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/snackbar": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-0.41.0.tgz", + "integrity": "sha512-z44BspVFD4B3p651sF0sHYCdQXNdPJR/MkHkrHT8bXnEql7B8qpBsGRKgnPzm1kbAjG5jPkdbbwhbH04WR/0IQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + } + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/switch": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/switch/-/switch-4.0.6.tgz", + "integrity": "sha512-hDGEEnLoSleJYK7YCW0yq7ZMcpVOPy1G4pXUaD3Rle9QWV1ZjLRYZX2HUw/FeTz/THWepxnUUgxTyLye7GRLYQ==", + "requires": { + "@material/switch": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/button": "^4.0.6", + "@rmwc/formfield": "^4.0.6", + "@rmwc/ripple": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/selection-control": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.41.0.tgz", + "integrity": "sha512-rRHGiZVPoP4nxAAoeqsgTsxz9GwInGs7HIlEhPfMFygmSZVUHHsuOJXSTpOKYi8GCoKHpB0RKZsAtxM0BYAelw==", + "requires": { + "@material/ripple": "^0.41.0" + } + }, + "@material/switch": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/switch/-/switch-0.41.0.tgz", + "integrity": "sha512-8YTrn1oisUhp6DlB1XAPeFWVr5nD88jlq9FoTVQOtGaUxaEybQD0nrsYI7OwaVm4HvSnepd2zmMvbjXKbQX4XQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/tabs": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/tabs/-/tabs-4.0.6.tgz", + "integrity": "sha512-jAfWTSAYo0u6eyvPt5uZJRXwZlu5eNKnRDL+bFRjoA1JhXmv4M00/FFvtPRitT5QNDGgTVTeK48YKjLWXaqz0w==", + "requires": { + "@material/tab": "~0.41.0", + "@material/tab-bar": "~0.41.0", + "@material/tab-indicator": "~0.41.0", + "@material/tab-scroller": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/tab": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/tab/-/tab-0.41.0.tgz", + "integrity": "sha512-yM6eYD8Kgrk2cHa+zN3GYIK4Mt6EsSxDIpaArE6JopqRpalULjiOk83hWVPR1V95xphnzYAWM1YF6I6JexE9kw==", + "requires": { + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/tab-indicator": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/tab-bar": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-0.41.0.tgz", + "integrity": "sha512-RL+0CA4ZeZAmhz3vlyFsm8h9sLim8JHTLkosfZSYRnx2o9iQHQHpV58jz76ZSWG+0iuDoHFnwZ2oNKNmImn0KQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/tab": "^0.41.0", + "@material/tab-scroller": "^0.41.0" + } + }, + "@material/tab-indicator": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-0.41.0.tgz", + "integrity": "sha512-IBJEO+O8OnFVgRAn4CCGccpyNPF1bvTp5+1foD46S2u7XZLD7ejfxTQhqE5HYWtVLQ3zk1aYo3+N9+oSUkpM2w==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/tab-scroller": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-0.41.0.tgz", + "integrity": "sha512-dyxaxLLSiDigIUVJ0BwqnKBtBseALrOhmPgvk6BQVDbynnRQ2bOvaNZ7cbpe3A0i8zOQGOoTZF4i9D38/iubcg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/tab": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/textfield": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/textfield/-/textfield-4.0.6.tgz", + "integrity": "sha512-NSgYXh8kAbXH6+1vBvzzXOMdPbrUrAi+IApY7sL8PCRQxgfABFIoT8hZu1WEQjR3JnvakGIc6soVyi4eumtSqw==", + "requires": { + "@material/textfield": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/floating-label": "^4.0.6", + "@rmwc/icon": "^4.0.6", + "@rmwc/line-ripple": "^4.0.6", + "@rmwc/notched-outline": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/floating-label": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-0.41.0.tgz", + "integrity": "sha512-qI6f1nZU3crXxWAI9fw3U5fHw2qOzEor49EvskbcaV5KSRW5qO+jtfUQ3ib/Vhki7lqhgwNHB/0n7KYhvhjRHQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/line-ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-0.41.0.tgz", + "integrity": "sha512-5DDIoC3d78fCLhNgle7DRFojT3D2SF+XVpUd3g6yLZmybHB7832p4bgl/qGpbIXwk1wAQA1dkUgKH5foxorjNQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/notched-outline": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-0.41.0.tgz", + "integrity": "sha512-nQBkOXvkd5G9FeJ9UuecZh88WRgTsnGVvfj7UFJZEkvkzZwLBGUiJS6fF9FYraih3ZFgmphdbJxXEd9af3cqyQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/textfield": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-0.41.0.tgz", + "integrity": "sha512-kJ52W2gxOS2xfpreVhvHQ1u3UkiDl58duw9HkhEkK5Oi1bSDOtbnlWy0pGTOiAma5ZQgetPNgoa+T0zMBptfnw==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/floating-label": "^0.41.0", + "@material/line-ripple": "^0.41.0", + "@material/notched-outline": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/theme": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/theme/-/theme-4.0.6.tgz", + "integrity": "sha512-iwsiTB4ykv01++ovTDjGPmroIW9DDUcFlJmYIYjR5WL4RifCTtOrwR21e5Bcs4JqpvKD9Rkii3Zp27ah5rrt+g==", + "requires": { + "@material/theme": "~0.41.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + } + } + }, + "@rmwc/toolbar": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/toolbar/-/toolbar-4.0.6.tgz", + "integrity": "sha512-/HfqqS4fOWsd6SkJjh3kXbcID96R3zqLUHnbL11w8n2st2J1FnFawXAUe0+ldU7O74AkV84ZmwOmq1BPgdKbng==", + "requires": { + "@material/toolbar": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/toolbar": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/toolbar/-/toolbar-0.41.0.tgz", + "integrity": "sha512-fAZSGM9xyVNI8FI92kmmvNCV4fzEWJBd1q9qMOqbna5AVtbJRNlGSY5HNgEi0vHi/nmY3UXD+VvDbLgoTXtdGg==", + "requires": { + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/top-app-bar": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/top-app-bar/-/top-app-bar-4.0.6.tgz", + "integrity": "sha512-Ug93vcCtuv4iENnLn7nGthdAR0q0gOtB/uTT+ZJRNA5GTyHMstUsT8hYdNz377/E6VqKennKmb2PtzXXsfkKDQ==", + "requires": { + "@material/top-app-bar": "~0.41.0", + "@rmwc/base": "^4.0.6", + "@rmwc/icon": "^4.0.6" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/top-app-bar": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-0.41.0.tgz", + "integrity": "sha512-U3MK6pdzyfXC3zttsrEYihzR7aRqnKM3w2MWRwI0iub/lFygVOSa4qQfaJhwjz9TTyxB8tdtZOXBpEVDsH+xmA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + } + } + }, + "@rmwc/typography": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@rmwc/typography/-/typography-4.0.6.tgz", + "integrity": "sha512-LgZ2/UYFHuMzEYfPkrnAePQS/YpP94qnZ78rJHavgw5uKofs+ldIvMPT1dx4Xpwa+ZmtGGNDES7TVQoeS4Onnw==", + "requires": { + "@material/typography": "~0.39.0", + "@rmwc/base": "^4.0.6" + }, + "dependencies": { + "@material/typography": { + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.39.0.tgz", + "integrity": "sha512-S7YTR2mXuAaPvsgX6jyT1YvWQhH2xHWi+SKJvlunoF/Dw6vq6Ud+APmqigHVRPNCcFt4zkbM7C64IxYjjkIApQ==" + } + } + }, + "@shellscape/koa-send": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@shellscape/koa-send/-/koa-send-4.1.3.tgz", + "integrity": "sha512-akNxJetq2ak8aj7U6ys+EYXfWY4k8keleDZJbHWvpuVDj0/PUbbOuPkeBYaie7C6d5fRNLK+0M1Puu8ywTlj3w==", + "dev": true, + "requires": { + "debug": "^2.6.3", + "http-errors": "^1.6.1", + "mz": "^2.6.0", + "resolve-path": "^1.3.3" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "@shellscape/koa-static": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@shellscape/koa-static/-/koa-static-4.0.5.tgz", + "integrity": "sha512-0T2g2NtaO2zhbqR8EBACIGtBy+haodKb8PuJ17RGDXAJwhjkgghUKLrLEnm05zuiwupfYm2APIax6D2TwLoflA==", + "dev": true, + "requires": { + "@shellscape/koa-send": "^4.1.0", + "debug": "^2.6.8" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "@types/jss": { + "version": "9.5.7", + "resolved": "https://registry.npmjs.org/@types/jss/-/jss-9.5.7.tgz", + "integrity": "sha512-OZimStu2QdDMtZ0h72JXqvLVbWUjXd5ZLk8vxLmfuC/nM1AabRyyGoxSufnzixrbpEcVcyy/JV5qeQu2JnjVZw==", + "requires": { + "csstype": "^2.0.0", + "indefinite-observable": "^1.0.1" + } + }, + "@types/node": { + "version": "11.9.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.6.tgz", + "integrity": "sha512-4hS2K4gwo9/aXIcoYxCtHpdgd8XUeDmo1siRCAH3RziXB65JlPqUFMtfy9VPj+og7dp3w1TFjGwYga4e0m9GwA==", + "dev": true + }, + "@types/prop-types": { + "version": "15.5.9", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.9.tgz", + "integrity": "sha512-Nha5b+jmBI271jdTMwrHiNXM+DvThjHOfyZtMX9kj/c/LUj2xiLHsG/1L3tJ8DjAoQN48cHwUwtqBotjyXaSdQ==" + }, + "@types/react": { + "version": "16.8.4", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.4.tgz", + "integrity": "sha512-Mpz1NNMJvrjf0GcDqiK8+YeOydXfD8Mgag3UtqQ5lXYTsMnOiHcKmO48LiSWMb1rSHB9MV/jlgyNzeAVxWMZRQ==", + "requires": { + "@types/prop-types": "*", + "csstype": "^2.2.0" + } + }, + "@types/react-transition-group": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.0.16.tgz", + "integrity": "sha512-FUJEx2BGJPU1qVQoWd9v7wpOwnCPTWhcE4iTaU5prry9SvwiI11lCXOci8Nz9cM/Fuf650l7Skg6nlVeCYjPFA==", + "requires": { + "@types/react": "*" + } + }, + "@webassemblyjs/ast": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.3.tgz", + "integrity": "sha512-xy3m06+Iu4D32+6soz6zLnwznigXJRuFNTovBX2M4GqVqLb0dnyWLbPnpcXvUSdEN+9DVyDeaq2jyH1eIL2LZQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/wast-parser": "1.8.3" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.3.tgz", + "integrity": "sha512-vq1TISG4sts4f0lDwMUM0f3kpe0on+G3YyV5P0IySHFeaLKRYZ++n2fCFfG4TcCMYkqFeTUYFxm75L3ddlk2xA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.3.tgz", + "integrity": "sha512-BmWEynI4FnZbjk8CaYZXwcv9a6gIiu+rllRRouQUo73hglanXD3AGFJE7Q4JZCoVE0p5/jeX6kf5eKa3D4JxwQ==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.3.tgz", + "integrity": "sha512-iVIMhWnNHoFB94+/2l7LpswfCsXeMRnWfExKtqsZ/E2NxZyUx9nTeKK/MEMKTQNEpyfznIUX06OchBHQ+VKi/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.3.tgz", + "integrity": "sha512-K1UxoJML7GKr1QXR+BG7eXqQkvu+eEeTjlSl5wUFQ6W6vaOc5OwSxTcb3oE9x/3+w4NHhrIKD4JXXCZmLdL2cg==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.3" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.3.tgz", + "integrity": "sha512-387zipfrGyO77/qm7/SDUiZBjQ5KGk4qkrVIyuoubmRNIiqn3g+6ijY8BhnlGqsCCQX5bYKOnttJobT5xoyviA==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.3.tgz", + "integrity": "sha512-lPLFdQfaRssfnGEJit5Sk785kbBPPPK4ZS6rR5W/8hlUO/5v3F+rN8XuUcMj/Ny9iZiyKhhuinWGTUuYL4VKeQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.3.tgz", + "integrity": "sha512-R1nJW7bjyJLjsJQR5t3K/9LJ0QWuZezl8fGa49DZq4IVaejgvkbNlKEQxLYTC579zgT4IIIVHb5JA59uBPHXyw==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.3.tgz", + "integrity": "sha512-P6F7D61SJY73Yz+fs49Q3+OzlYAZP86OfSpaSY448KzUy65NdfzDmo2NPVte+Rw4562MxEAacvq/mnDuvRWOcg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-buffer": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/wasm-gen": "1.8.3" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.3.tgz", + "integrity": "sha512-UD4HuLU99hjIvWz1pD68b52qsepWQlYCxDYVFJQfHh3BHyeAyAlBJ+QzLR1nnS5J6hAzjki3I3AoJeobNNSZlg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.3.tgz", + "integrity": "sha512-XXd3s1BmkC1gpGABuCRLqCGOD6D2L+Ma2BpwpjrQEHeQATKWAQtxAyU9Z14/z8Ryx6IG+L4/NDkIGHrccEhRUg==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.3.tgz", + "integrity": "sha512-Wv/WH9Zo5h5ZMyfCNpUrjFsLZ3X1amdfEuwdb7MLdG3cPAjRS6yc6ElULlpjLiiBTuzvmLhr3ENsuGyJ3wyCgg==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.3.tgz", + "integrity": "sha512-nB19eUx3Yhi1Vvv3yev5r+bqQixZprMtaoCs1brg9Efyl8Hto3tGaUoZ0Yb4Umn/gQCyoEGFfUxPLp1/8+Jvnw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-buffer": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/helper-wasm-section": "1.8.3", + "@webassemblyjs/wasm-gen": "1.8.3", + "@webassemblyjs/wasm-opt": "1.8.3", + "@webassemblyjs/wasm-parser": "1.8.3", + "@webassemblyjs/wast-printer": "1.8.3" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.3.tgz", + "integrity": "sha512-sDNmu2nLBJZ/huSzlJvd9IK8B1EjCsOl7VeMV9VJPmxKYgTJ47lbkSP+KAXMgZWGcArxmcrznqm7FrAPQ7vVGg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/ieee754": "1.8.3", + "@webassemblyjs/leb128": "1.8.3", + "@webassemblyjs/utf8": "1.8.3" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.3.tgz", + "integrity": "sha512-j8lmQVFR+FR4/645VNgV4R/Jz8i50eaPAj93GZyd3EIJondVshE/D9pivpSDIXyaZt+IkCodlzOoZUE4LnQbeA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-buffer": "1.8.3", + "@webassemblyjs/wasm-gen": "1.8.3", + "@webassemblyjs/wasm-parser": "1.8.3" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.3.tgz", + "integrity": "sha512-NBI3SNNtRoy4T/KBsRZCAWUzE9lI94RH2nneLwa1KKIrt/2zzcTavWg6oY05ArCbb/PZDk3OUi63CD1RYtN65w==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-api-error": "1.8.3", + "@webassemblyjs/helper-wasm-bytecode": "1.8.3", + "@webassemblyjs/ieee754": "1.8.3", + "@webassemblyjs/leb128": "1.8.3", + "@webassemblyjs/utf8": "1.8.3" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.3.tgz", + "integrity": "sha512-gZPst4CNcmGtKC1eYQmgCx6gwQvxk4h/nPjfPBbRoD+Raw3Hs+BS3yhrfgyRKtlYP+BJ8LcY9iFODEQofl2qbg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/floating-point-hex-parser": "1.8.3", + "@webassemblyjs/helper-api-error": "1.8.3", + "@webassemblyjs/helper-code-frame": "1.8.3", + "@webassemblyjs/helper-fsm": "1.8.3", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.3.tgz", + "integrity": "sha512-DTA6kpXuHK4PHu16yAD9QVuT1WZQRT7079oIFFmFSjqjLWGXS909I/7kiLTn931mcj7wGsaUNungjwNQ2lGQ3Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/wast-parser": "1.8.3", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "abab": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", + "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", + "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, + "requires": { + "mime-types": "~2.1.18", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", + "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", + "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.0.tgz", + "integrity": "sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "dev": true + }, + "ajv": { + "version": "6.9.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", + "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", + "dev": true, + "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" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", + "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "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": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "app-root-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.1.0.tgz", + "integrity": "sha1-mL9lmTJ+zqGZMJhm6BQDaP0uZGo=", + "dev": true + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "arch": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.1.1.tgz", + "integrity": "sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "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" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "array.prototype.flat": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.1.tgz", + "integrity": "sha512-rVqIs330nLJvfC7JqYvEWwqVr5QjYF1ib02i3YJtR/fICO6527Tjpc/e4Mvmxh3GIePPreRXMdaGyC99YphWEw==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.10.0", + "function-bind": "^1.1.1" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", + "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, + "requires": { + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz", + "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "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" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true + }, + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", + "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", + "dev": true, + "requires": { + "browserslist": "^1.7.6", + "caniuse-db": "^1.0.30000634", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^5.2.16", + "postcss-value-parser": "^3.2.3" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "^1.0.30000639", + "electron-to-chromium": "^1.2.7" + } + } + } + }, + "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=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "axios": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", + "requires": { + "follow-redirects": "^1.3.0", + "is-buffer": "^1.1.5" + } + }, + "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" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "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" + } + }, + "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 + }, + "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" + } + }, + "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 + } + } + }, + "babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true + }, + "babel-jest": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.1.0.tgz", + "integrity": "sha512-MLcagnVrO9ybQGLEfZUqnOzv36iQzU7Bj4elm39vCukumLVSfoX+tRy3/jW7lUKc7XdpRmB/jech6L/UCsSZjw==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.1.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + }, + "dependencies": { + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "babel-loader": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.5.tgz", + "integrity": "sha512-NTnHnVRd2JnRqPC0vW+iOQWU5pchDbYXsG2E6DMXEpMfUcQKclF9gmf3G3ZMhzG7IG9ji4coL0cm+FxeWxDpnw==", + "dev": true, + "requires": { + "find-cache-dir": "^2.0.0", + "loader-utils": "^1.0.2", + "mkdirp": "^0.5.1", + "util.promisify": "^1.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", + "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + } + } + }, + "babel-plugin-jest-hoist": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.1.0.tgz", + "integrity": "sha512-gljYrZz8w1b6fJzKcsfKsipSru2DU2DmQ39aB6nV3xQ0DDv3zpIzKGortA5gknrhNnPN8DweaEgrnZdmbGmhnw==", + "dev": true + }, + "babel-preset-jest": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.1.0.tgz", + "integrity": "sha512-FfNLDxFWsNX9lUmtwY7NheGlANnagvxq8LZdl5PKnVG3umP+S/g0XbVBfwtA4Ai3Ri/IMkWabBz3Tyk9wdspcw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.1.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=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.0.tgz", + "integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz", + "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brcast": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/brcast/-/brcast-3.0.1.tgz", + "integrity": "sha512-eI3yqf9YEqyGl9PCNTR46MGvDylGtaHjalcz6Q3fAPnP/PhpKkkve52vFdfGpwp4VUvK6LUr4TQN+2stCrEwTg==" + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.4.2.tgz", + "integrity": "sha512-ISS/AIAiHERJ3d45Fz0AVYKkgcy+F/eJHzKEvv1j0wwKGKD9T3BrwKr/5g45L+Y4XIK5PlTqefHciRFcfE1Jxg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000939", + "electron-to-chromium": "^1.3.113", + "node-releases": "^1.1.8" + } + }, + "bser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz", + "integrity": "sha1-mseNPtXZFYBP2HrLFYvHlxR6Fxk=", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cacache": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.2", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cache-content-type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", + "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", + "dev": true, + "requires": { + "mime-types": "^2.1.18", + "ylru": "^1.2.0" + } + }, + "callsites": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.0.0.tgz", + "integrity": "sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + } + } + }, + "caniuse-api": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", + "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", + "dev": true, + "requires": { + "browserslist": "^1.3.6", + "caniuse-db": "^1.0.30000529", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "^1.0.30000639", + "electron-to-chromium": "^1.2.7" + } + } + } + }, + "caniuse-db": { + "version": "1.0.30000939", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000939.tgz", + "integrity": "sha512-nB5tLf3hOs+biXl1lhKjHRgNC0J1I7H52h/t1FP7qxARKKwpB0z+P/JewJLYAlxCBP/q7rxJzQzHHrQMl0viKg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30000939", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000939.tgz", + "integrity": "sha512-oXB23ImDJOgQpGjRv1tCtzAvJr4/OvrHi5SO2vUgB0g0xpdZZoA/BxfImiWfdwoYdUTtQrPsXsvYU/dmCSM8gg==", + "dev": true + }, + "capture-exit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-1.2.0.tgz", + "integrity": "sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28=", + "dev": true, + "requires": { + "rsvp": "^3.3.3" + } + }, + "capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "change-emitter": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz", + "integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU=" + }, + "cheerio": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", + "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", + "dev": true, + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash": "^4.15.0", + "parse5": "^3.0.1" + }, + "dependencies": { + "parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "dev": true, + "requires": { + "@types/node": "*" + } + } + } + }, + "chokidar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.2.tgz", + "integrity": "sha512-IwXUx0FXc5ibYmPC2XeEj5mpXoV66sR+t3jqu2NS2GYwCktt3KF1/Qqjws/NkegajBA4RbZ5+DDwlOiJsxDHEg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.0" + }, + "dependencies": { + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + } + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz", + "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "clap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", + "dev": true, + "requires": { + "chalk": "^1.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "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" + } + }, + "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" + } + }, + "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 + } + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "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 + } + } + }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true + }, + "clipboardy": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-1.2.3.tgz", + "integrity": "sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==", + "dev": true, + "requires": { + "arch": "^2.1.0", + "execa": "^0.8.0" + }, + "dependencies": { + "execa": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", + "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + } + } + }, + "cliui": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-deep": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", + "integrity": "sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.0", + "shallow-clone": "^1.0.0" + }, + "dependencies": { + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", + "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", + "dev": true, + "requires": { + "q": "^1.1.2" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", + "dev": true, + "requires": { + "clone": "^1.0.2", + "color-convert": "^1.3.0", + "color-string": "^0.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-string": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", + "dev": true, + "requires": { + "color-name": "^1.0.0" + } + }, + "colormin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", + "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", + "dev": true, + "requires": { + "color": "^0.11.0", + "css-color-names": "0.0.4", + "has": "^1.0.1" + } + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "compare-versions": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.4.0.tgz", + "integrity": "sha512-tK69D7oNXXqUW3ZNo/z7NXTEz22TCF0pTE+YF9cxvaAM9XnkLo1fV621xCLrRR6aevJlKxExkss0vWqUCUpqdg==", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "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=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "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==", + "dev": true, + "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==", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookies": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.3.tgz", + "integrity": "sha512-+gixgxYSgQLTaTIilDHAdlNPZDENDQernEMiIcZpYYP14zgHsCt4Ce1FEjFtcp6GefhozebB6orvhAAWx/IS0A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "keygrip": "~1.0.3" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", + "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==" + }, + "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=", + "dev": true + }, + "cosmiconfig": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz", + "integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==", + "dev": true, + "requires": { + "is-directory": "^0.3.1", + "js-yaml": "^3.9.0", + "parse-json": "^4.0.0", + "require-from-string": "^2.0.1" + }, + "dependencies": { + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + } + } + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-loader": { + "version": "0.28.11", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.11.tgz", + "integrity": "sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==", + "dev": true, + "requires": { + "babel-code-frame": "^6.26.0", + "css-selector-tokenizer": "^0.7.0", + "cssnano": "^3.10.0", + "icss-utils": "^2.1.0", + "loader-utils": "^1.0.2", + "lodash.camelcase": "^4.3.0", + "object-assign": "^4.1.1", + "postcss": "^5.0.6", + "postcss-modules-extract-imports": "^1.2.0", + "postcss-modules-local-by-default": "^1.2.0", + "postcss-modules-scope": "^1.1.0", + "postcss-modules-values": "^1.3.0", + "postcss-value-parser": "^3.3.0", + "source-list-map": "^2.0.0" + } + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-selector-tokenizer": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz", + "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==", + "dev": true, + "requires": { + "cssesc": "^0.1.0", + "fastparse": "^1.1.1", + "regexpu-core": "^1.0.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "regexpu-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", + "dev": true, + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, + "css-vendor": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz", + "integrity": "sha1-ZCHP0wNM5mT+dnOXL9ARn8KJQfo=", + "requires": { + "is-in-browser": "^1.0.2" + } + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true + }, + "cssesc": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", + "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=", + "dev": true + }, + "cssnano": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", + "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", + "dev": true, + "requires": { + "autoprefixer": "^6.3.1", + "decamelize": "^1.1.2", + "defined": "^1.0.0", + "has": "^1.0.1", + "object-assign": "^4.0.1", + "postcss": "^5.0.14", + "postcss-calc": "^5.2.0", + "postcss-colormin": "^2.1.8", + "postcss-convert-values": "^2.3.4", + "postcss-discard-comments": "^2.0.4", + "postcss-discard-duplicates": "^2.0.1", + "postcss-discard-empty": "^2.0.1", + "postcss-discard-overridden": "^0.1.1", + "postcss-discard-unused": "^2.2.1", + "postcss-filter-plugins": "^2.0.0", + "postcss-merge-idents": "^2.1.5", + "postcss-merge-longhand": "^2.0.1", + "postcss-merge-rules": "^2.0.3", + "postcss-minify-font-values": "^1.0.2", + "postcss-minify-gradients": "^1.0.1", + "postcss-minify-params": "^1.0.4", + "postcss-minify-selectors": "^2.0.4", + "postcss-normalize-charset": "^1.1.0", + "postcss-normalize-url": "^3.0.7", + "postcss-ordered-values": "^2.1.0", + "postcss-reduce-idents": "^2.2.2", + "postcss-reduce-initial": "^1.0.0", + "postcss-reduce-transforms": "^1.0.3", + "postcss-svgo": "^2.1.1", + "postcss-unique-selectors": "^2.0.2", + "postcss-value-parser": "^3.2.3", + "postcss-zindex": "^2.0.1" + } + }, + "csso": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", + "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", + "dev": true, + "requires": { + "clap": "^1.0.9", + "source-map": "^0.5.3" + } + }, + "cssom": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", + "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==", + "dev": true + }, + "cssstyle": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.1.tgz", + "integrity": "sha512-7DYm8qe+gPx/h77QlCyFmX80+fGaE/6A/Ekl0zaszYOubvySO2saYFdQ78P29D0UsULxFKCetDGNaNRUdSF+2A==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "csstype": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.2.tgz", + "integrity": "sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==" + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "^0.10.9" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debounce": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz", + "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==" + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "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 + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==" + }, + "default-require-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", + "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "dev": true, + "requires": { + "strip-bom": "^3.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "diff-sequences": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.0.0.tgz", + "integrity": "sha512-46OkIuVGBBnrC0soO/4LHu5LHGHx0uhP65OVz8XOrAJpqiCB2aVIuESvjI1F9oqebuvY8lekS1pt6TN7vt7qsw==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", + "dev": true + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "dom-serializer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", + "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "dev": true, + "requires": { + "domelementtype": "^1.3.0", + "entities": "^1.1.1" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "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=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.113", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz", + "integrity": "sha512-De+lPAxEcpxvqPTyZAXELNpRZXABRxf+uL/rSykstQhzj/B0l1150G/ExIIxKc16lI89Hgz81J0BHAcbTqK49g==", + "dev": true + }, + "elliptic": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emitter-component": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.1.tgz", + "integrity": "sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY=" + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "enzyme": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/enzyme/-/enzyme-3.9.0.tgz", + "integrity": "sha512-JqxI2BRFHbmiP7/UFqvsjxTirWoM1HfeaJrmVSZ9a1EADKkZgdPcAuISPMpoUiHlac9J4dYt81MC5BBIrbJGMg==", + "dev": true, + "requires": { + "array.prototype.flat": "^1.2.1", + "cheerio": "^1.0.0-rc.2", + "function.prototype.name": "^1.1.0", + "has": "^1.0.3", + "html-element-map": "^1.0.0", + "is-boolean-object": "^1.0.0", + "is-callable": "^1.1.4", + "is-number-object": "^1.0.3", + "is-regex": "^1.0.4", + "is-string": "^1.0.4", + "is-subset": "^0.1.1", + "lodash.escape": "^4.0.1", + "lodash.isequal": "^4.5.0", + "object-inspect": "^1.6.0", + "object-is": "^1.0.1", + "object.assign": "^4.1.0", + "object.entries": "^1.0.4", + "object.values": "^1.0.4", + "raf": "^3.4.0", + "rst-selector-parser": "^2.2.3", + "string.prototype.trim": "^1.1.2" + } + }, + "enzyme-adapter-react-16": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.10.0.tgz", + "integrity": "sha512-0QqwEZcBv1xEEla+a3H7FMci+y4ybLia9cZzsdIrId7qcig4MK0kqqf6iiCILH1lsKS6c6AVqL3wGPhCevv5aQ==", + "dev": true, + "requires": { + "enzyme-adapter-utils": "^1.10.0", + "object.assign": "^4.1.0", + "object.values": "^1.1.0", + "prop-types": "^15.6.2", + "react-is": "^16.7.0", + "react-test-renderer": "^16.0.0-0" + } + }, + "enzyme-adapter-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/enzyme-adapter-utils/-/enzyme-adapter-utils-1.10.0.tgz", + "integrity": "sha512-VnIXJDYVTzKGbdW+lgK8MQmYHJquTQZiGzu/AseCZ7eHtOMAj4Rtvk8ZRopodkfPves0EXaHkXBDkVhPa3t0jA==", + "dev": true, + "requires": { + "function.prototype.name": "^1.1.0", + "object.assign": "^4.1.0", + "object.fromentries": "^2.0.0", + "prop-types": "^15.6.2", + "semver": "^5.6.0" + } + }, + "enzyme-to-json": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/enzyme-to-json/-/enzyme-to-json-3.3.5.tgz", + "integrity": "sha512-DmH1wJ68HyPqKSYXdQqB33ZotwfUhwQZW3IGXaNXgR69Iodaoj8TF/D9RjLdz4pEhGq2Tx2zwNUIjBuqoZeTgA==", + "dev": true, + "requires": { + "lodash": "^4.17.4" + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-inject": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/error-inject/-/error-inject-1.0.0.tgz", + "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=", + "dev": true + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.48", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.48.tgz", + "integrity": "sha512-CdRvPlX/24Mj5L4NVxTs4804sxiS2CjVprgCmrgoDkdmjdY4D+ySHa7K3jJf8R40dFg0tIm3z/dk326LrnuSGw==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "es6-templates": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz", + "integrity": "sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=", + "dev": true, + "requires": { + "recast": "~0.11.12", + "through": "~2.3.6" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "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 + }, + "escodegen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", + "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "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 + } + } + }, + "eslint-scope": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "exec-sh": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.2.2.tgz", + "integrity": "sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw==", + "dev": true, + "requires": { + "merge": "^1.2.0" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "expect": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.1.0.tgz", + "integrity": "sha512-lVcAPhaYkQcIyMS+F8RVwzbm1jro20IG8OkvxQ6f1JfqhVZyyudCwYogQ7wnktlf14iF3ii7ArIUO/mqvrW9Gw==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.0.0", + "jest-matcher-utils": "^24.0.0", + "jest-message-util": "^24.0.0", + "jest-regex-util": "^24.0.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "extract-loader": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-loader/-/extract-loader-2.0.1.tgz", + "integrity": "sha512-P/jwAXSgvtnzFlPCdlsQkgLHDPzOf7Syt+GpU1LkP6TwWAYm7Exfyas3kBffc8Lfq/mDah4qnY3P1uopNzhD4A==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0" + } + }, + "extract-text-webpack-plugin": { + "version": "4.0.0-beta.0", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-4.0.0-beta.0.tgz", + "integrity": "sha512-Hypkn9jUTnFr0DpekNam53X47tXn3ucY08BQumv7kdGgeVUBLq3DJHJTi6HNxv4jl9W+Skxjz9+RnK0sJyqqjA==", + "dev": true, + "requires": { + "async": "^2.4.1", + "loader-utils": "^1.1.0", + "schema-utils": "^0.4.5", + "webpack-sources": "^1.1.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "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=", + "dev": true + }, + "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=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "^2.0.0" + } + }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + } + } + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "file-loader": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", + "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^0.4.5" + } + }, + "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" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz", + "integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^1.0.0", + "pkg-dir": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "focus-trap": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-2.4.6.tgz", + "integrity": "sha512-vWZTPtBU6pBoyWZDRZJHkXsyP2ZCZBHE3DRVXnSVdQKH/mcDtu9S5Kz8CUDyIqpfZfLEyI9rjKJLnc4Y40BRBg==", + "requires": { + "tabbable": "^1.0.3" + } + }, + "follow-redirects": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", + "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", + "requires": { + "debug": "^3.2.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "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" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": 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" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.5", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": 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" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.0.tgz", + "integrity": "sha512-Bs0VRrTz4ghD8pTmbJQD1mZ8A/mN0ur/jGz+A6FBxPDUPkm1tNfF6bhTYPA7i7aF4lZJVr+OXTNNrnnIl58Wfg==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "is-callable": "^1.1.3" + } + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.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" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.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" + } + } + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "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" + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "hammerjs": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", + "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" + }, + "handlebars": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", + "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", + "dev": true, + "requires": { + "async": "^2.5.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=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", + "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==", + "dev": true + }, + "html-element-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/html-element-map/-/html-element-map-1.0.0.tgz", + "integrity": "sha512-/SP6aOiM5Ai9zALvCxDubIeez0LvG3qP7R9GcRDnJEP/HBmv0A8A9K0o8+HFudcFt46+i921ANjzKsjPjb7Enw==", + "dev": true, + "requires": { + "array-filter": "^1.0.0" + } + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "html-loader": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-0.5.5.tgz", + "integrity": "sha512-7hIW7YinOYUpo//kSYcPB6dCKoceKLmOwjEMmhIobHuWGDVl0Nwe4l68mdG/Ru0wcUxQjVMEoZpkalZ/SE7zog==", + "dev": true, + "requires": { + "es6-templates": "^0.2.3", + "fastparse": "^1.1.1", + "html-minifier": "^3.5.8", + "loader-utils": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "html-minifier": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz", + "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==", + "dev": true, + "requires": { + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" + } + }, + "html-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz", + "integrity": "sha1-sBq71yOsqqeze2r0SS69oD2d03s=", + "dev": true, + "requires": { + "html-minifier": "^3.2.3", + "loader-utils": "^0.2.16", + "lodash": "^4.17.3", + "pretty-error": "^2.0.2", + "tapable": "^1.0.0", + "toposort": "^1.0.0", + "util.promisify": "1.0.0" + }, + "dependencies": { + "big.js": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true + }, + "loader-utils": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", + "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", + "dev": true, + "requires": { + "big.js": "^3.1.3", + "emojis-list": "^2.0.0", + "json5": "^0.5.0", + "object-assign": "^4.0.1" + } + } + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", + "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "http-assert": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.0.tgz", + "integrity": "sha512-tPVv62a6l3BbQoM/N5qo969l0OFxqpnQzNUPeYfTP6Spo4zkgWeDBD1D5thI7sDLg7jCCihXTLB0X8UtdyAy8A==", + "dev": true, + "requires": { + "deep-equal": "~1.0.1", + "http-errors": "~1.7.1" + } + }, + "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==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "hyperform": { + "version": "0.9.22", + "resolved": "https://registry.npmjs.org/hyperform/-/hyperform-0.9.22.tgz", + "integrity": "sha512-zJ6Bif/qAnN633pfOcvkEbwvCXnKPjqNgR6VdcRsxXcr+zGV9AdH5m5C/g4Xui16mdotlqweCb8CtkD42x6omQ==" + }, + "hyphenate-style-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", + "integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==" + }, + "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" + } + }, + "icss-replace-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", + "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=", + "dev": true + }, + "icss-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", + "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", + "dev": true, + "requires": { + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "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 + } + } + }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "import-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-1.0.0.tgz", + "integrity": "sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ==", + "dev": true, + "requires": { + "pkg-dir": "^2.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "dev": true + }, + "indefinite-observable": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-1.0.2.tgz", + "integrity": "sha512-Mps0898zEduHyPhb7UCgNmfzlqNZknVmaFz5qzr0mm04YQ5FGLhAyK/dJ+NaRxGyR6juQXIxh5Ev0xx+qq0nYA==", + "requires": { + "symbol-observable": "1.2.0" + } + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-boolean-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.0.tgz", + "integrity": "sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "requires": { + "ci-info": "^1.5.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "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-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-function": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz", + "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=" + }, + "is-generator-fn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.0.0.tgz", + "integrity": "sha512-elzyIdM7iKoFHzcrndIqjYomImhxrFRnGP3galODoII4TB9gI7mZ+FnlLQmmjf27SxHS2gKEeyhX5/+YRS6H9g==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", + "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==", + "dev": true + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-number-object": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.3.tgz", + "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=", + "dev": true + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "is-string": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.4.tgz", + "integrity": "sha1-zDqbaYV9Yh6WNyWiTK7shzuCbmQ=", + "dev": true + }, + "is-subset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", + "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", + "dev": true + }, + "is-svg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", + "dev": true, + "requires": { + "html-comment-regex": "^1.1.0" + } + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "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 + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-api": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-2.1.1.tgz", + "integrity": "sha512-kVmYrehiwyeBAk/wE71tW6emzLiHGjYIiDrc8sfyty4F8M02/lrgXSm+R1kXysmF20zArvmZXjlE/mg24TVPJw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "compare-versions": "^3.2.1", + "fileset": "^2.0.3", + "istanbul-lib-coverage": "^2.0.3", + "istanbul-lib-hook": "^2.0.3", + "istanbul-lib-instrument": "^3.1.0", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.2", + "istanbul-reports": "^2.1.1", + "js-yaml": "^3.12.0", + "make-dir": "^1.3.0", + "minimatch": "^3.0.4", + "once": "^1.4.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz", + "integrity": "sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA==", + "dev": true, + "requires": { + "append-transform": "^1.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + }, + "istanbul-lib-report": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz", + "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "supports-color": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz", + "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.3", + "make-dir": "^1.3.0", + "rimraf": "^2.6.2", + "source-map": "^0.6.1" + }, + "dependencies": { + "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" + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "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 + } + } + }, + "istanbul-reports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz", + "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", + "dev": true, + "requires": { + "handlebars": "^4.1.0" + } + }, + "jest": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.1.0.tgz", + "integrity": "sha512-+q91L65kypqklvlRFfXfdzUKyngQLOcwGhXQaLmVHv+d09LkNXuBuGxlofTFW42XMzu3giIcChchTsCNUjQ78A==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", + "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + }, + "jest-cli": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.1.0.tgz", + "integrity": "sha512-U/iyWPwOI0T1CIxVLtk/2uviOTJ/OiSWJSe8qt6X1VkbbgP+nrtLJlmT9lPBe4lK78VNFJtrJ7pttcNv/s7yCw==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.1.15", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "istanbul-api": "^2.0.8", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-source-maps": "^3.0.1", + "jest-changed-files": "^24.0.0", + "jest-config": "^24.1.0", + "jest-environment-jsdom": "^24.0.0", + "jest-get-type": "^24.0.0", + "jest-haste-map": "^24.0.0", + "jest-message-util": "^24.0.0", + "jest-regex-util": "^24.0.0", + "jest-resolve-dependencies": "^24.1.0", + "jest-runner": "^24.1.0", + "jest-runtime": "^24.1.0", + "jest-snapshot": "^24.1.0", + "jest-util": "^24.0.0", + "jest-validate": "^24.0.0", + "jest-watcher": "^24.0.0", + "jest-worker": "^24.0.0", + "micromatch": "^3.1.10", + "node-notifier": "^5.2.1", + "p-each-series": "^1.0.0", + "pirates": "^4.0.0", + "prompts": "^2.0.1", + "realpath-native": "^1.0.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "string-length": "^2.0.0", + "strip-ansi": "^5.0.0", + "which": "^1.2.12", + "yargs": "^12.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-is-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", + "dev": true + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "strip-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz", + "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==", + "dev": true, + "requires": { + "ansi-regex": "^4.0.0" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-changed-files": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.0.0.tgz", + "integrity": "sha512-nnuU510R9U+UX0WNb5XFEcsrMqriSiRLeO9KWDFgPrpToaQm60prfQYpxsXigdClpvNot5bekDY440x9dNGnsQ==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "throat": "^4.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "jest-config": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.1.0.tgz", + "integrity": "sha512-FbbRzRqtFC6eGjG5VwsbW4E5dW3zqJKLWYiZWhB0/4E5fgsMw8GODLbGSrY5t17kKOtCWb/Z7nsIThRoDpuVyg==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "babel-jest": "^24.1.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.0.0", + "jest-environment-node": "^24.0.0", + "jest-get-type": "^24.0.0", + "jest-jasmine2": "^24.1.0", + "jest-regex-util": "^24.0.0", + "jest-resolve": "^24.1.0", + "jest-util": "^24.0.0", + "jest-validate": "^24.0.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.0.0", + "realpath-native": "^1.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "babel-jest": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.1.0.tgz", + "integrity": "sha512-MLcagnVrO9ybQGLEfZUqnOzv36iQzU7Bj4elm39vCukumLVSfoX+tRy3/jW7lUKc7XdpRmB/jech6L/UCsSZjw==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.1.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", + "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.1.0.tgz", + "integrity": "sha512-gljYrZz8w1b6fJzKcsfKsipSru2DU2DmQ39aB6nV3xQ0DDv3zpIzKGortA5gknrhNnPN8DweaEgrnZdmbGmhnw==", + "dev": true + }, + "babel-preset-jest": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.1.0.tgz", + "integrity": "sha512-FfNLDxFWsNX9lUmtwY7NheGlANnagvxq8LZdl5PKnVG3umP+S/g0XbVBfwtA4Ai3Ri/IMkWabBz3Tyk9wdspcw==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.1.0" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "test-exclude": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", + "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" + } + } + } + }, + "jest-diff": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.0.0.tgz", + "integrity": "sha512-XY5wMpRaTsuMoU+1/B2zQSKQ9RdE9gsLkGydx3nvApeyPijLA8GtEvIcPwISRCer+VDf9W1mStTYYq6fPt8ryA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.0.0", + "jest-get-type": "^24.0.0", + "pretty-format": "^24.0.0" + } + }, + "jest-docblock": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.0.0.tgz", + "integrity": "sha512-KfAKZ4SN7CFOZpWg4i7g7MSlY0M+mq7K0aMqENaG2vHuhC9fc3vkpU/iNN9sOus7v3h3Y48uEjqz3+Gdn2iptA==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.0.0.tgz", + "integrity": "sha512-gFcbY4Cu55yxExXMkjrnLXov3bWO3dbPAW7HXb31h/DNWdNc/6X8MtxGff8nh3/MjkF9DpVqnj0KsPKuPK0cpA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-get-type": "^24.0.0", + "jest-util": "^24.0.0", + "pretty-format": "^24.0.0" + } + }, + "jest-environment-jsdom": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.0.0.tgz", + "integrity": "sha512-1YNp7xtxajTRaxbylDc2pWvFnfDTH5BJJGyVzyGAKNt/lEULohwEV9zFqTgG4bXRcq7xzdd+sGFws+LxThXXOw==", + "dev": true, + "requires": { + "jest-mock": "^24.0.0", + "jest-util": "^24.0.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-node": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.0.0.tgz", + "integrity": "sha512-62fOFcaEdU0VLaq8JL90TqwI7hLn0cOKOl8vY2n477vRkCJRojiRRtJVRzzCcgFvs6gqU97DNqX5R0BrBP6Rxg==", + "dev": true, + "requires": { + "jest-mock": "^24.0.0", + "jest-util": "^24.0.0" + } + }, + "jest-get-type": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.0.0.tgz", + "integrity": "sha512-z6/Eyf6s9ZDGz7eOvl+fzpuJmN9i0KyTt1no37/dHu8galssxz5ZEgnc1KaV8R31q1khxyhB4ui/X5ZjjPk77w==", + "dev": true + }, + "jest-haste-map": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.0.0.tgz", + "integrity": "sha512-CcViJyUo41IQqttLxXVdI41YErkzBKbE6cS6dRAploCeutePYfUimWd3C9rQEWhX0YBOQzvNsC0O9nYxK2nnxQ==", + "dev": true, + "requires": { + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.0.0", + "jest-util": "^24.0.0", + "jest-worker": "^24.0.0", + "micromatch": "^3.1.10", + "sane": "^3.0.0" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "jest-jasmine2": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.1.0.tgz", + "integrity": "sha512-H+o76SdSNyCh9fM5K8upK45YTo/DiFx5w2YAzblQebSQmukDcoVBVeXynyr7DDnxh+0NTHYRCLwJVf3tC518wg==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.1.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.0.0", + "jest-matcher-utils": "^24.0.0", + "jest-message-util": "^24.0.0", + "jest-snapshot": "^24.1.0", + "jest-util": "^24.0.0", + "pretty-format": "^24.0.0", + "throat": "^4.0.0" + } + }, + "jest-leak-detector": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.0.0.tgz", + "integrity": "sha512-ZYHJYFeibxfsDSKowjDP332pStuiFT2xfc5R67Rjm/l+HFJWJgNIOCOlQGeXLCtyUn3A23+VVDdiCcnB6dTTrg==", + "dev": true, + "requires": { + "pretty-format": "^24.0.0" + } + }, + "jest-matcher-utils": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.0.0.tgz", + "integrity": "sha512-LQTDmO+aWRz1Tf9HJg+HlPHhDh1E1c65kVwRFo5mwCVp5aQDzlkz4+vCvXhOKFjitV2f0kMdHxnODrXVoi+rlA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.0.0", + "jest-get-type": "^24.0.0", + "pretty-format": "^24.0.0" + } + }, + "jest-message-util": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.0.0.tgz", + "integrity": "sha512-J9ROJIwz/IeC+eV1XSwnRK4oAwPuhmxEyYx1+K5UI+pIYwFZDSrfZaiWTdq0d2xYFw4Xiu+0KQWsdsQpgJMf3Q==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + } + } + }, + "jest-mock": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.0.0.tgz", + "integrity": "sha512-sQp0Hu5fcf5NZEh1U9eIW2qD0BwJZjb63Yqd98PQJFvf/zzUTBoUAwv/Dc/HFeNHIw1f3hl/48vNn+j3STaI7A==", + "dev": true + }, + "jest-regex-util": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.0.0.tgz", + "integrity": "sha512-Jv/uOTCuC+PY7WpJl2mpoI+WbY2ut73qwwO9ByJJNwOCwr1qWhEW2Lyi2S9ZewUdJqeVpEBisdEVZSI+Zxo58Q==", + "dev": true + }, + "jest-resolve": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.1.0.tgz", + "integrity": "sha512-TPiAIVp3TG6zAxH28u/6eogbwrvZjBMWroSLBDkwkHKrqxB/RIdwkWDye4uqPlZIXWIaHtifY3L0/eO5Z0f2wg==", + "dev": true, + "requires": { + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "realpath-native": "^1.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.1.0.tgz", + "integrity": "sha512-2VwPsjd3kRPu7qe2cpytAgowCObk5AKeizfXuuiwgm1a9sijJDZe8Kh1sFj6FKvSaNEfCPlBVkZEJa2482m/Uw==", + "dev": true, + "requires": { + "jest-regex-util": "^24.0.0", + "jest-snapshot": "^24.1.0" + } + }, + "jest-runner": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.1.0.tgz", + "integrity": "sha512-CDGOkT3AIFl16BLL/OdbtYgYvbAprwJ+ExKuLZmGSCSldwsuU2dEGauqkpvd9nphVdAnJUcP12e/EIlnTX0QXg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.1.0", + "jest-docblock": "^24.0.0", + "jest-haste-map": "^24.0.0", + "jest-jasmine2": "^24.1.0", + "jest-leak-detector": "^24.0.0", + "jest-message-util": "^24.0.0", + "jest-runtime": "^24.1.0", + "jest-util": "^24.0.0", + "jest-worker": "^24.0.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + }, + "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 + }, + "source-map-support": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", + "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "jest-runtime": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.1.0.tgz", + "integrity": "sha512-59/BY6OCuTXxGeDhEMU7+N33dpMQyXq7MLK07cNSIY/QYt2QZgJ7Tjx+rykBI0skAoigFl0A5tmT8UdwX92YuQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "exit": "^0.1.2", + "fast-json-stable-stringify": "^2.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.1.0", + "jest-haste-map": "^24.0.0", + "jest-message-util": "^24.0.0", + "jest-regex-util": "^24.0.0", + "jest-resolve": "^24.1.0", + "jest-snapshot": "^24.1.0", + "jest-util": "^24.0.0", + "jest-validate": "^24.0.0", + "micromatch": "^3.1.10", + "realpath-native": "^1.0.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "write-file-atomic": "2.4.1", + "yargs": "^12.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "babel-plugin-istanbul": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.1.1.tgz", + "integrity": "sha512-RNNVv2lsHAXJQsEJ5jonQwrJVWK8AcZpG1oxhnjCUaAjL7xahYLANhPUZbzEQHjKy1NMYUwn+0NPKQc8iSY4xQ==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.0.0", + "test-exclude": "^5.0.0" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz", + "integrity": "sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA==", + "dev": true, + "requires": { + "@babel/generator": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/template": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "istanbul-lib-coverage": "^2.0.3", + "semver": "^5.5.0" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "mem": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-is-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", + "dev": true + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "test-exclude": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", + "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" + } + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "jest-serializer": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.0.0.tgz", + "integrity": "sha512-9FKxQyrFgHtx3ozU+1a8v938ILBE7S8Ko3uiAVjT8Yfi2o91j/fj81jacCQZ/Ihjiff/VsUCXVgQ+iF1XdImOw==", + "dev": true + }, + "jest-snapshot": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.1.0.tgz", + "integrity": "sha512-th6TDfFqEmXvuViacU1ikD7xFb7lQsPn2rJl7OEmnfIVpnrx3QNY2t3PE88meeg0u/mQ0nkyvmC05PBqO4USFA==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "chalk": "^2.0.1", + "jest-diff": "^24.0.0", + "jest-matcher-utils": "^24.0.0", + "jest-message-util": "^24.0.0", + "jest-resolve": "^24.1.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.0.0", + "semver": "^5.5.0" + } + }, + "jest-util": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.0.0.tgz", + "integrity": "sha512-QxsALc4wguYS7cfjdQSOr5HTkmjzkHgmZvIDkcmPfl1ib8PNV8QUWLwbKefCudWS0PRKioV+VbQ0oCUPC691fQ==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "jest-message-util": "^24.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "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 + } + } + }, + "jest-validate": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.0.0.tgz", + "integrity": "sha512-vMrKrTOP4BBFIeOWsjpsDgVXATxCspC9S1gqvbJ3Tnn/b9ACsJmteYeVx9830UMV28Cob1RX55x96Qq3Tfad4g==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.0.0", + "leven": "^2.1.0", + "pretty-format": "^24.0.0" + }, + "dependencies": { + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.0.0.tgz", + "integrity": "sha512-GxkW2QrZ4YxmW1GUWER05McjVDunBlKMFfExu+VsGmXJmpej1saTEKvONdx5RJBlVdpPI5x6E3+EDQSIGgl53g==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.0.0", + "string-length": "^2.0.0" + } + }, + "jest-worker": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.0.0.tgz", + "integrity": "sha512-s64/OThpfQvoCeHG963MiEZOAAxu8kHsaL/rCMF7lpdzo7vgF0CtPml9hfguOMgykgH/eOm4jFP4ibfHLruytg==", + "dev": true, + "requires": { + "merge-stream": "^1.0.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jquery": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", + "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" + }, + "js-base64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", + "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", + "dev": true + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", + "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", + "dev": true, + "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=", + "dev": true + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + } + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "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==", + "dev": true + }, + "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=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jss": { + "version": "9.8.7", + "resolved": "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz", + "integrity": "sha512-awj3XRZYxbrmmrx9LUSj5pXSUfm12m8xzi/VKeqI1ZwWBtQ0kVPTs3vYs32t4rFw83CgFDukA8wKzOE9sMQnoQ==", + "requires": { + "is-in-browser": "^1.1.3", + "symbol-observable": "^1.1.0", + "warning": "^4.0.1" + } + }, + "jss-camel-case": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jss-camel-case/-/jss-camel-case-6.1.0.tgz", + "integrity": "sha512-HPF2Q7wmNW1t79mCqSeU2vdd/vFFGpkazwvfHMOhPlMgXrJDzdj9viA2SaHk9ZbD5pfL63a8ylp4++irYbbzMQ==", + "requires": { + "hyphenate-style-name": "^1.0.2" + } + }, + "jss-compose": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/jss-compose/-/jss-compose-5.0.0.tgz", + "integrity": "sha512-YofRYuiA0+VbeOw0VjgkyO380sA4+TWDrW52nSluD9n+1FWOlDzNbgpZ/Sb3Y46+DcAbOS21W5jo6SAqUEiuwA==", + "requires": { + "warning": "^4.0.1" + } + }, + "jss-default-unit": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz", + "integrity": "sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg==" + }, + "jss-expand": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/jss-expand/-/jss-expand-5.3.0.tgz", + "integrity": "sha512-NiM4TbDVE0ykXSAw6dfFmB1LIqXP/jdd0ZMnlvlGgEMkMt+weJIl8Ynq1DsuBY9WwkNyzWktdqcEW2VN0RAtQg==" + }, + "jss-extend": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jss-extend/-/jss-extend-6.2.0.tgz", + "integrity": "sha512-YszrmcB6o9HOsKPszK7NeDBNNjVyiW864jfoiHoMlgMIg2qlxKw70axZHqgczXHDcoyi/0/ikP1XaHDPRvYtEA==", + "requires": { + "warning": "^4.0.1" + } + }, + "jss-global": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jss-global/-/jss-global-3.0.0.tgz", + "integrity": "sha512-wxYn7vL+TImyQYGAfdplg7yaxnPQ9RaXY/cIA8hawaVnmmWxDHzBK32u1y+RAvWboa3lW83ya3nVZ/C+jyjZ5Q==" + }, + "jss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jss-nested/-/jss-nested-6.0.1.tgz", + "integrity": "sha512-rn964TralHOZxoyEgeq3hXY8hyuCElnvQoVrQwKHVmu55VRDd6IqExAx9be5HgK0yN/+hQdgAXQl/GUrBbbSTA==", + "requires": { + "warning": "^4.0.1" + } + }, + "jss-preset-default": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-4.5.0.tgz", + "integrity": "sha512-qZbpRVtHT7hBPpZEBPFfafZKWmq3tA/An5RNqywDsZQGrlinIF/mGD9lmj6jGqu8GrED2SMHZ3pPKLmjCZoiaQ==", + "requires": { + "jss-camel-case": "^6.1.0", + "jss-compose": "^5.0.0", + "jss-default-unit": "^8.0.2", + "jss-expand": "^5.3.0", + "jss-extend": "^6.2.0", + "jss-global": "^3.0.0", + "jss-nested": "^6.0.1", + "jss-props-sort": "^6.0.0", + "jss-template": "^1.0.1", + "jss-vendor-prefixer": "^7.0.0" + } + }, + "jss-props-sort": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz", + "integrity": "sha512-E89UDcrphmI0LzmvYk25Hp4aE5ZBsXqMWlkFXS0EtPkunJkRr+WXdCNYbXbksIPnKlBenGB9OxzQY+mVc70S+g==" + }, + "jss-template": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/jss-template/-/jss-template-1.0.1.tgz", + "integrity": "sha512-m5BqEWha17fmIVXm1z8xbJhY6GFJxNB9H68GVnCWPyGYfxiAgY9WTQyvDAVj+pYRgrXSOfN5V1T4+SzN1sJTeg==", + "requires": { + "warning": "^4.0.1" + } + }, + "jss-vendor-prefixer": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz", + "integrity": "sha512-Agd+FKmvsI0HLcYXkvy8GYOw3AAASBUpsmIRvVQheps+JWaN892uFOInTr0DRydwaD91vSSUCU4NssschvF7MA==", + "requires": { + "css-vendor": "^0.3.8" + } + }, + "keycharm": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.2.0.tgz", + "integrity": "sha1-+m6i5DuQpoAohD0n8gddNajD5vk=" + }, + "keycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=" + }, + "keygrip": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.3.tgz", + "integrity": "sha512-/PpesirAIfaklxUzp4Yb7xBper9MwP6hNRA6BGGUFCgbJ+BM5CKBtsoxinNXkLHAr+GXS1/lSlF2rP7cv5Fl+g==", + "dev": true + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "kleur": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.2.tgz", + "integrity": "sha512-3h7B2WRT5LNXOtQiAaWonilegHcPSf9nLVXlSTci8lu1dZUuui61+EsPEZqSVxY7rXYmB2DVKMQILxaO5WL61Q==", + "dev": true + }, + "koa": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.7.0.tgz", + "integrity": "sha512-7ojD05s2Q+hFudF8tDLZ1CpCdVZw8JQELWSkcfG9bdtoTDzMmkRF6BQBU7JzIzCCOY3xd3tftiy/loHBUYaY2Q==", + "dev": true, + "requires": { + "accepts": "^1.3.5", + "cache-content-type": "^1.0.0", + "content-disposition": "~0.5.2", + "content-type": "^1.0.4", + "cookies": "~0.7.1", + "debug": "~3.1.0", + "delegates": "^1.0.0", + "depd": "^1.1.2", + "destroy": "^1.0.4", + "error-inject": "^1.0.0", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.3.0", + "http-errors": "^1.6.3", + "is-generator-function": "^1.0.7", + "koa-compose": "^4.1.0", + "koa-convert": "^1.2.0", + "koa-is-json": "^1.0.0", + "on-finished": "^2.3.0", + "only": "~0.0.2", + "parseurl": "^1.3.2", + "statuses": "^1.5.0", + "type-is": "^1.6.16", + "vary": "^1.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==", + "dev": true + }, + "koa-convert": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", + "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", + "dev": true, + "requires": { + "co": "^4.6.0", + "koa-compose": "^3.0.0" + }, + "dependencies": { + "koa-compose": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", + "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", + "dev": true, + "requires": { + "any-promise": "^1.1.0" + } + } + } + }, + "koa-is-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz", + "integrity": "sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=", + "dev": true + }, + "koa-webpack": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/koa-webpack/-/koa-webpack-3.0.2.tgz", + "integrity": "sha512-SZIhsNOnBVXgspYFfuG/MQ2Orbih97sHxNtswKV5xV2P7CLhvNNzfZFRegaEjQyGQYqWrxbkYRhVcYx83O0p9A==", + "dev": true, + "requires": { + "app-root-path": "^2.0.1", + "merge-options": "^1.0.0", + "webpack-dev-middleware": "^3.0.0", + "webpack-hot-client": "^2.0.0", + "webpack-log": "^1.1.1" + } + }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.escape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz", + "integrity": "sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg=", + "dev": true + }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.mergewith": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", + "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "lodash.tail": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", + "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", + "dev": true + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "loglevelnext": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz", + "integrity": "sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A==", + "dev": true, + "requires": { + "es6-symbol": "^3.1.1", + "object.assign": "^4.1.0" + } + }, + "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==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "material-components-web": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/material-components-web/-/material-components-web-0.38.1.tgz", + "integrity": "sha512-QiiQUETBmjs/AdtQtSCS/oUocCpBiZTLWujEBmx7lFQbEu2jACJnjE4OLUsvMJvOA4B88rbk6ifUN+ImuBVDTQ==", + "requires": { + "@material/animation": "^0.34.0", + "@material/auto-init": "^0.38.0", + "@material/base": "^0.35.0", + "@material/button": "^0.38.1", + "@material/card": "^0.38.1", + "@material/checkbox": "^0.38.1", + "@material/chips": "^0.38.1", + "@material/dialog": "^0.38.1", + "@material/drawer": "^0.38.0", + "@material/elevation": "^0.38.0", + "@material/fab": "^0.38.1", + "@material/floating-label": "^0.38.0", + "@material/form-field": "^0.38.1", + "@material/grid-list": "^0.38.0", + "@material/icon-button": "^0.38.1", + "@material/icon-toggle": "^0.38.1", + "@material/image-list": "^0.38.0", + "@material/layout-grid": "^0.34.0", + "@material/line-ripple": "^0.38.0", + "@material/linear-progress": "^0.38.0", + "@material/list": "^0.38.1", + "@material/menu": "^0.38.0", + "@material/notched-outline": "^0.38.0", + "@material/radio": "^0.38.1", + "@material/ripple": "^0.38.1", + "@material/rtl": "^0.36.0", + "@material/select": "^0.38.1", + "@material/selection-control": "^0.38.1", + "@material/shape": "^0.35.0", + "@material/slider": "^0.38.0", + "@material/snackbar": "^0.38.0", + "@material/switch": "^0.38.1", + "@material/tab": "^0.38.1", + "@material/tab-bar": "^0.38.1", + "@material/tab-indicator": "^0.38.0", + "@material/tab-scroller": "^0.38.1", + "@material/textfield": "^0.38.1", + "@material/theme": "^0.38.0", + "@material/toolbar": "^0.38.1", + "@material/top-app-bar": "^0.38.1", + "@material/typography": "^0.38.0" + } + }, + "material-design-icons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/material-design-icons/-/material-design-icons-3.0.1.tgz", + "integrity": "sha1-mnHEh0chjrylHlGmbaaCA4zct78=" + }, + "math-expression-evaluator": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", + "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "mem": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", + "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^1.0.0", + "p-is-promise": "^2.0.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "merge": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge/-/merge-1.2.1.tgz", + "integrity": "sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==", + "dev": true + }, + "merge-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-1.0.1.tgz", + "integrity": "sha512-iuPV41VWKWBIOpBsjoxjDZw8/GbSfZ2mk7N1453bwMrfzdrIk7EzBd+8UVR6rkw67th7xnk9Dytl3J+lHPdxvg==", + "dev": true, + "requires": { + "is-plain-obj": "^1.1" + } + }, + "merge-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", + "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz", + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==", + "dev": true + }, + "mime-db": { + "version": "1.38.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", + "dev": true + }, + "mime-types": { + "version": "2.1.22", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", + "dev": true, + "requires": { + "mime-db": "~1.38.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "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 + }, + "minimist-options": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "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" + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "moo": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.4.3.tgz", + "integrity": "sha512-gFD2xGCl8YFgGHsqJ9NKRVdwlioeW3mI1iqfLNYQOv0+6JRwG58Zk9DIGQgyIaffSYaO1xsKnMaYzzNr1KyIAw==", + "dev": true + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "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==" + }, + "mutation-observer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mutation-observer/-/mutation-observer-1.0.3.tgz", + "integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA==" + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==", + "dev": true + }, + "nanoassert": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-1.1.0.tgz", + "integrity": "sha1-TzFS4JVA/eKMdvRLGbvNHVpCR40=", + "dev": true + }, + "nanobus": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/nanobus/-/nanobus-4.4.0.tgz", + "integrity": "sha512-Hv9USGyH8EsPy0o8pPWE7x3YRIfuZDgMBirzjU6XLebhiSK2g53JlfqgolD0c39ne6wXAfaBNcIAvYe22Bav+Q==", + "dev": true, + "requires": { + "nanoassert": "^1.1.0", + "nanotiming": "^7.2.0", + "remove-array-items": "^1.0.0" + } + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "nanoscheduler": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/nanoscheduler/-/nanoscheduler-1.0.3.tgz", + "integrity": "sha512-jBbrF3qdU9321r8n9X7yu18DjP31Do2ItJm3mWrt90wJTrnDO+HXpoV7ftaUglAtjgj9s+OaCxGufbvx6pvbEQ==", + "dev": true, + "requires": { + "nanoassert": "^1.1.0" + } + }, + "nanotiming": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/nanotiming/-/nanotiming-7.3.1.tgz", + "integrity": "sha512-l3lC7v/PfOuRWQa8vV29Jo6TG10wHtnthLElFXs4Te4Aas57Fo4n1Q8LH9n+NDh9riOzTVvb2QNBhTS4JUKNjw==", + "dev": true, + "requires": { + "nanoassert": "^1.1.0", + "nanoscheduler": "^1.0.2" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nearley": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.16.0.tgz", + "integrity": "sha512-Tr9XD3Vt/EujXbZBv6UAHYoLUSMQAxSsTnm9K3koXzjzNWY195NqALeyrzLZBKzAkL3gl92BcSogqrHjD8QuUg==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "moo": "^0.4.3", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6", + "semver": "^5.4.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + } + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "neo-async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz", + "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "dev": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", + "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.0", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "0.0.4" + }, + "dependencies": { + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.0.tgz", + "integrity": "sha512-SUDEb+o71XR5lXSTyivXd9J7fCloE3SyP4lSgt3lU2oSANiox+SxlNRGPjDKrwU1YN3ix2KN/VGGCg0t01rttQ==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, + "node-releases": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.8.tgz", + "integrity": "sha512-gQm+K9mGCiT/NXHy+V/ZZS1N/LOaGGqRAAJJs3X9Ah1g+CIbRcBgNyoNYQ+SEtcyAtB9KqDruu+fF7nWjsqRaA==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "node-sass": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", + "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==", + "dev": true, + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash.assign": "^4.2.0", + "lodash.clonedeep": "^4.3.2", + "lodash.mergewith": "^4.6.0", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.10.0", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "^2.2.4", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "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" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "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" + } + }, + "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 + } + } + }, + "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" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-scroll-left": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-scroll-left/-/normalize-scroll-left-0.1.2.tgz", + "integrity": "sha512-F9YMRls0zCF6BFIE2YnXDRpHPpfd91nOIaNdDgrx5YMoPLo8Wqj+6jNXHQsYBavJeXP4ww8HCt0xQAKc5qk2Fg==" + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "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 + }, + "nwsapi": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.1.tgz", + "integrity": "sha512-T5GaA1J/d34AC8mkrFD2O0DR17kwJ702ZOtJOsS8RpbsQZVOC2/xYFb1i/cw+xdM54JIlMuojjDOYct8GIWtwg==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, + "object-is": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.1.tgz", + "integrity": "sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY=", + "dev": true + }, + "object-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", + "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.entries": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz", + "integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "object.fromentries": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz", + "integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.11.0", + "function-bind": "^1.1.1", + "has": "^1.0.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.values": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.0.tgz", + "integrity": "sha512-8mf0nKLAoFX6VlNVdhGj31SVYpaNFtUnuoOXWyFEstsWRgU837AK+JYM0iAxwkSzGRbwn8cbFmgbyxj1j4VbXg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.12.0", + "function-bind": "^1.1.1", + "has": "^1.0.3" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "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=", + "requires": { + "wrappy": "1" + } + }, + "only": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", + "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=", + "dev": true + }, + "opn": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", + "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "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" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", + "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + }, + "dependencies": { + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + } + } + }, + "pako": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.8.tgz", + "integrity": "sha512-6i0HVbUfcKaTv+EG8ZTr75az7GFXcLYk9UyLEg7Notv/Ma+z/UG3TCoz6GiNeOrn1E/e63I0X/Hpw18jHOTUnA==", + "dev": true + }, + "parallel-transform": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", + "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "dev": true, + "requires": { + "cyclist": "~0.2.2", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parse-asn1": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "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=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "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-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "popper.js": { + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.7.tgz", + "integrity": "sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ==" + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "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" + }, + "dependencies": { + "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 + } + } + }, + "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 + }, + "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" + } + }, + "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" + } + } + } + }, + "postcss-calc": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", + "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", + "dev": true, + "requires": { + "postcss": "^5.0.2", + "postcss-message-helpers": "^2.0.0", + "reduce-css-calc": "^1.2.6" + } + }, + "postcss-colormin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", + "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", + "dev": true, + "requires": { + "colormin": "^1.0.5", + "postcss": "^5.0.13", + "postcss-value-parser": "^3.2.3" + } + }, + "postcss-convert-values": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", + "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", + "dev": true, + "requires": { + "postcss": "^5.0.11", + "postcss-value-parser": "^3.1.2" + } + }, + "postcss-discard-comments": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", + "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", + "dev": true, + "requires": { + "postcss": "^5.0.14" + } + }, + "postcss-discard-duplicates": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", + "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", + "dev": true, + "requires": { + "postcss": "^5.0.4" + } + }, + "postcss-discard-empty": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", + "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", + "dev": true, + "requires": { + "postcss": "^5.0.14" + } + }, + "postcss-discard-overridden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", + "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", + "dev": true, + "requires": { + "postcss": "^5.0.16" + } + }, + "postcss-discard-unused": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", + "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", + "dev": true, + "requires": { + "postcss": "^5.0.14", + "uniqs": "^2.0.0" + } + }, + "postcss-filter-plugins": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz", + "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==", + "dev": true, + "requires": { + "postcss": "^5.0.4" + } + }, + "postcss-merge-idents": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", + "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", + "dev": true, + "requires": { + "has": "^1.0.1", + "postcss": "^5.0.10", + "postcss-value-parser": "^3.1.1" + } + }, + "postcss-merge-longhand": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", + "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", + "dev": true, + "requires": { + "postcss": "^5.0.4" + } + }, + "postcss-merge-rules": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", + "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", + "dev": true, + "requires": { + "browserslist": "^1.5.2", + "caniuse-api": "^1.5.2", + "postcss": "^5.0.4", + "postcss-selector-parser": "^2.2.2", + "vendors": "^1.0.0" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "^1.0.30000639", + "electron-to-chromium": "^1.2.7" + } + } + } + }, + "postcss-message-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", + "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=", + "dev": true + }, + "postcss-minify-font-values": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", + "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.2" + } + }, + "postcss-minify-gradients": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", + "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", + "dev": true, + "requires": { + "postcss": "^5.0.12", + "postcss-value-parser": "^3.3.0" + } + }, + "postcss-minify-params": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", + "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.1", + "postcss": "^5.0.2", + "postcss-value-parser": "^3.0.2", + "uniqs": "^2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", + "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.2", + "has": "^1.0.1", + "postcss": "^5.0.14", + "postcss-selector-parser": "^2.0.0" + } + }, + "postcss-modules-extract-imports": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz", + "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==", + "dev": true, + "requires": { + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "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 + } + } + }, + "postcss-modules-local-by-default": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", + "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "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 + } + } + }, + "postcss-modules-scope": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", + "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", + "dev": true, + "requires": { + "css-selector-tokenizer": "^0.7.0", + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "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 + } + } + }, + "postcss-modules-values": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", + "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", + "dev": true, + "requires": { + "icss-replace-symbols": "^1.1.0", + "postcss": "^6.0.1" + }, + "dependencies": { + "postcss": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", + "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "source-map": "^0.6.1", + "supports-color": "^5.4.0" + } + }, + "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 + } + } + }, + "postcss-normalize-charset": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", + "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", + "dev": true, + "requires": { + "postcss": "^5.0.5" + } + }, + "postcss-normalize-url": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", + "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", + "dev": true, + "requires": { + "is-absolute-url": "^2.0.0", + "normalize-url": "^1.4.0", + "postcss": "^5.0.14", + "postcss-value-parser": "^3.2.3" + } + }, + "postcss-ordered-values": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", + "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", + "dev": true, + "requires": { + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.1" + } + }, + "postcss-reduce-idents": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", + "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", + "dev": true, + "requires": { + "postcss": "^5.0.4", + "postcss-value-parser": "^3.0.2" + } + }, + "postcss-reduce-initial": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", + "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", + "dev": true, + "requires": { + "postcss": "^5.0.4" + } + }, + "postcss-reduce-transforms": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", + "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", + "dev": true, + "requires": { + "has": "^1.0.1", + "postcss": "^5.0.8", + "postcss-value-parser": "^3.0.1" + } + }, + "postcss-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", + "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", + "dev": true, + "requires": { + "flatten": "^1.0.2", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1" + } + }, + "postcss-svgo": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", + "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", + "dev": true, + "requires": { + "is-svg": "^2.0.0", + "postcss": "^5.0.14", + "postcss-value-parser": "^3.2.3", + "svgo": "^0.7.0" + } + }, + "postcss-unique-selectors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", + "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", + "dev": true, + "requires": { + "alphanum-sort": "^1.0.1", + "postcss": "^5.0.4", + "uniqs": "^2.0.0" + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "postcss-zindex": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", + "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", + "dev": true, + "requires": { + "has": "^1.0.1", + "postcss": "^5.0.4", + "uniqs": "^2.0.0" + } + }, + "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 + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "pretty-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", + "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", + "dev": true, + "requires": { + "renderkid": "^2.0.1", + "utila": "~0.4" + } + }, + "pretty-format": { + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.0.0.tgz", + "integrity": "sha512-LszZaKG665djUcqg5ZQq+XzezHLKrxsA86ZABTozp+oNhkdqa+tG2dX4qa6ERl5c/sRDrAa3lHmwnvKoP+OG/g==", + "dev": true, + "requires": { + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz", + "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w==", + "dev": true + } + } + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "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 + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prompts": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.0.3.tgz", + "integrity": "sha512-H8oWEoRZpybm6NV4to9/1limhttEo13xK62pNvn2JzY0MA03p7s0OjtmhXyon3uJmxiJJVSuUwEJFFssI3eBiQ==", + "dev": true, + "requires": { + "kleur": "^3.0.2", + "sisteransi": "^1.0.0" + } + }, + "prop-types": { + "version": "15.6.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", + "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, + "propagating-hammerjs": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/propagating-hammerjs/-/propagating-hammerjs-1.4.6.tgz", + "integrity": "sha1-/tAOmwB2f/1C0U9bUxvEk+tnLjc=", + "requires": { + "hammerjs": "^2.0.6" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, + "raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dev": true, + "requires": { + "performance-now": "^2.1.0" + } + }, + "railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=", + "dev": true + }, + "randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dev": true, + "requires": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + } + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "react": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/react/-/react-16.4.1.tgz", + "integrity": "sha512-3GEs0giKp6E0Oh/Y9ZC60CmYgUPnp7voH9fbjWsvXtYFb4EWtgQub0ADSq0sJR0BbHc4FThLLtzlcFaFXIorwg==", + "requires": { + "fbjs": "^0.8.16", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.0" + } + }, + "react-dom": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.1.tgz", + "integrity": "sha512-1Gin+wghF/7gl4Cqcvr1DxFX2Osz7ugxSwl6gBqCMpdrxHjIFUS7GYxrFftZ9Ln44FHw0JxCFD9YtZsrbR5/4A==", + "requires": { + "fbjs": "^0.8.16", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.0" + } + }, + "react-event-listener": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.6.6.tgz", + "integrity": "sha512-+hCNqfy7o9wvO6UgjqFmBzARJS7qrNoda0VqzvOuioEpoEXKutiKuv92dSz6kP7rYLmyHPyYNLesi5t/aH1gfw==", + "requires": { + "@babel/runtime": "^7.2.0", + "prop-types": "^15.6.0", + "warning": "^4.0.1" + } + }, + "react-iframe": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/react-iframe/-/react-iframe-1.5.0.tgz", + "integrity": "sha512-hHPK0Os1iQIGD5YVM4N7DMZB9mcWHm+BmY+pSauuaX+NofilONnWUrVbCbrzy0gW6NkDW1ETAmUqlY4mrE9cxg==", + "requires": { + "object-assign": "^4.1.1", + "prop-types": "^15.6.x" + } + }, + "react-is": { + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.3.tgz", + "integrity": "sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA==" + }, + "react-jss": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz", + "integrity": "sha512-SH6XrJDJkAphp602J14JTy3puB2Zxz1FkM3bKVE8wON+va99jnUTKWnzGECb3NfIn9JPR5vHykge7K3/A747xQ==", + "requires": { + "hoist-non-react-statics": "^2.5.0", + "jss": "^9.7.0", + "jss-preset-default": "^4.3.0", + "prop-types": "^15.6.0", + "theming": "^1.3.0" + } + }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "react-redux": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.1.tgz", + "integrity": "sha512-LE7Ned+cv5qe7tMV5BPYkGQ5Lpg8gzgItK07c67yHvJ8t0iaD9kPFPAli/mYkiyJYrs2pJgExR2ZgsGqlrOApg==", + "requires": { + "@babel/runtime": "^7.1.2", + "hoist-non-react-statics": "^3.1.0", + "invariant": "^2.2.4", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.1", + "react-is": "^16.6.0", + "react-lifecycles-compat": "^3.0.0" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + } + } + } + }, + "react-split-pane": { + "version": "0.1.87", + "resolved": "https://registry.npmjs.org/react-split-pane/-/react-split-pane-0.1.87.tgz", + "integrity": "sha512-F22jqWyKB1WximT0U5HKdSuB9tmJGjjP+WUyveHxJJys3ANsljj163kCdsI6M3gdfyCVC+B2rq8sc5m2Ko02RA==", + "requires": { + "prop-types": "^15.5.10", + "react-lifecycles-compat": "^3.0.4", + "react-style-proptype": "^3.0.0" + } + }, + "react-style-proptype": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-style-proptype/-/react-style-proptype-3.2.2.tgz", + "integrity": "sha512-ywYLSjNkxKHiZOqNlso9PZByNEY+FTyh3C+7uuziK0xFXu9xzdyfHwg4S9iyiRRoPCR4k2LqaBBsWVmSBwCWYQ==", + "requires": { + "prop-types": "^15.5.4" + } + }, + "react-test-renderer": { + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.8.3.tgz", + "integrity": "sha512-rjJGYebduKNZH0k1bUivVrRLX04JfIQ0FKJLPK10TAb06XWhfi4gTobooF9K/DEFNW98iGac3OSxkfIJUN9Mdg==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "react-is": "^16.8.3", + "scheduler": "^0.13.3" + } + }, + "react-tooltip": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.10.0.tgz", + "integrity": "sha512-GGdxJvM1zSFztkTP7gCQbLTstWr1OOoMpJ5WZUGhimj0nhRY+MPz+92MpEnKmj0cftJ9Pd/M6FfSl0sfzmZWkg==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, + "react-transition-group": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz", + "integrity": "sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==", + "requires": { + "dom-helpers": "^3.3.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + } + } + }, + "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" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "recast": { + "version": "0.11.23", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz", + "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=", + "dev": true, + "requires": { + "ast-types": "0.9.6", + "esprima": "~3.1.0", + "private": "~0.1.5", + "source-map": "~0.5.0" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + } + } + }, + "recompose": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.28.2.tgz", + "integrity": "sha512-baVNKQBQAAAuLRnv6Cb/6/j59a1BVj6c6Pags1KXVyRB0yPfQVUZtuAUnqHDBXoR8iXPrLGWE4RNtCQ/AaRP3g==", + "requires": { + "@babel/runtime": "7.0.0-beta.56", + "change-emitter": "^0.1.2", + "fbjs": "^0.8.1", + "hoist-non-react-statics": "^2.3.1", + "react-lifecycles-compat": "^3.0.2", + "symbol-observable": "^1.0.4" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.0.0-beta.56", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.56.tgz", + "integrity": "sha512-vP9XV2VP013UEyZdU9eWClCsm6rQPUYHVNCfmpcv5uKviW7mKmUZq71Y5cr5dYsFKfnGDxSo8h6plUGR60lwHg==", + "requires": { + "regenerator-runtime": "^0.12.0" + } + }, + "regenerator-runtime": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz", + "integrity": "sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg==" + } + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "dev": true, + "requires": { + "balanced-match": "^0.4.2", + "math-expression-evaluator": "^1.2.14", + "reduce-function-call": "^1.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + } + } + }, + "reduce-function-call": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", + "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "dev": true, + "requires": { + "balanced-match": "^0.4.2" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + } + } + }, + "redux": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.1.tgz", + "integrity": "sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, + "redux-thunk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz", + "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==" + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz", + "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.1.tgz", + "integrity": "sha512-5KzMIyPLvfdPmvsdlYsHqITrDfK9k7bmvf97HvHSN4810i254ponbxCQ1NukpRWlu6en2MBWzAlhDExEKISwAA==", + "dev": true + }, + "regenerator-transform": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.4.tgz", + "integrity": "sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp-tree": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.5.tgz", + "integrity": "sha512-nUmxvfJyAODw+0B13hj8CFVAxhe7fDEAgJgaotBu3nnR+IgGgZq59YedJP5VYTlkEfqjuK6TuRpnymKdatLZfQ==", + "dev": true + }, + "regexpu-core": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.4.0.tgz", + "integrity": "sha512-eDDWElbwwI3K0Lo6CqbQbA6FwgtCz4kYTarrri1okfkRLZAqstU+B3voZBCjg8Fl6iq0gXrJG6MvRgLthfvgOA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^7.0.0", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.0.2" + } + }, + "registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remove-array-items": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/remove-array-items/-/remove-array-items-1.1.1.tgz", + "integrity": "sha512-MXW/jtHyl5F1PZI7NbpS8SOtympdLuF20aoWJT5lELR1p/HJDd5nqW8Eu9uLh/hCRY3FgvrIT5AwDCgBODklcA==", + "dev": true + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "renderkid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz", + "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "strip-ansi": "^3.0.0", + "utila": "^0.4.0" + }, + "dependencies": { + "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" + } + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "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==", + "dev": true, + "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": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "tough-cookie": { + "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==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "request-promise-native": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", + "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", + "dev": true, + "requires": { + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "reselect": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz", + "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==" + }, + "resolve": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-path": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz", + "integrity": "sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=", + "dev": true, + "requires": { + "http-errors": "~1.6.2", + "path-is-absolute": "1.0.1" + }, + "dependencies": { + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "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" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rmwc": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/rmwc/-/rmwc-4.0.6.tgz", + "integrity": "sha512-sX+fFZakR5E9yFsqwZFh89D9EobljWbiFlVRLG6KtffYgVdblyp5GivjzWygoRYB61uGqyMHJZgslNvHLyelog==", + "requires": { + "@rmwc/base": "^4.0.6", + "@rmwc/button": "^4.0.6", + "@rmwc/card": "^4.0.6", + "@rmwc/checkbox": "^4.0.6", + "@rmwc/chip": "^4.0.6", + "@rmwc/circular-progress": "^4.0.6", + "@rmwc/data-table": "^4.0.6", + "@rmwc/dialog": "^4.0.6", + "@rmwc/drawer": "^4.0.6", + "@rmwc/elevation": "^4.0.6", + "@rmwc/fab": "^4.0.6", + "@rmwc/floating-label": "^4.0.6", + "@rmwc/formfield": "^4.0.6", + "@rmwc/grid": "^4.0.6", + "@rmwc/grid-list": "^4.0.6", + "@rmwc/icon": "^4.0.6", + "@rmwc/icon-button": "^4.0.6", + "@rmwc/image-list": "^4.0.6", + "@rmwc/line-ripple": "^4.0.6", + "@rmwc/linear-progress": "^4.0.6", + "@rmwc/list": "^4.0.6", + "@rmwc/menu": "^4.0.6", + "@rmwc/notched-outline": "^4.0.6", + "@rmwc/provider": "^4.0.6", + "@rmwc/radio": "^4.0.6", + "@rmwc/ripple": "^4.0.6", + "@rmwc/select": "^4.0.6", + "@rmwc/slider": "^4.0.6", + "@rmwc/snackbar": "^4.0.6", + "@rmwc/switch": "^4.0.6", + "@rmwc/tabs": "^4.0.6", + "@rmwc/textfield": "^4.0.6", + "@rmwc/theme": "^4.0.6", + "@rmwc/toolbar": "^4.0.6", + "@rmwc/top-app-bar": "^4.0.6", + "@rmwc/typography": "^4.0.6", + "material-components-web": "~0.41.0" + }, + "dependencies": { + "@material/animation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-0.41.0.tgz", + "integrity": "sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==" + }, + "@material/auto-init": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-0.41.0.tgz", + "integrity": "sha512-jp6L8MpYu7DudgDfA8iTyD9BwQrYPEDsIJGbqzN9vcCBl5FoBatkB8pcFXKr+1mRBk7T1Qmf6+H5nDtxyXjHEQ==" + }, + "@material/base": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-0.41.0.tgz", + "integrity": "sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==" + }, + "@material/button": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/button/-/button-0.41.0.tgz", + "integrity": "sha512-9mA/7P8yD3YPJ8ijwu0oOiT65OCa8Km3M9OF6VAsBE+XJS9Wo5hWDMgkv16raeOFeXj+1ALsjvuTz31JdcSkgQ==", + "requires": { + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/card": { + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/@material/card/-/card-0.41.1.tgz", + "integrity": "sha512-0L3BkkHK9qRXNh9MOK4XkCYHmZcqwLK5gACIWSLDOjEefmifBeahJeDJSYLVHS9KWl43glIGSrpNGjyXs19mCQ==", + "requires": { + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/checkbox": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-0.41.0.tgz", + "integrity": "sha512-Zz6e5WRpziO7Z+4rbEs8GHNNBf1UuttniLp6/RvwPSQRaD8G04sdg4HcP/aDCY1KGMwivkuDPc2Bsgs6j+rD7Q==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/chips": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/chips/-/chips-0.41.0.tgz", + "integrity": "sha512-Z2q01n4JdRR2f2fdYNCftmgu0M8wu8PZUeQTK3e3zVkQyRdmXcbqMbLHRawVWuXORC8/mIA6tuTtOEqle/Qj9w==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/checkbox": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/dialog": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-0.41.0.tgz", + "integrity": "sha512-IhRMGTr/41/D0lhagvshCtzI4d9+ynE7FFjpQXc6GU81pHHGt0eYt5vQl3Z/DsatOCdBd+Nc3YDTyJX8OA+8CQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/dom": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0", + "focus-trap": "^2.3.0" + } + }, + "@material/drawer": { + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-0.41.1.tgz", + "integrity": "sha512-4t9ARGaIg8jpXIqD8hy4kcZ0hsF7y25gk2jNQAYG8ukQuDgbenjydlNFnC+I/eWBVIKqnVBlens+4ZUns+n3hg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/list": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0", + "focus-trap": "^3.0.0" + }, + "dependencies": { + "focus-trap": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-3.0.0.tgz", + "integrity": "sha512-jTFblf0tLWbleGjj2JZsAKbgtZTdL1uC48L8FcmSDl4c2vDoU4NycN1kgV5vJhuq1mxNFkw7uWZ1JAGlINWvyw==", + "requires": { + "tabbable": "^3.1.0", + "xtend": "^4.0.1" + } + } + } + }, + "@material/elevation": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-0.41.0.tgz", + "integrity": "sha512-ZtZS8z5ie9c7Cx5PVudgSorGYa0C3lu3dA+Nn6qJdhGUokl01msh54NfNuwk+EZsk65bNRRqw1Td/63TCbKIzg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/fab": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/fab/-/fab-0.41.0.tgz", + "integrity": "sha512-SY/XhkFqlbT8byz0wVJF6vPoGQQRwcTpA7toK1WexW87tSme8KE17yAGJxsZYzIOOFZqW1xF+aDajWdaWyDZdQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/floating-label": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-0.41.0.tgz", + "integrity": "sha512-qI6f1nZU3crXxWAI9fw3U5fHw2qOzEor49EvskbcaV5KSRW5qO+jtfUQ3ib/Vhki7lqhgwNHB/0n7KYhvhjRHQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/form-field": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-0.41.0.tgz", + "integrity": "sha512-vNduTfxS1KHCt/NATfX56m7iSXqcemrDq3NMX0txijUQyZ3Sr4xdUQdys+2ky/rBuQTVqBBsc9ixIyHehECaoQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/grid-list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/grid-list/-/grid-list-0.41.0.tgz", + "integrity": "sha512-vs0UyvfswW/nyPAoYLRIWEvMmfZUSKVOUSTnHC+PsZ5aXTwGCiCdUugMZdQVhPp9NkxW5mqmCCVroD5eH/yd4g==", + "requires": { + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/icon-button": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-0.41.0.tgz", + "integrity": "sha512-RzGSH97aUcTW4he+uU8ahT75DEn6+29L0hH4PBKe03/R/qHFfOrWfjfd03PPiCkaT5SNkPkt1YnfEPqKolnH1Q==", + "requires": { + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/icon-toggle": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/icon-toggle/-/icon-toggle-0.41.0.tgz", + "integrity": "sha512-kNB5mRwCtppNYqcMWZM1vbCymjiWTaWFMGrVSMy++y0a6BU1YAJSnDyw+8Yr0PINGcU5+ecwEYdNsaY8K83enw==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/image-list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-0.41.0.tgz", + "integrity": "sha512-j3V51PYdfhHB6CWfy076BYT4jHJMqQ86zOpv2OtsjexDc3JPQImB/v/+y018tyDCGOuwjWLoCUi+szTbtzCeQA==", + "requires": { + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/layout-grid": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-0.41.0.tgz", + "integrity": "sha512-Sa5RNoTGgfIojqJ9E94p7/k11V6q/tGk7HwKi4AQNAPjxield0zcl3G/SbsSb8YSHoK+D+7OXDN+n11x6EqF7g==" + }, + "@material/line-ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-0.41.0.tgz", + "integrity": "sha512-5DDIoC3d78fCLhNgle7DRFojT3D2SF+XVpUd3g6yLZmybHB7832p4bgl/qGpbIXwk1wAQA1dkUgKH5foxorjNQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/linear-progress": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-0.41.0.tgz", + "integrity": "sha512-yWnJK58QfovYNJXANGfKWcyC5k9IqBFvygYa2EYQSH/MZbIvd84+MIn0fJO9xsRza79BA8Xh2tFIdTFy4+2Ctg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/list": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-0.41.0.tgz", + "integrity": "sha512-HhYN0I02CTT8j91c1eeeI+L2KXVKdfzj0Zuapp2SdeCmQZLJO2tu2NYj0W6REBDTVBWBccr12Sn8o71CodEScQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/dom": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/menu": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-0.41.0.tgz", + "integrity": "sha512-w8UFEnTWzOWl1hRx06tFBqAY4I0vYmbDIVwxO8g1CIgQkfG2dIXjJUfVvlYf9NzZ0VOyyKMh69MmMA5KP+HgAw==", + "requires": { + "@material/base": "^0.41.0", + "@material/list": "^0.41.0", + "@material/menu-surface": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1" + } + }, + "@material/notched-outline": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-0.41.0.tgz", + "integrity": "sha512-nQBkOXvkd5G9FeJ9UuecZh88WRgTsnGVvfj7UFJZEkvkzZwLBGUiJS6fF9FYraih3ZFgmphdbJxXEd9af3cqyQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/radio": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/radio/-/radio-0.41.0.tgz", + "integrity": "sha512-nJvVVu2x2lAttUNnJczpZzKWK+3lEw/BOYsSLVSYp1qUlIQsOfQ6aItI7URokbLkQDqDqlsNmvGP5JJv/Cpksw==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/ripple": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-0.41.0.tgz", + "integrity": "sha512-rxEUVWM4AByDlTCH0kkthZQmUuY6eeN0X6cOHBoioFN2vUDk0D0Nfzz/N9FF2AlAf8C2lDDLrTuqnJPVIn+NHA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/rtl": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-0.40.1.tgz", + "integrity": "sha512-Pk6Iw1/KrhWZoZtkDsPMDUW0bm7Z1zeXb3MTQRCFmjf1wU5cRxgOTtuoZLcJqlcKGppLAzJL/TJV3E7KEiuL0A==" + }, + "@material/select": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/select/-/select-0.41.0.tgz", + "integrity": "sha512-MAU/EHGT1QmBlDvvKI1X7M0ua9w8RqP0UjDMkFxhyfA9tv7ZBS7u/z2/GBb9DUzFu2rKu9DCQ5B+GLBglukfAg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/floating-label": "^0.41.0", + "@material/line-ripple": "^0.41.0", + "@material/menu": "^0.41.0", + "@material/menu-surface": "^0.41.0", + "@material/notched-outline": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/selection-control": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/selection-control/-/selection-control-0.41.0.tgz", + "integrity": "sha512-rRHGiZVPoP4nxAAoeqsgTsxz9GwInGs7HIlEhPfMFygmSZVUHHsuOJXSTpOKYi8GCoKHpB0RKZsAtxM0BYAelw==", + "requires": { + "@material/ripple": "^0.41.0" + } + }, + "@material/shape": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-0.41.0.tgz", + "integrity": "sha512-k1K3CjOVxclfb/0r28cOa2oJpP7QMA2fP0SOS3Vh8ale5Q2jkaHTL60KX8VkHvV6rMqShpXW+60gPjoz5XRbDQ==" + }, + "@material/slider": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/slider/-/slider-0.41.0.tgz", + "integrity": "sha512-u+riWFMeEiczu9bv+Am+28ICX6ba8S55Z+c5JUFtegZNILC76DAuYe++jy0huZw4j/RJXq8hDtj4wJQwvaFTyw==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/snackbar": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-0.41.0.tgz", + "integrity": "sha512-z44BspVFD4B3p651sF0sHYCdQXNdPJR/MkHkrHT8bXnEql7B8qpBsGRKgnPzm1kbAjG5jPkdbbwhbH04WR/0IQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/switch": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/switch/-/switch-0.41.0.tgz", + "integrity": "sha512-8YTrn1oisUhp6DlB1XAPeFWVr5nD88jlq9FoTVQOtGaUxaEybQD0nrsYI7OwaVm4HvSnepd2zmMvbjXKbQX4XQ==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/selection-control": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/tab": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/tab/-/tab-0.41.0.tgz", + "integrity": "sha512-yM6eYD8Kgrk2cHa+zN3GYIK4Mt6EsSxDIpaArE6JopqRpalULjiOk83hWVPR1V95xphnzYAWM1YF6I6JexE9kw==", + "requires": { + "@material/base": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/tab-indicator": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/tab-bar": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-0.41.0.tgz", + "integrity": "sha512-RL+0CA4ZeZAmhz3vlyFsm8h9sLim8JHTLkosfZSYRnx2o9iQHQHpV58jz76ZSWG+0iuDoHFnwZ2oNKNmImn0KQ==", + "requires": { + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/tab": "^0.41.0", + "@material/tab-scroller": "^0.41.0" + } + }, + "@material/tab-indicator": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-0.41.0.tgz", + "integrity": "sha512-IBJEO+O8OnFVgRAn4CCGccpyNPF1bvTp5+1foD46S2u7XZLD7ejfxTQhqE5HYWtVLQ3zk1aYo3+N9+oSUkpM2w==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/theme": "^0.41.0" + } + }, + "@material/tab-scroller": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-0.41.0.tgz", + "integrity": "sha512-dyxaxLLSiDigIUVJ0BwqnKBtBseALrOhmPgvk6BQVDbynnRQ2bOvaNZ7cbpe3A0i8zOQGOoTZF4i9D38/iubcg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/tab": "^0.41.0" + } + }, + "@material/textfield": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-0.41.0.tgz", + "integrity": "sha512-kJ52W2gxOS2xfpreVhvHQ1u3UkiDl58duw9HkhEkK5Oi1bSDOtbnlWy0pGTOiAma5ZQgetPNgoa+T0zMBptfnw==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/floating-label": "^0.41.0", + "@material/line-ripple": "^0.41.0", + "@material/notched-outline": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/theme": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-0.41.0.tgz", + "integrity": "sha512-ohW2JxObKOWvP34EkIIcrEVtL3g0Gs/T3/MdOsM36euyshY8Jwl1f6fjVUQvVjSpixUtSb30/+ulblF8fTOwBg==" + }, + "@material/toolbar": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/toolbar/-/toolbar-0.41.0.tgz", + "integrity": "sha512-fAZSGM9xyVNI8FI92kmmvNCV4fzEWJBd1q9qMOqbna5AVtbJRNlGSY5HNgEi0vHi/nmY3UXD+VvDbLgoTXtdGg==", + "requires": { + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/top-app-bar": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-0.41.0.tgz", + "integrity": "sha512-U3MK6pdzyfXC3zttsrEYihzR7aRqnKM3w2MWRwI0iub/lFygVOSa4qQfaJhwjz9TTyxB8tdtZOXBpEVDsH+xmA==", + "requires": { + "@material/animation": "^0.41.0", + "@material/base": "^0.41.0", + "@material/elevation": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/shape": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "@material/typography": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-0.41.0.tgz", + "integrity": "sha512-15dlqSU+9uGcWdg4KXXcmDzTKJPb7/5Z9kmooONb2Laot1uiuntDXQS0yL+U2FYLW5Ros+WVMosDBKFruWx68A==" + }, + "material-components-web": { + "version": "0.41.1", + "resolved": "https://registry.npmjs.org/material-components-web/-/material-components-web-0.41.1.tgz", + "integrity": "sha512-/LGHx4GlGeQz7oYWGNU6OJ3lkDSZs7J+2B9jdIkRmTdvAuHJwiZzeDWAywo5s9IOmg2OSmAOdUCcoAkoagYFKg==", + "requires": { + "@material/animation": "^0.41.0", + "@material/auto-init": "^0.41.0", + "@material/base": "^0.41.0", + "@material/button": "^0.41.0", + "@material/card": "^0.41.1", + "@material/checkbox": "^0.41.0", + "@material/chips": "^0.41.0", + "@material/dialog": "^0.41.0", + "@material/dom": "^0.41.0", + "@material/drawer": "^0.41.1", + "@material/elevation": "^0.41.0", + "@material/fab": "^0.41.0", + "@material/floating-label": "^0.41.0", + "@material/form-field": "^0.41.0", + "@material/grid-list": "^0.41.0", + "@material/icon-button": "^0.41.0", + "@material/icon-toggle": "^0.41.0", + "@material/image-list": "^0.41.0", + "@material/layout-grid": "^0.41.0", + "@material/line-ripple": "^0.41.0", + "@material/linear-progress": "^0.41.0", + "@material/list": "^0.41.0", + "@material/menu": "^0.41.0", + "@material/menu-surface": "^0.41.0", + "@material/notched-outline": "^0.41.0", + "@material/radio": "^0.41.0", + "@material/ripple": "^0.41.0", + "@material/rtl": "^0.40.1", + "@material/select": "^0.41.0", + "@material/selection-control": "^0.41.0", + "@material/shape": "^0.41.0", + "@material/slider": "^0.41.0", + "@material/snackbar": "^0.41.0", + "@material/switch": "^0.41.0", + "@material/tab": "^0.41.0", + "@material/tab-bar": "^0.41.0", + "@material/tab-indicator": "^0.41.0", + "@material/tab-scroller": "^0.41.0", + "@material/textfield": "^0.41.0", + "@material/theme": "^0.41.0", + "@material/toolbar": "^0.41.0", + "@material/top-app-bar": "^0.41.0", + "@material/typography": "^0.41.0" + } + }, + "tabbable": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-3.1.2.tgz", + "integrity": "sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==" + } + } + }, + "rst-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", + "integrity": "sha1-gbIw6i/MYGbInjRy3nlChdmwPZE=", + "dev": true, + "requires": { + "lodash.flattendeep": "^4.4.0", + "nearley": "^2.7.10" + } + }, + "rsvp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", + "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==", + "dev": true + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "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==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-3.1.0.tgz", + "integrity": "sha512-G5GClRRxT1cELXfdAq7UKtUsv8q/ZC5k8lQGmjEm4HcAl3HzBy68iglyNCmw4+0tiXPCBZntslHlRhbnsSws+Q==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "capture-exit": "^1.2.0", + "exec-sh": "^0.2.0", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.3", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5", + "watch": "~0.18.0" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "dev": true, + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.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" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.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" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + } + } + }, + "sass-loader": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-6.0.7.tgz", + "integrity": "sha512-JoiyD00Yo1o61OJsoP2s2kb19L1/Y2p3QFcCdWdF6oomBGKVYuZyqHWemRBfQ2uGYsk+CH3eCguXNfpjzlcpaA==", + "dev": true, + "requires": { + "clone-deep": "^2.0.1", + "loader-utils": "^1.0.1", + "lodash.tail": "^4.1.1", + "neo-async": "^2.5.0", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "scheduler": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.3.tgz", + "integrity": "sha512-UxN5QRYWtpR1egNWzJcVLk8jlegxAugswQc984lD3kU7NuobsO37/sRfbpTdBjtnD5TBNFA2Q2oLV5+UmPSmEQ==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", + "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "^5.0.3" + } + }, + "serialize-javascript": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.6.1.tgz", + "integrity": "sha512-A5MOagrPFga4YaKQSWHryl7AXvbQkEqpw4NNYMTNYUNV51bA8ABHgYFpqKx+YFFrw59xMV1qGH1R4AgoNIVgCw==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "dev": true, + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sisteransi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz", + "integrity": "sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "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 + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "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==", + "dev": true, + "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" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trim": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", + "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.0", + "function-bind": "^1.0.2" + } + }, + "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" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, + "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" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "style-loader": { + "version": "0.20.3", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.20.3.tgz", + "integrity": "sha512-2I7AVP73MvK33U7B9TKlYZAqdROyMXDYSMvHLX43qy3GCOaJNiV6i0v/sv9idWIaQ42Yn2dNv79Q5mKXbKhAZg==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "schema-utils": "^0.4.5" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "dev": true, + "requires": { + "coa": "~1.0.1", + "colors": "~1.1.2", + "csso": "~2.3.1", + "js-yaml": "~3.7.0", + "mkdirp": "~0.5.1", + "sax": "~1.2.1", + "whet.extend": "~0.9.9" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^2.6.0" + } + } + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, + "symbol-tree": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true + }, + "tabbable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-1.1.3.tgz", + "integrity": "sha512-nOWwx35/JuDI4ONuF0ZTo6lYvI0fY0tZCH1ErzY2EXfu4az50ZyiUX8X073FLiZtmWUVlkRnuXsehjJgCw9tYg==" + }, + "tapable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.1.tgz", + "integrity": "sha512-9I2ydhj8Z9veORCw5PRm4u9uebCn0mcCa6scWoNcbZ6dAtoo2618u9UUzxgmsCOreJpqDDuv61LvwofW7hLcBA==", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.2", + "inherits": "2" + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "^0.7.0" + } + }, + "terser": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz", + "integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==", + "dev": true, + "requires": { + "commander": "~2.17.1", + "source-map": "~0.6.1", + "source-map-support": "~0.5.9" + }, + "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 + }, + "source-map-support": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", + "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "terser-webpack-plugin": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.3.tgz", + "integrity": "sha512-GOK7q85oAb/5kE12fMuLdn2btOS9OBZn4VsecpHDywoUC/jLhSAKOiYo0ezx7ss2EXPMzyEWFoE0s1WLE+4+oA==", + "dev": true, + "requires": { + "cacache": "^11.0.2", + "find-cache-dir": "^2.0.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "terser": "^3.16.1", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "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 + } + } + }, + "test-exclude": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", + "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^1.0.1" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "theming": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/theming/-/theming-1.3.0.tgz", + "integrity": "sha512-ya5Ef7XDGbTPBv5ENTwrwkPUexrlPeiAg/EI9kdlUAZhNlRbCdhMKRgjNX1IcmsmiPcqDQZE6BpSaH+cr31FKw==", + "requires": { + "brcast": "^3.0.1", + "is-function": "^1.0.1", + "is-plain-object": "^2.0.1", + "prop-types": "^15.5.8" + } + }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "time-fix-plugin": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/time-fix-plugin/-/time-fix-plugin-2.0.5.tgz", + "integrity": "sha512-veHRiEsQ50KSrfdhkZiFvZIjRoyfyfxpgskD+P7uVQAcNe6rIMLZ8vhjFRE2XrPqQdy+4CF+jXsWAlgVy9Bfcg==", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", + "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + } + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "toposort": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz", + "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "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 + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "dev": true, + "requires": { + "glob": "^7.1.2" + } + }, + "tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "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" + } + }, + "type-is": { + "version": "1.6.16", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.18" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.19", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", + "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" + }, + "uglify-js": { + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", + "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", + "dev": true, + "requires": { + "commander": "~2.17.1", + "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 + } + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz", + "integrity": "sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz", + "integrity": "sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", + "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "dev": true + }, + "update-notifier": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "dev": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "url-join": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-3.0.0.tgz", + "integrity": "sha1-JugROs4ZXqMND8OBhuRUAPnOpnI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + }, + "v8-compile-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz", + "integrity": "sha512-1wFuMUIM16MDJRCrpbpuEPTUGmM5QMUg0cr3KFwra2XgOgFcPGDQHDh3CszSCD2Zewc/dh/pamNEW8CbfDebUw==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "vendors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", + "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vis": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/vis/-/vis-4.21.0.tgz", + "integrity": "sha1-3XFji/9/ZJXQC8n0DCU1JhM97Ws=", + "requires": { + "emitter-component": "^1.1.1", + "hammerjs": "^2.0.8", + "keycharm": "^0.2.0", + "moment": "^2.18.1", + "propagating-hammerjs": "^1.4.6" + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "watch": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", + "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", + "dev": true, + "requires": { + "exec-sh": "^0.2.0", + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "webpack": { + "version": "4.29.5", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.5.tgz", + "integrity": "sha512-DuWlYUT982c7XVHodrLO9quFbNpVq5FNxLrMUfYUTlgKW0+yPimynYf1kttSQpEneAL1FH3P3OLNgkyImx8qIQ==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.3", + "@webassemblyjs/helper-module-context": "1.8.3", + "@webassemblyjs/wasm-edit": "1.8.3", + "@webassemblyjs/wasm-parser": "1.8.3", + "acorn": "^6.0.5", + "acorn-dynamic-import": "^4.0.0", + "ajv": "^6.1.0", + "ajv-keywords": "^3.1.0", + "chrome-trace-event": "^1.0.0", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.0", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.3.0", + "loader-utils": "^1.1.0", + "memory-fs": "~0.4.1", + "micromatch": "^3.1.8", + "mkdirp": "~0.5.0", + "neo-async": "^2.5.0", + "node-libs-browser": "^2.0.0", + "schema-utils": "^1.0.0", + "tapable": "^1.1.0", + "terser-webpack-plugin": "^1.1.0", + "watchpack": "^1.5.0", + "webpack-sources": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.0.tgz", + "integrity": "sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw==", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "webpack-cli": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.2.3.tgz", + "integrity": "sha512-Ik3SjV6uJtWIAN5jp5ZuBMWEAaP5E4V78XJ2nI+paFPh8v4HPSwo/myN0r29Xc/6ZKnd2IdrAlpSgNOu2CDQ6Q==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.0", + "findup-sync": "^2.0.0", + "global-modules": "^1.0.0", + "import-local": "^2.0.0", + "interpret": "^1.1.0", + "loader-utils": "^1.1.0", + "supports-color": "^5.5.0", + "v8-compile-cache": "^2.0.2", + "yargs": "^12.0.4" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.6.0.tgz", + "integrity": "sha512-oeXA3m+5gbYbDBGo4SvKpAHJJEGMoekUbHgo1RK7CP1sz7/WOSeu/dWJtSTk+rzDCLkPwQhGocgIq6lQqOyOwg==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.3.1", + "range-parser": "^1.0.3", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + } + } + } + }, + "webpack-hot-client": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/webpack-hot-client/-/webpack-hot-client-2.2.2.tgz", + "integrity": "sha512-AYpr6H11QqY630Ze87F+SYi23ZnuaE7rnHD+amupepc+7Z5nLJHMwb6Q8d6PNhr+DiidBYT3MWFHcUQngbS1xQ==", + "dev": true, + "requires": { + "json-stringify-safe": "^5.0.1", + "loglevelnext": "^1.0.2", + "uuid": "^3.1.0", + "webpack-log": "^1.1.1", + "ws": "^4.0.0" + }, + "dependencies": { + "ws": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.1.0.tgz", + "integrity": "sha512-ZGh/8kF9rrRNffkLFV4AzhvooEclrOH0xaugmqGsIfFgOE/pIz4fMc4Ef+5HSQqTEug2S9JZIWDR47duDSLfaA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0" + } + } + } + }, + "webpack-log": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz", + "integrity": "sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA==", + "dev": true, + "requires": { + "chalk": "^2.1.0", + "log-symbols": "^2.1.0", + "loglevelnext": "^1.0.1", + "uuid": "^3.1.0" + } + }, + "webpack-serve": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/webpack-serve/-/webpack-serve-0.3.2.tgz", + "integrity": "sha512-R6F62hsgAC0hwYiNvNsNzgzjS98Id2OxnY7k3x2LcFgzMNv0qZvwm8c3vBl2R5+NK7r0Zy2805838B9JjN+s+g==", + "dev": true, + "requires": { + "@shellscape/koa-static": "^4.0.4", + "chalk": "^2.3.0", + "clipboardy": "^1.2.2", + "cosmiconfig": "^4.0.0", + "debug": "^3.1.0", + "find-up": "^2.1.0", + "get-port": "^3.2.0", + "import-local": "^1.0.0", + "killable": "^1.0.0", + "koa": "^2.4.1", + "koa-webpack": "^3.0.1", + "lodash": "^4.17.5", + "loud-rejection": "^1.6.0", + "meow": "^4.0.0", + "nanobus": "^4.3.1", + "opn": "^5.1.0", + "resolve": "^1.6.0", + "time-fix-plugin": "^2.0.0", + "update-notifier": "^2.3.0", + "url-join": "3.0.0", + "v8-compile-cache": "^1.1.0", + "webpack-hot-client": "^2.2.0", + "webpack-log": "^1.1.2" + }, + "dependencies": { + "camelcase-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + } + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "map-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", + "dev": true + }, + "meow": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", + "dev": true, + "requires": { + "camelcase-keys": "^4.0.0", + "decamelize-keys": "^1.0.0", + "loud-rejection": "^1.0.0", + "minimist": "^1.1.3", + "minimist-options": "^3.0.1", + "normalize-package-data": "^2.3.4", + "read-pkg-up": "^3.0.0", + "redent": "^2.0.0", + "trim-newlines": "^2.0.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "redent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz", + "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=", + "dev": true, + "requires": { + "indent-string": "^3.0.0", + "strip-indent": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=", + "dev": true + }, + "trim-newlines": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz", + "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=", + "dev": true + }, + "v8-compile-cache": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz", + "integrity": "sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA==", + "dev": true + } + } + }, + "webpack-sources": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", + "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "dev": true, + "requires": { + "source-list-map": "^2.0.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 + } + } + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", + "dev": true + }, + "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" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "worker-farm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", + "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.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" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.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" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", + "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "requires": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + } + }, + "yargs": { + "version": "12.0.5", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", + "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "dev": true, + "requires": { + "cliui": "^4.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^1.0.1", + "os-locale": "^3.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1 || ^4.0.0", + "yargs-parser": "^11.1.1" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", + "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", + "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", + "dev": true + } + } + }, + "yargs-parser": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", + "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", + "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", + "dev": true + } + } + }, + "ylru": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz", + "integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==", + "dev": true + } + } +} diff --git a/js-apps/meep-frontend/package.json b/js-apps/meep-frontend/package.json new file mode 100644 index 0000000000000000000000000000000000000000..97472b4b6b4341fc4ea9357739f20303771b40ff --- /dev/null +++ b/js-apps/meep-frontend/package.json @@ -0,0 +1,78 @@ +{ + "name": "meep-controller-web-ui-js", + "version": "1.0.0", + "description": "", + "private": true, + "scripts": { + "test": "jest", + "test:verbose": "jest --verbose true", + "test:coverage": "jest --verbose true --coverage --colors", + "build": "webpack", + "build:dev": "webpack-serve --port 8091 --host 10.3.16.136" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@babel/core": "^7.2.0", + "@babel/preset-env": "^7.2.0", + "@babel/preset-react": "^7.0.0", + "babel-core": "^7.0.0-bridge.0", + "babel-jest": "^24.1.0", + "babel-loader": "^8.0.4", + "css-loader": "^0.28.11", + "enzyme": "^3.9.0", + "enzyme-adapter-react-16": "^1.10.0", + "enzyme-to-json": "^3.3.5", + "extract-loader": "^2.0.1", + "extract-text-webpack-plugin": "^4.0.0-beta.0", + "file-loader": "^1.1.11", + "html-loader": "^0.5.5", + "html-webpack-plugin": "^3.2.0", + "jest": "^24.1.0", + "node-sass": "^4.8.3", + "regenerator-runtime": "^0.13.1", + "sass-loader": "^6.0.7", + "style-loader": "^0.20.3", + "webpack": "^4.4.1", + "webpack-cli": "^3.2.3", + "webpack-serve": "^0.3.1" + }, + "dependencies": { + "@material-ui/core": "^1.5.1", + "@material-ui/icons": "^1.1.1", + "axios": "^0.18.0", + "classnames": "2.2.6", + "jquery": "3.3.1", + "lodash": "^4.17.11", + "material-components-web": "0.38.1", + "material-design-icons": "3.0.1", + "prop-types": "15.6.2", + "react": "16.4.1", + "react-dom": "16.4.1", + "react-iframe": "^1.5.0", + "react-redux": "^5.1.1", + "react-split-pane": "^0.1.87", + "react-tooltip": "^3.10.0", + "redux": "^4.0.1", + "redux-thunk": "^2.3.0", + "reselect": "^4.0.0", + "rmwc": "^4.0.1", + "vis": "4.21.0", + "warning": "^4.0.1", + "yamljs": "0.3.0" + }, + "jest": { + "setupFilesAfterEnv": [ + "/test/setup/setupEnzyme.js" + ], + "roots": [ + "test" + ], + "testPathIgnorePatterns": [ + "/test/setup/" + ], + "collectCoverageFrom": [ + "src/**/*.{js,jsx}" + ] + } +} diff --git a/js-apps/meep-frontend/src/.eslintignore b/js-apps/meep-frontend/src/.eslintignore new file mode 100644 index 0000000000000000000000000000000000000000..baea8769f3410a7740ee783a34f5699d9d9d5eaf --- /dev/null +++ b/js-apps/meep-frontend/src/.eslintignore @@ -0,0 +1,6 @@ +# path/to/project/root/.eslintignore +# /node_modules/* and /bower_components/* in the project root are ignored by default + +# Ignore built files except build/index.js +dist/* + diff --git a/js-apps/meep-frontend/src/css/meep-controller.scss b/js-apps/meep-frontend/src/css/meep-controller.scss new file mode 100755 index 0000000000000000000000000000000000000000..0b8778400a74ab791ee103c7a327a459357b2a8b --- /dev/null +++ b/js-apps/meep-frontend/src/css/meep-controller.scss @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +// Set IDCC color theme +$mdc-theme-primary: #379DD8; +$mdc-theme-secondary: #FF9800; +$mdc-theme-background: #FFFFFF; + +// Set default margin to 0px +$mdc-layout-grid-default-margin: ( + desktop: 0px, + tablet: 16px, + phone: 16px +); + +// Set default gutter to 10px +$mdc-layout-grid-default-gutter: ( + desktop: 10px, + tablet: 16px, + phone: 16px +) !default; + +@import "material-components-web/material-components-web"; + +// Ensure layout covers the entire screen + +html { + height: 100%; +} +select { + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; +} + +#meep-container { + width: 100%; +} + +// UI +#meep-container { + width: 100%; +} +.ui-body { + display: flex; + flex-direction: row; + padding: 0; + margin: 0; + box-sizing: border-box; + height: 100%; + width: 100%; + background-color: #FCFCFC; +} +.ui-content { + flex-direction: column; + flex-grow: 1; + height: 100%; + box-sizing: border-box; +} +.ui-main { + padding: 16px; +} +.component-style { + background-color: #FFFFFF; +} + + +// Visualization +.vis-network-placeholder { + text-align: center; + display: inline-block; + vertical-align: middle; +} +.vis-network-div { + display:inline-block; + width:100%; + height:60vh; + margin-top: 10px; + background-color: #FFFFFF; +} +#vis-report { + display:inline-block; + width:200px; + vertical-align:top; +} + +// Element configuration +.cfg-network-element-div { + height:60vh; +} + +// Navigation +#idcc-toolbar { + @include mdc-top-app-bar-ink-color(#fff); +} +// #idcc-logo { +// height: 40px; +// width: 40px; +// padding-top: 4px; +// padding-bottom: 4px; +// } +#idcc-title { + font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif; + font-size: 22px; +} + +#cfg-vis-network-container { + padding: 10; +}; +// #file-export-ta-div { +// margin-top: 10px; +// } +#page-operate { + display: none; +} + + + +#refresh-interval-form-div { + display: inline-block; + vertical-align: middle; + padding-left: 16px; +} + +// Monitoring +#idcc-monitoring-iframe { + height: 80vh; + width: 100%; + border-style: none; +} + +// IDCC Styles +.idcc-button { + @include mdc-button-ink-color(#fff); +} +.idcc-margin-top { + margin-top: 10px; +} +.idcc-margin-left { + margin-left: 20px; +} +.idcc-elevated-area { + margin-bottom: 10px; + padding: 10px; +} +.idcc-fullwidth { + width: 100%; +} + +#new-element-error-message { + color: firebrick; +} + +// Under construction logo +.construction-div-img { + height: 50px; + vertical-align: middle; +} diff --git a/js-apps/meep-frontend/src/img/AdvantEDGE-logo-NoTagline_White_RGB.png b/js-apps/meep-frontend/src/img/AdvantEDGE-logo-NoTagline_White_RGB.png new file mode 100644 index 0000000000000000000000000000000000000000..7130a29dd039c283ef3e921a795199c9d0cb3bd7 Binary files /dev/null and b/js-apps/meep-frontend/src/img/AdvantEDGE-logo-NoTagline_White_RGB.png differ diff --git a/js-apps/meep-frontend/src/img/Gear-01-idcc.svg b/js-apps/meep-frontend/src/img/Gear-01-idcc.svg new file mode 100644 index 0000000000000000000000000000000000000000..113eee4922e9874f4d0c03ab83ec1f2b5ce15eef --- /dev/null +++ b/js-apps/meep-frontend/src/img/Gear-01-idcc.svg @@ -0,0 +1,91 @@ + + + +image/svg+xml + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/demo1/bin/demo-server/static/img/ID-Icon-01-idcc.svg b/js-apps/meep-frontend/src/img/ID-Icon-01-idcc.svg similarity index 100% rename from examples/demo1/bin/demo-server/static/img/ID-Icon-01-idcc.svg rename to js-apps/meep-frontend/src/img/ID-Icon-01-idcc.svg diff --git a/bin/meep-ctrl-engine/static/img/Screen-02-idcc.svg b/js-apps/meep-frontend/src/img/Screen-02-idcc.svg similarity index 100% rename from bin/meep-ctrl-engine/static/img/Screen-02-idcc.svg rename to js-apps/meep-frontend/src/img/Screen-02-idcc.svg diff --git a/bin/meep-ctrl-engine/static/img/cloud-black.svg b/js-apps/meep-frontend/src/img/cloud-black.svg similarity index 100% rename from bin/meep-ctrl-engine/static/img/cloud-black.svg rename to js-apps/meep-frontend/src/img/cloud-black.svg diff --git a/bin/meep-ctrl-engine/static/img/cloud-blue.svg b/js-apps/meep-frontend/src/img/cloud-blue.svg similarity index 100% rename from bin/meep-ctrl-engine/static/img/cloud-blue.svg rename to js-apps/meep-frontend/src/img/cloud-blue.svg diff --git a/bin/meep-ctrl-engine/static/img/cloud-outline-black.svg b/js-apps/meep-frontend/src/img/cloud-outline-black.svg similarity index 100% rename from bin/meep-ctrl-engine/static/img/cloud-outline-black.svg rename to js-apps/meep-frontend/src/img/cloud-outline-black.svg diff --git a/bin/meep-ctrl-engine/static/img/cloud-server-black-blue.svg b/js-apps/meep-frontend/src/img/cloud-server-black-blue.svg old mode 100644 new mode 100755 similarity index 100% rename from bin/meep-ctrl-engine/static/img/cloud-server-black-blue.svg rename to js-apps/meep-frontend/src/img/cloud-server-black-blue.svg diff --git a/bin/meep-ctrl-engine/static/img/cloud-server-black.svg b/js-apps/meep-frontend/src/img/cloud-server-black.svg old mode 100644 new mode 100755 similarity index 100% rename from bin/meep-ctrl-engine/static/img/cloud-server-black.svg rename to js-apps/meep-frontend/src/img/cloud-server-black.svg diff --git a/bin/meep-ctrl-engine/static/img/cloud-server-grey-blue.svg b/js-apps/meep-frontend/src/img/cloud-server-grey-blue.svg old mode 100644 new mode 100755 similarity index 100% rename from bin/meep-ctrl-engine/static/img/cloud-server-grey-blue.svg rename to js-apps/meep-frontend/src/img/cloud-server-grey-blue.svg diff --git a/bin/meep-ctrl-engine/static/img/cloud-server-orange.svg b/js-apps/meep-frontend/src/img/cloud-server-orange.svg old mode 100644 new mode 100755 similarity index 100% rename from bin/meep-ctrl-engine/static/img/cloud-server-orange.svg rename to js-apps/meep-frontend/src/img/cloud-server-orange.svg diff --git a/bin/meep-ctrl-engine/static/img/drone-black.svg b/js-apps/meep-frontend/src/img/drone-black.svg old mode 100644 new mode 100755 similarity index 100% rename from bin/meep-ctrl-engine/static/img/drone-black.svg rename to js-apps/meep-frontend/src/img/drone-black.svg diff --git a/bin/meep-ctrl-engine/static/img/drone-blue.svg b/js-apps/meep-frontend/src/img/drone-blue.svg old mode 100644 new mode 100755 similarity index 100% rename from bin/meep-ctrl-engine/static/img/drone-blue.svg rename to js-apps/meep-frontend/src/img/drone-blue.svg diff --git a/bin/meep-ctrl-engine/static/img/edge-idcc.svg b/js-apps/meep-frontend/src/img/edge-idcc.svg similarity index 100% rename from bin/meep-ctrl-engine/static/img/edge-idcc.svg rename to js-apps/meep-frontend/src/img/edge-idcc.svg diff --git a/bin/meep-ctrl-engine/static/img/fog-idcc.svg b/js-apps/meep-frontend/src/img/fog-idcc.svg similarity index 100% rename from bin/meep-ctrl-engine/static/img/fog-idcc.svg rename to js-apps/meep-frontend/src/img/fog-idcc.svg diff --git a/bin/meep-ctrl-engine/static/img/green-led.png b/js-apps/meep-frontend/src/img/green-led.png similarity index 100% rename from bin/meep-ctrl-engine/static/img/green-led.png rename to js-apps/meep-frontend/src/img/green-led.png diff --git a/bin/meep-ctrl-engine/static/img/red-led.png b/js-apps/meep-frontend/src/img/red-led.png similarity index 100% rename from bin/meep-ctrl-engine/static/img/red-led.png rename to js-apps/meep-frontend/src/img/red-led.png diff --git a/js-apps/meep-frontend/src/img/switch-black.svg b/js-apps/meep-frontend/src/img/switch-black.svg new file mode 100644 index 0000000000000000000000000000000000000000..9fe4a6153d237243b33b63f96de884159f23e050 --- /dev/null +++ b/js-apps/meep-frontend/src/img/switch-black.svg @@ -0,0 +1,161 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/bin/meep-ctrl-engine/static/img/switch-blue.svg b/js-apps/meep-frontend/src/img/switch-blue.svg similarity index 100% rename from bin/meep-ctrl-engine/static/img/switch-blue.svg rename to js-apps/meep-frontend/src/img/switch-blue.svg diff --git a/bin/meep-ctrl-engine/static/img/tower-02-idcc.svg b/js-apps/meep-frontend/src/img/tower-02-idcc.svg similarity index 100% rename from bin/meep-ctrl-engine/static/img/tower-02-idcc.svg rename to js-apps/meep-frontend/src/img/tower-02-idcc.svg diff --git a/js-apps/meep-frontend/src/img/tower-04-idcc.svg b/js-apps/meep-frontend/src/img/tower-04-idcc.svg new file mode 100644 index 0000000000000000000000000000000000000000..d04d4ffb4d9219d59aa2ae64753f956bf9581d48 --- /dev/null +++ b/js-apps/meep-frontend/src/img/tower-04-idcc.svg @@ -0,0 +1,194 @@ + + + +image/svg+xml + + + + + + + + + + + \ No newline at end of file diff --git a/bin/meep-ctrl-engine/static/index.html b/js-apps/meep-frontend/src/index.html old mode 100644 new mode 100755 similarity index 72% rename from bin/meep-ctrl-engine/static/index.html rename to js-apps/meep-frontend/src/index.html index 2be7b8162b6a9bcc62987abd0ec8593023359ce9..9b2cfca27d11d55517e07aed443d31ae86ab6589 --- a/bin/meep-ctrl-engine/static/index.html +++ b/js-apps/meep-frontend/src/index.html @@ -1,3 +1,11 @@ + @@ -11,9 +19,9 @@ - +
    - + diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-confirm-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-confirm-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..801ab00597d940c70ad16bc9b72b42dbc5e1dd1b --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-confirm-dialog.js @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React, { Component } from 'react'; + +import IDDialog from './id-dialog'; +import { MEEP_DLG_CONFIRM } from '../../meep-constants'; + +class IDConfirmDialog extends Component { + + constructor(props) { + super(props); + this.state={}; + } + + render() { + return ( + this.props.onSubmit()} + cydata={MEEP_DLG_CONFIRM} + > + {`Are you sure you want to ${this.props.title.toLowerCase()}?`} + + ); + } +} + +const styles = { + text: { + color: 'gray' + } +}; + +export default IDConfirmDialog; diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-delete-scenario-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-delete-scenario-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..a4996763e29f294c5d526f9eaf96763a855e23e3 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-delete-scenario-dialog.js @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React, { Component } from 'react'; + +import IDDialog from './id-dialog'; +import { MEEP_DLG_DEL_SCENARIO } from '../../meep-constants'; + +class IDDeleteScenarioDialog extends Component { + + constructor(props) { + super(props); + this.state={}; + } + + render() { + return ( + + {'Are you sure you want to delete the current scenario from the MEEP Controller?'} + + ); + } +} + +const styles = { + text: { + color: 'gray' + } +}; + +export default IDDeleteScenarioDialog; diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-deploy-scenario-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-deploy-scenario-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..494461eb369d0825999ce30b4ecbe4fd5420f70d --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-deploy-scenario-dialog.js @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React, { Component } from 'react'; + +import IDDialog from './id-dialog'; +import IDSelect from '../helper-components/id-select'; +import { MEEP_DLG_DEPLOY_SCENARIO, MEEP_DLG_DEPLOY_SCENARIO_SELECT } from '../../meep-constants'; + +class IDDeployScenarioDialog extends Component { + + constructor(props) { + super(props); + this.state={ + selectedScenario: null + }; + } + + onDeployScenario() { + if (this.state.selectedScenario === '') { + // console.log('Invalid scenario name'); + // TODO: consider showing an alert + return; + } + this.props.api.activateScenario(this.state.selectedScenario, this.props.activateScenarioCb); + } + + render() { + return ( + {this.onDeployScenario();}} + cydata={MEEP_DLG_DEPLOY_SCENARIO} + > + { + this.setState({selectedScenario: e.target.value}); + } + } + cydata={MEEP_DLG_DEPLOY_SCENARIO_SELECT} + /> + + ); + } +} + +export default IDDeployScenarioDialog; + +// diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..ebded4c47239f6b7c2ce02cf1a8debb929196f22 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-dialog.js @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React from 'react'; +import { Grid, GridCell } from '@rmwc/grid'; + +import { + Dialog, + DialogTitle, + DialogContent, + DialogActions, + DialogButton +} from '@rmwc/dialog'; + +const IDDialog = (props) => { + return ( + { + props.onClose(); + }} + data-cy={props.cydata} + > + + + + {props.title} + + + + + + + + {props.children} + + + + + + + + + + + Cancel + + + + + props.onSubmit()} + disabled={props.okDisabled} + > + Ok + + + + + + + ); +}; + +const styles = { + title: { + paddingLeft:25, + paddingRight:25 + }, + content: { + paddingLeft:25, + paddingRight:30 + }, + actions: { + marginTop: 20 + }, + button: { + margin: 5 + } +}; + +export default IDDialog; diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-export-scenario-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-export-scenario-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..0c7554fc49ccf6639a4c5df250ebd3f511acc681 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-export-scenario-dialog.js @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React, { Component } from 'react'; +import { TextField, TextFieldHelperText } from '@rmwc/textfield'; +import * as YAML from 'yamljs'; + +import IDDialog from './id-dialog'; + +class IDExportScenarioDialog extends Component { + + constructor(props) { + super(props); + this.state={ + filename:null + }; + this.exportScenarioTextFile= ''; + } + + makeTextFile(text) { + var data = new Blob([text], {type: 'text/plain'}); + // If we are replacing a previously generated file we need to + // manually revoke the object URL to avoid memory leaks. + if (this.state.exportScenarioTextFile !== null) { + window.URL.revokeObjectURL(this.state.exportScenarioTextFile); + } + + this.exportScenarioTextFile = window.URL.createObjectURL(data); + + return this.exportScenarioTextFile; + } + + exportScenario() { + + if (this.state.filename === '') { + // console.log('Invalid file name provided'); + // TODO: consider showing an alert + return; + } + + var filename = (this.state.filename === null) ? this.props.scenarioName + '.yaml' : this.state.filename; + var link = document.getElementById('export-scenario-link'); + link.href = this.makeTextFile(YAML.stringify(this.props.scenario, 20, 4)); + // link.href = makeTextFile(JSON.stringify(meep.cfg.scenario, null, "\t")); + link.download = filename; + link.click(); + } + + render() { + + return ( + { + this.exportScenario(); + this.setState({filename: null, err: null}); + }} + okDisabled={this.state.err} + > + { + const val = e.target.value; + const err = (!val && val !== null) + ? 'Please enter a filename' + : ''; + this.setState({ + filename: val, + err: err + }); + } + } + value={this.state.filename === null ? this.props.scenarioName + '.yaml' : this.state.filename} + /> + + + {this.state.err} + + + + ); + } +} + +export default IDExportScenarioDialog; diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-new-scenario-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-new-scenario-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..d2425bb32e380d2f89409f22cad4c75b7dc2e39a --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-new-scenario-dialog.js @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React, { Component } from 'react'; +import { TextField, TextFieldHelperText } from '@rmwc/textfield'; + +import IDDialog from './id-dialog'; +import { MEEP_DLG_NEW_SCENARIO, MEEP_DLG_NEW_SCENARIO_NAME } from '../../meep-constants'; + +class IDNewScenarioDialog extends Component { + + constructor(props) { + super(props); + this.state={ + scenarioName: '', + err: null + }; + } + + changeScenarioName(name) { + var err = null; + + if (name) { + if (name.length > 20) { + err = 'Maximum 20 characters'; + } else if (!name.match(/^(([a-z0-9][-a-z0-9.]*)?[a-z0-9])+$/)) { + err = 'Lowercase alphanumeric or \'-\''; + } + } + + this.setState({scenarioName: name, err: err}); + } + + /** + * Callback function to receive the result of the getScenario operation. + * @callback module:api/ScenarioConfigurationApi~getScenarioCallback + * @param {String} error Error message, if any. + * @param {module:model/Scenario} data The data returned by the service call. + * @param {String} response The complete HTTP response. + */ + getScenarioNewCb(error/*, data, response*/) { + + if (error === null) { + // TODO: consider showing an alert + return; + } + + // Validate scenario name + if (this.state.scenarioName === '' || this.state.err !== null) { + // TODO: consider showing an alert + return; + } + + // Clear scenario + this.props.createScenario(this.state.scenarioName); + } + + render() { + return ( + { + this.props.api.getScenario(this.state.scenarioName, (error, data, response) => { + this.getScenarioNewCb(error, data, response); + }); + }} + cydata={MEEP_DLG_NEW_SCENARIO} + > + {this.changeScenarioName(e.target.value);}} + value={this.state.scenarioName} + invalid={(this.state.err) ? true : false} + data-cy={MEEP_DLG_NEW_SCENARIO_NAME} + /> + + + {this.state.err} + + + + ); + } +} + +export default IDNewScenarioDialog; diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-open-scenario-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-open-scenario-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..236b6ca78f973e1065fd3adfa49ed736029fcea1 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-open-scenario-dialog.js @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React, { Component } from 'react'; + +import IDDialog from './id-dialog'; +import IDSelect from '../helper-components/id-select'; +import { MEEP_DLG_OPEN_SCENARIO, MEEP_DLG_OPEN_SCENARIO_SELECT } from '../../meep-constants'; + +class IDOpenScenarioDialog extends Component { + + constructor(props) { + super(props); + this.state={ + selectedScenario: null + }; + } + + render() { + return ( + { + this.props.api.getScenario(this.state.selectedScenario, this.props.getScenarioLoadCb); + }} + cydata={MEEP_DLG_OPEN_SCENARIO} + > + { + this.setState({selectedScenario: e.target.value}); + } + } + cydata={MEEP_DLG_OPEN_SCENARIO_SELECT} + /> + + ); + } +} + +export default IDOpenScenarioDialog; diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-save-scenario-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-save-scenario-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..23235a9f628982f5b7ba7ab63b197a3a210b6725 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-save-scenario-dialog.js @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React, { Component } from 'react'; +import { TextField, TextFieldHelperText } from '@rmwc/textfield'; +import IDDialog from './id-dialog'; +import { MEEP_DLG_SAVE_SCENARIO } from '../../meep-constants'; + +class IDSaveScenarioDialog extends Component { + + constructor(props) { + super(props); + this.state={ + err: null, + scenarioName: null + }; + } + + changeScenarioName(name) { + var err = null; + + if (name) { + if (name.length > 20) { + err = 'Maximum 20 characters'; + } else if (!name.match(/^(([a-z0-9][-a-z0-9.]*)?[a-z0-9])+$/)) { + err = 'Lowercase alphanumeric or \'-\''; + } + } else { + err = 'Please enter a scenario name'; + } + + this.setState({ + scenarioName: name, + err: err + }); + } + + saveScenario() { + this.props.saveScenario(this.scenarioName()); + } + + scenarioName() { + return this.state.scenarioName === null ? this.props.scenarioName : this.state.scenarioName; + } + + render() { + return ( + this.saveScenario()} + okDisabled={(!this.state.scenarioName && this.props.scenarioNameRequired)|| this.state.err} + cydata={MEEP_DLG_SAVE_SCENARIO} + > + {'Store the scenario in the MEEP Controller (overwrites any existing scenario with the same name)'} + + this.changeScenarioName(e.target.value) + } + value={this.scenarioName()} + /> + + + {this.state.err} + + + + ); + } +} + +const styles = { + text: { + color: 'gray' + } +}; + +export default IDSaveScenarioDialog; diff --git a/js-apps/meep-frontend/src/js/components/dialogs/id-terminate-scenario-dialog.js b/js-apps/meep-frontend/src/js/components/dialogs/id-terminate-scenario-dialog.js new file mode 100644 index 0000000000000000000000000000000000000000..2f5e01accf336d4616c85d0106c455a1c94a59c9 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/dialogs/id-terminate-scenario-dialog.js @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React, { Component } from 'react'; + +import IDDialog from './id-dialog'; +import { MEEP_DLG_TERMINATE_SCENARIO } from '../../meep-constants'; + +class IDTerminateScenarioDialog extends Component { + + constructor(props) { + super(props); + this.state={}; + } + + render() { + return ( + this.props.onSubmit()} + cydata={MEEP_DLG_TERMINATE_SCENARIO} + > + {'Are you sure you want to terminate the deployed scenario?'} + + ); + } +} + +const styles = { + text: { + color: 'gray' + } +}; + +export default IDTerminateScenarioDialog; diff --git a/js-apps/meep-frontend/src/js/components/headline-bar.js b/js-apps/meep-frontend/src/js/components/headline-bar.js new file mode 100644 index 0000000000000000000000000000000000000000..5fb16bb081cd45191cf9b97946c4d9e35877d375 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/headline-bar.js @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React from 'react'; + +import { + NO_SCENARIO_NAME, + MEEP_LBL_SCENARIO_NAME +} from '../meep-constants'; + +const HeadlineBar = ({titleLabel, scenarioName}) => { + var name = (scenarioName === NO_SCENARIO_NAME) ? 'None' : scenarioName; + return ( +
    + {titleLabel}: + + {name} + +
    + ); +}; + +export default HeadlineBar; diff --git a/js-apps/meep-frontend/src/js/components/helper-components/cancel-apply-pair.js b/js-apps/meep-frontend/src/js/components/helper-components/cancel-apply-pair.js new file mode 100644 index 0000000000000000000000000000000000000000..937b3ce9dab56d2d3425473e2bd05fac8e964d3f --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/helper-components/cancel-apply-pair.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React from 'react'; +import { Grid, GridInner, GridCell } from '@rmwc/grid'; +import { Button } from '@rmwc/button'; +import { + MEEP_BTN_CANCEL, + MEEP_BTN_APPLY +} from '../../meep-constants'; + +const buttonStyles = { + marginRight: 10 +}; + +const CancelApplyPair = (props) => { + return ( + + + + + + + + + ); +}; + +export default CancelApplyPair; diff --git a/js-apps/meep-frontend/src/js/components/helper-components/id-select-row.js b/js-apps/meep-frontend/src/js/components/helper-components/id-select-row.js new file mode 100644 index 0000000000000000000000000000000000000000..5472e11ac5dfe6527a566997aeb3c203c49cb2c5 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/helper-components/id-select-row.js @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React from 'react'; +import { Grid, GridCell } from '@rmwc/grid'; +import IDSelect from './id-select'; + +const IDSelectRow = (props) => { + return ( + + + + + ); +}; + +export default IDSelectRow; diff --git a/js-apps/meep-frontend/src/js/components/helper-components/id-select.js b/js-apps/meep-frontend/src/js/components/helper-components/id-select.js new file mode 100644 index 0000000000000000000000000000000000000000..442ae81018f99bb5b6c5486c8877922e5c481667 --- /dev/null +++ b/js-apps/meep-frontend/src/js/components/helper-components/id-select.js @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React from 'react'; +import { Select } from '@rmwc/select'; +import { GridCell } from '@rmwc/grid'; + + +const IDSelect = (props) => { + return ( + + onUpdate(FIELD_PROTOCOL, event.target.value, null)} + data-cy={CFG_ELEM_PROT} + /> + + + ); +}; + +const CommandGroup = ({onUpdate, element}) => { + return ( + + + + + ); +}; + +const NCGroups = ({prefixes, onUpdate, element}) => { + return _.map(prefixes, p => { + return ( + + ); + }); +}; + +const UserChartFields = ({element, onUpdate}) => { + return ( + <> + + + + + ); +}; + +// Display element-specific form fields +const TypeRelatedFormFields = ({onUpdate, element}) => { + var type = getElemFieldVal(element, FIELD_TYPE); + var chartEnabled = getElemFieldVal(element, FIELD_CHART_ENABLED); + + switch (type) { + case ELEMENT_TYPE_SCENARIO: + return ( + + ); + case ELEMENT_TYPE_OPERATOR: + return ( + + ); + case ELEMENT_TYPE_ZONE: + return ( + + ); + case ELEMENT_TYPE_POA: + return ( + + ); + case ELEMENT_TYPE_UE_APP: + return ( + <> + onUpdate(FIELD_CHART_ENABLED, e.target.checked, null)} + data-cy={CFG_ELEM_CHART_CHECK} + > + User-Defined Chart + + {chartEnabled ? + + : + <> + + + + + } + + + ); + case ELEMENT_TYPE_EXT_UE_APP: + return ( + + ); + case ELEMENT_TYPE_CLOUD_APP: + case ELEMENT_TYPE_MECSVC: + return ( + <> + onUpdate(FIELD_CHART_ENABLED, e.target.checked, null)} + data-cy={CFG_ELEM_CHART_CHECK} + > + User-Defined Chart + + {chartEnabled ? + + : + <> + + + + + + } + + + ); + case ELEMENT_TYPE_EDGE_APP: + return ( + <> + onUpdate(FIELD_CHART_ENABLED, e.target.checked, null)} + data-cy={CFG_ELEM_CHART_CHECK} + > + User-Defined Chart + + {chartEnabled ? + + : + <> + + + + + + + } + + ); + + default: + return null; + } +}; + +const elementTypes = [ + { + label: 'Logical Domain', + options: [ + ELEMENT_TYPE_OPERATOR + ] + }, + { + label: 'Logical Zone', + options: [ + ELEMENT_TYPE_ZONE + ] + }, + { + label: 'Network Location', + options: [ + ELEMENT_TYPE_DC, + ELEMENT_TYPE_POA + ] + }, + { + label: 'Physical Location', + options: [ + ELEMENT_TYPE_UE, + ELEMENT_TYPE_FOG, + ELEMENT_TYPE_EDGE, + ELEMENT_TYPE_CN + ] + }, + { + label: 'Process', + options: [ + ELEMENT_TYPE_MECSVC, + ELEMENT_TYPE_EDGE_APP, + ELEMENT_TYPE_CLOUD_APP, + ELEMENT_TYPE_EXT_UE_APP, + ELEMENT_TYPE_UE_APP + ] + } +]; + +var parentTypes = {}; +parentTypes[ELEMENT_TYPE_SCENARIO] = null; +parentTypes[ELEMENT_TYPE_OPERATOR] = [ELEMENT_TYPE_SCENARIO]; +parentTypes[ELEMENT_TYPE_EDGE] = [ELEMENT_TYPE_ZONE]; +parentTypes[ELEMENT_TYPE_ZONE] = [ELEMENT_TYPE_OPERATOR]; +parentTypes[ELEMENT_TYPE_POA] = [ELEMENT_TYPE_ZONE]; +parentTypes[ELEMENT_TYPE_CN] = [ELEMENT_TYPE_ZONE]; +parentTypes[ELEMENT_TYPE_FOG] = [ELEMENT_TYPE_POA]; +parentTypes[ELEMENT_TYPE_UE] = [ELEMENT_TYPE_POA]; +parentTypes[ELEMENT_TYPE_DC] = [ELEMENT_TYPE_SCENARIO]; +parentTypes[ELEMENT_TYPE_UE_APP] = [ELEMENT_TYPE_UE]; +parentTypes[ELEMENT_TYPE_EXT_UE_APP] = [ELEMENT_TYPE_UE]; +parentTypes[ELEMENT_TYPE_MECSVC] = [ELEMENT_TYPE_FOG, ELEMENT_TYPE_EDGE, ELEMENT_TYPE_CN]; +parentTypes[ELEMENT_TYPE_EDGE_APP] = [ELEMENT_TYPE_FOG, ELEMENT_TYPE_EDGE]; +parentTypes[ELEMENT_TYPE_CLOUD_APP] = [ELEMENT_TYPE_DC]; + +const getParentTypes = (type) => { + return parentTypes[type]; +}; + +const buttonStyles = { + marginRight: 5 +}; + +const ElementCfgButtons = ({configuredElement, configMode, onNewElement, onDeleteElement}) => { + + const canCreateNewElement = () => { + return !configuredElement; + }; + + const canDeleteElement = () => { + return configuredElement && configMode === CFG_ELEM_MODE_EDIT; + }; + + return ( + <> + + + + + ); +}; + +const HeaderGroup = ({element, onTypeChange, onUpdate, disabled}) => { + var type = getElemFieldVal(element, FIELD_TYPE) || ''; + var parent = getElemFieldVal(element, FIELD_PARENT) || ''; + var parentElements = element.parentElements || [parent]; + + return ( + <> + + onTypeChange(elem.target.value)} + value={type} + disabled={disabled} + cydata={CFG_ELEM_TYPE} + /> + {type && + onUpdate(FIELD_PARENT, elem.target.value, null)} + value={parent} + disabled={disabled} + cydata={CFG_ELEM_PARENT} + /> + } + + + + + + ); +}; + +export class CfgNetworkElementContainer extends Component { + + constructor(props) { + super(props); + } + + // Element update handler + onUpdateElement(name, val, err) { + var updatedElem = updateObject({}, this.props.configuredElement); + setElemFieldVal(updatedElem, name, val); + setElemFieldErr(updatedElem, name, err); + + this.props.cfgElemUpdate(updatedElem); + } + + // Retrieve names of elements with matching type + elementsOfType(types) { + return _.chain(this.props.tableData) + .filter((e) => { + var elemType = getElemFieldVal(e, FIELD_TYPE); + return _.includes(types, elemType); + }) + .map((e) => { + return getElemFieldVal(e, FIELD_NAME); + }) + .value(); + } + + // Element configuration type change handler + onElementTypeChange(elementType) { + var elem = updateObject({}, this.props.configuredElement); + + setElemFieldVal(elem, FIELD_TYPE, elementType); + setElemFieldVal(elem, FIELD_PARENT, null); + setElemFieldVal(elem, FIELD_IS_EXTERNAL, (elementType === ELEMENT_TYPE_EXT_UE_APP) ? true : false); + + elem.parentElements = this.elementsOfType(getParentTypes(elementType)); + + this.props.cfgElemUpdate(elem); + } + + render() { + const element = this.props.configuredElement; + return ( +
    + + +
    + Element Configuration +
    +
    + + + + {this.props.onDeleteElement(element);}} + /> + + + +
    + + {element && + <> + {this.onElementTypeChange(type);}} + onUpdate={(name, val, err) => {this.onUpdateElement(name, val, err);}} + disabled={this.props.configMode === CFG_ELEM_MODE_EDIT} + /> + + {this.onUpdateElement(name, val, err);}} + /> + +
    + {this.props.errorMessage} +
    + + { + this.props.onSaveElement(element); + }} + /> + + } +
    + ); + } +} + +const styles = { + outer: { + padding: 10, + height: '100%' + }, + block: { + marginBottom: 20 + }, + field: { + marginBottom: 10 + }, + button: { + color: 'white' + }, + select: { + width: '100%' + } +}; + +const mapStateToProps = state => { + return { + tableData: state.cfg.table.entries, + configuredElement: state.cfg.elementConfiguration.configuredElement, + configMode: state.cfg.elementConfiguration.configurationMode, + errorMessage: state.cfg.elementConfiguration.errorMessage + }; +}; + +const mapDispatchToProps = dispatch => { + return { + cfgElemUpdate: (element) => dispatch(cfgElemUpdate(element)) + }; +}; + +const ConnectedCfgNetworkElementContainer = connect( + mapStateToProps, + mapDispatchToProps +)(CfgNetworkElementContainer); + +export default ConnectedCfgNetworkElementContainer; + diff --git a/js-apps/meep-frontend/src/js/containers/cfg/cfg-page-container.js b/js-apps/meep-frontend/src/js/containers/cfg/cfg-page-container.js new file mode 100644 index 0000000000000000000000000000000000000000..50b7781b12401c536a5532982d63cb2273499dc1 --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/cfg/cfg-page-container.js @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import _ from 'lodash'; +import { connect } from 'react-redux'; +import React, { Component } from 'react'; +import * as YAML from 'yamljs'; +import { Grid, GridCell, GridInner } from '@rmwc/grid'; +import { Elevation } from '@rmwc/elevation'; +import IDCVis from '../idc-vis'; +import CfgNetworkElementContainer from './cfg-network-element-container'; +import CfgPageScenarioButtons from './cfg-page-scenario-buttons'; + +import HeadlineBar from '../../components/headline-bar'; +import CfgTable from './cfg-table'; +import IDOpenScenarioDialog from '../../components/dialogs/id-open-scenario-dialog'; +import IDNewScenarioDialog from '../../components/dialogs/id-new-scenario-dialog'; +import IDSaveScenarioDialog from '../../components/dialogs/id-save-scenario-dialog'; +import IDDeleteScenarioDialog from '../../components/dialogs/id-delete-scenario-dialog'; +import IDExportScenarioDialog from '../../components/dialogs/id-export-scenario-dialog'; + +import { + cfgElemNew, + cfgElemEdit, + cfgElemClear, + cfgElemSetErrMsg, + cfgChangeScenario, + cfgChangeScenarioList, + cfgChangeState, + CFG_ELEM_MODE_NEW +} from '../../state/cfg'; + +import { + uiChangeCurrentDialog, + IDC_DIALOG_OPEN_SCENARIO, + IDC_DIALOG_NEW_SCENARIO, + IDC_DIALOG_SAVE_SCENARIO, + IDC_DIALOG_DELETE_SCENARIO, + IDC_DIALOG_EXPORT_SCENARIO, + PAGE_CONFIGURE +} from '../../state/ui'; + +import { + TYPE_CFG, + CFG_STATE_LOADED, + CFG_STATE_NEW, + CFG_STATE_IDLE, + ELEMENT_TYPE_SCENARIO +} from '../../meep-constants'; + +import { + FIELD_TYPE, + FIELD_PARENT, + FIELD_NAME, + FIELD_SVC_MAP, + FIELD_EXT_PORT, + + getElemFieldVal +} from '../../util/elem-utils'; + +import { + pipe, + filter +} from '../../util/functional'; + +const firstElementIfPresent = (val) => Array.isArray(val) ? (val.length ? val[0] : null) : val; +const notNull = x => x; +const extractPort = svcMapEntry => Number(firstElementIfPresent(svcMapEntry.split(':'))); + +const externalPorts = elem => { + return getElemFieldVal(elem, FIELD_SVC_MAP) + .split(',') + .map(extractPort) + .filter(notNull) + .concat([Number(getElemFieldVal(elem, FIELD_EXT_PORT))] + .filter(notNull)); +}; + +const hasExtPortsInCommon = elem1 => elem2 => { + const ports1 = externalPorts(elem1); + const ports2 = externalPorts(elem2); + const intersection = _.intersection(ports1, ports2); + return intersection.length; +}; + +const hasDifferentName = elem1 => elem2 => elem1.name.val !== elem2.name.val; + +class CfgPageContainer extends Component { + constructor(props) { + super(props); + } + + // ---------------------------------------- + // NETWORK ELEMENT CONFIGURATION + // ---------------------------------------- + + // NEW + onNewElement() { + this.props.cfgElemNew(); + } + + // EDIT + onEditElement(element) { + if (element !== null) { + this.props.cfgElemEdit(element); + } else { + this.props.cfgElemClear(); + } + } + + // SAVE + onSaveElement(element) { + + // Validate network element + if (this.validateNetworkElement(element) === false) { + return; + } + + // Add/update element in scenario + if (this.props.cfg.elementConfiguration.configurationMode === CFG_ELEM_MODE_NEW) { + this.props.newScenarioElem(element); + } else { + this.props.updateScenarioElem(element); + } + + // Reset Element configuration pane + this.props.cfgElemClear(); + } + + // DELETE + onDeleteElement(element) { + this.props.deleteScenarioElem(element); + this.props.cfgElemClear(); + } + + // CANCEL + onCancelElement() { + this.props.cfgElemClear(); + } + + findIndexByKeyValue(_array, key, value) { + for (var i = 0; i < _array.length; i++) { + if (getElemFieldVal(_array[i], key) === value) { + return i; + } + } + return -1; + } + + // Validate new network element form field entries + validateNetworkElement(element) { + var configMode = this.props.cfg.elementConfiguration.configurationMode; + var data = this.props.cfg.table.entries; + + // Clear previous error message + this.props.cfgElemSetErrMsg(''); + + // Verify that no field is in error + var fieldsInError=0; + _.forOwn(element, (val) => fieldsInError = val.err ? fieldsInError+1 : fieldsInError); + if (fieldsInError) { + this.props.cfgElemSetErrMsg(`${fieldsInError} fields in error`); + return false; + } + + // Verify element type + var type = getElemFieldVal(element, FIELD_TYPE); + if (type === null) { + this.props.cfgElemSetErrMsg('Missing element type'); + return false; + } + + // Check for valid & unique network element name (except if editing) + var name = getElemFieldVal(element, FIELD_NAME); + if (name === null || name === '') { + this.props.cfgElemSetErrMsg('Missing element name'); + return false; + } + if (configMode === CFG_ELEM_MODE_NEW && (this.findIndexByKeyValue(data, FIELD_NAME, name) !== -1)) { + this.props.cfgElemSetErrMsg('Element name already exists'); + return false; + } + + // Nothing else to validate for Scenario element + if (type === ELEMENT_TYPE_SCENARIO) { + return true; + } + + // Make sure parent exists + if (this.findIndexByKeyValue(data, FIELD_NAME, getElemFieldVal(element, FIELD_PARENT)) === -1) { + this.props.cfgElemSetErrMsg('Parent does not exist'); + return false; + } + + // TODO -- verify node port not already used + const extPorts = externalPorts(element); + + if (extPorts.length) { + + const elemsWithSameExtPort = pipe( + filter(hasDifferentName(element)), + filter(hasExtPortsInCommon(element)), + )(data); + + if (elemsWithSameExtPort.length) { + const elemNames = elemsWithSameExtPort.map(e => e.id); + this.props.cfgElemSetErrMsg(`External port already used in ${elemNames}`); + return false; + } + } + + + return true; + } + + // ---------------------------------------- + // SCENARIO CONFIGURATION + // ---------------------------------------- + + /** + * Callback function to receive the result of the getScenario operation. + * @callback module:api/ScenarioConfigurationApi~getScenarioCallback + * @param {String} error Error message, if any. + * @param {module:model/Scenario} data The data returned by the service call. + * @param {String} response The complete HTTP response. + */ + getScenarioLoadCb(error, data/*, response*/) { + if (error !== null) { + // TODO: consider showgina an alert + return; + } + + // Store & process loaded scenario + this.props.setScenario(data); + this.setPageState(CFG_STATE_LOADED); + } + + /** + * Callback function to receive the result of the getScenarioList operation. + * @callback module:api/ScenarioConfigurationApi~getScenarioListCallback + * @param {String} error Error message, if any. + * @param {module:model/ScenarioList} data The data returned by the service call. + * @param {String} response The complete HTTP response. + */ + getScenarioListLoadCb(error, data/*, response*/) { + if (error !== null) { + // TODO: consider showgina an alert + return; + } + if (!data.scenarios) { + return; + } + + this.props.changeScenarioList(_.map(data.scenarios, 'name')); + } + + /** + * Callback function to receive the result of the getScenario operation. + * @callback module:api/ScenarioConfigurationApi~getScenarioCallback + * @param {String} error Error message, if any. + * @param {module:model/Scenario} data The data returned by the service call. + * @param {String} response The complete HTTP response. + */ + getScenarioImportCb(error, /* data, response*/) { + // Update configuration page state based on whether scenario already exists + if (error === null) { + // TODO: consider showgina an alert + this.setPageState(CFG_STATE_LOADED); + } else { + this.setPageState(CFG_STATE_NEW); + } + } + + /** + * Callback function to receive the result of the createScenario operation. + * @callback module:api/ScenarioConfigurationApi~createScenarioCallback + * @param {String} error Error message, if any. + * @param data This operation does not return a value. + * @param {String} response The complete HTTP response. + */ + createScenarioCb(error, /*data, response*/) { + // Update configuration page state based on whether scenario was successfully created + if (error === null) { + // TODO: consider showgina an alert + this.setPageState(CFG_STATE_LOADED); + } else { + // TODO: consider showgina an alert + this.setPageState(CFG_STATE_NEW); + } + } + + /** + * Callback function to receive the result of the setScenario operation. + * @callback module:api/ScenarioConfigurationApi~setScenarioCallback + * @param {String} error Error message, if any. + * @param data This operation does not return a value. + * @param {String} response The complete HTTP response. + */ + setScenarioCb(error, /* data, response*/) { + // Update configuration page state based on whether scenario was successfully saved + if (error === null) { + // TODO: consider showgina an alert + this.setPageState(CFG_STATE_LOADED); + } else { + // TODO: consider showgina an alert + this.setPageState(CFG_STATE_NEW); + } + } + + /** + * Callback function to receive the result of the deleteScenario operation. + * @callback module:api/ScenarioConfigurationApi~deleteScenarioCallback + * @param {String} error Error message, if any. + * @param data This operation does not return a value. + * @param {String} response The complete HTTP response. + */ + deleteScenarioCb(error, /* data, response*/) { + if (error !== null) { + // TODO: consider showgina an alert + } + // TODO: consider showing an alert + + // Delete scenario + this.props.deleteScenario(); + this.setPageState(CFG_STATE_IDLE); + } + + // Update configuration page state + setPageState(state) { + this.props.changeState(state); + this.props.cfgElemClear(); + } + + // Create & Process new scenario + createScenario(name) { + this.props.createScenario(name); + this.setPageState(CFG_STATE_NEW); + } + + // Save currently configured scenario + saveScenario(name) { + var cfg = this.props.cfg; + + const scenarioName = name || cfg.scenario.name; + const scenarioCopy = JSON.parse(JSON.stringify(cfg.scenario)); + scenarioCopy.name = scenarioName; + + // Create new scenario if scenario is new + if (cfg.state === CFG_STATE_NEW || scenarioName !== cfg.scenario.name) { + this.props.api.createScenario(scenarioName, scenarioCopy, (error, data, response) => this.createScenarioCb(error, data, response)); + } else { + this.props.api.setScenario(scenarioName, scenarioCopy, (error, data, response) => this.setScenarioCb(error, data, response)); + } + + this.props.changeScenario(scenarioCopy); + } + + // Delete saved scenario + deleteScenario() { + var cfg = this.props.cfg; + + this.props.api.deleteScenario(cfg.scenario.name, (error, data, response) => this.deleteScenarioCb(error, data, response)); + } + + // CLOSE DIALOG + closeDialog() { + this.props.changeCurrentDialog(Math.random()); + } + + // SAVE SCENARIO DIALOG + onSaveScenario() { + this.props.changeCurrentDialog(IDC_DIALOG_SAVE_SCENARIO); + } + + // DELETE SCENARIO DIALOG + onDeleteScenario() { + this.props.changeCurrentDialog(IDC_DIALOG_DELETE_SCENARIO); + } + + // NEW SCENARIO DIALOG + onNewScenario() { + this.props.changeCurrentDialog(IDC_DIALOG_NEW_SCENARIO); + } + + // OPEN SCENARIO DIALOG + onOpenScenario() { + // Retrieve list of available scenarios + this.props.api.getScenarioList((error, data, response) => {this.getScenarioListLoadCb(error, data, response);}); + this.props.changeCurrentDialog(IDC_DIALOG_OPEN_SCENARIO); + } + + // EXPORT SCENARIO DIALOG + onExportScenario() { + this.props.changeCurrentDialog(IDC_DIALOG_EXPORT_SCENARIO); + } + + // IMPORT SCENARIO + onScenarioInputChange(elem) { + const props = this.props; + const self = this; + + if (elem.value) { + var reader = new FileReader(); + reader.onload = function (event) { + // Parse imported Scenario + var importedScenario; + try { + importedScenario = YAML.parse(event.target.result.replace(/\bNaN\b/g, 'null')); + // importedScenario = JSON.parse(event.target.result); + } catch(e) { + // TODO: consider showing an alert + return; + } + + // Store & Process imported scenario + props.setScenario(importedScenario); + + // Retrieve list of stored scenarios + props.api.getScenario(importedScenario.name, (error, data, response) => {self.getScenarioImportCb(error, data, response);}); + }; + reader.readAsText(elem.files[0]); + elem.value = null; + } + } + + renderDialogs() { + return ( + <> + {this.closeDialog();}} + api={this.props.api} + createScenario={(name) => this.createScenario(name)} + /> + + {this.closeDialog();}} + api={this.props.api} + scenarioName={this.props.scenarioName} + saveScenario={(name) => this.saveScenario(name)} + /> + + {this.closeDialog();}} + api={this.props.api} + getScenarioLoadCb={(error, data, response) => this.getScenarioLoadCb(error, data, response)} + /> + + {this.closeDialog();}} + api={this.props.api} + deleteScenario={() => this.deleteScenario()} + /> + + {this.closeDialog();}} + scenario={this.props.cfg.scenario} + scenarioName={this.props.scenarioName} + /> + + ); + } + + render() { + if (this.props.page !== PAGE_CONFIGURE) { + return null; + } + + return ( +
    + {this.renderDialogs()} + +
    + + + + + + + + + + + {this.onDeleteScenario();}} + onSaveScenario={() => {this.onSaveScenario();}} + onNewScenario={() => {this.onNewScenario();}} + onOpenScenario={() => {this.onOpenScenario();}} + onInputScenario={(elem) => this.onScenarioInputChange(elem)} + onExportScenario={() => this.onExportScenario()} + /> + + + + + + + +
    + + {this.props.cfgState !== CFG_STATE_IDLE && + <> + + + + +
    + this.onEditElement(elem)} + /> +
    +
    +
    + + + this.onNewElement()} + onSaveElement={(elem) => this.onSaveElement(elem)} + onDeleteElement={(elem) => this.onDeleteElement(elem)} + onCancelElement={() => this.onCancelElement()} + /> + + +
    +
    + +
    + this.onNewElement()} + onEditElement={(elem) => this.onEditElement(elem)} + onDeleteElement={() => this.onDeleteElement()} + /> +
    + + } +
    + ); + } +} + +const styles = { + headlineGrid: { + marginBottom: 10 + }, + headline: { + padding: 10 + }, + inner: { + height: '100%' + }, + page: { + height: '100%', + marginBottom: 10, + width: '100%', + marginRight: 100 + }, + cfgTable: { + marginTop: 20, + padding: 10 + } +}; + +const mapStateToProps = state => { + return { + cfg: state.cfg, + cfgState: state.cfg.state, + configuredElement: state.cfg.elementConfiguration.configuredElement, + table: state.cfg.table, + selectedElements: state.cfg.table.selected, + currentDialog: state.ui.currentDialog, + scenarios: state.cfg.apiResults.scenarios, + page: state.ui.page, + scenarioName: state.cfg.scenario.name + }; +}; + +const mapDispatchToProps = dispatch => { + return { + cfgElemNew: (elem) => dispatch(cfgElemNew(elem)), + cfgElemEdit: (elem) => dispatch(cfgElemEdit(elem)), + cfgElemClear: (elem) => dispatch(cfgElemClear(elem)), + cfgElemSetErrMsg: (msg) => dispatch(cfgElemSetErrMsg(msg)), + changeCurrentDialog: (type) => dispatch(uiChangeCurrentDialog(type)), + changeScenarioList: (scenarios) => dispatch(cfgChangeScenarioList(scenarios)), + changeState: (s) => dispatch(cfgChangeState(s)), + changeScenario: (scenario) => dispatch(cfgChangeScenario(scenario)) + }; +}; + +const ConnectedCfgPageContainer = connect( + mapStateToProps, + mapDispatchToProps +)(CfgPageContainer); + +export default ConnectedCfgPageContainer; + + diff --git a/js-apps/meep-frontend/src/js/containers/cfg/cfg-page-scenario-buttons.js b/js-apps/meep-frontend/src/js/containers/cfg/cfg-page-scenario-buttons.js new file mode 100644 index 0000000000000000000000000000000000000000..1812b630cfcb97b65261e565409e6d0051ac4d4c --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/cfg/cfg-page-scenario-buttons.js @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import { connect } from 'react-redux'; +import React, { Component } from 'react'; +import { Button } from '@rmwc/button'; +import { TextField } from '@rmwc/textfield'; + +import { + CFG_STATE_IDLE, + CFG_STATE_NEW, + CFG_STATE_LOADED, + CFG_BTN_NEW_SCENARIO, + CFG_BTN_OPEN_SCENARIO, + CFG_BTN_SAVE_SCENARIO, + CFG_BTN_DEL_SCENARIO, + CFG_BTN_IMP_SCENARIO, + CFG_BTN_EXP_SCENARIO +} from '../../meep-constants'; + + +class CfgPageScenarioButtons extends Component { + constructor(props) { + super(props); + } + + canCreateNewScenario() { + const cfgState = this.props.cfgState; + return this.props.cfgState === CFG_STATE_IDLE || cfgState === CFG_STATE_NEW || cfgState === CFG_STATE_LOADED; + } + + canOpenScenario() { + const cfgState = this.props.cfgState; + return cfgState === CFG_STATE_IDLE || cfgState === CFG_STATE_NEW || cfgState === CFG_STATE_LOADED; + } + + canSaveScenario() { + const cfgState = this.props.cfgState; + return cfgState === CFG_STATE_NEW || cfgState === CFG_STATE_LOADED; + } + + canDeleteScenario() { + const cfgState = this.props.cfgState; + return cfgState === CFG_STATE_LOADED; + } + + canImportScenario() { + const cfgState = this.props.cfgState; + return cfgState === CFG_STATE_IDLE || cfgState === CFG_STATE_NEW || cfgState === CFG_STATE_LOADED; + } + + canExportScenario() { + const cfgState = this.props.cfgState; + return cfgState === CFG_STATE_NEW || cfgState === CFG_STATE_LOADED; + } + + render() { + + const input = ( + this.inputElement = input} + onClick={() => this.props.onInputScenario(this.inputElement.input_)} + onChange={() => this.props.onInputScenario(this.inputElement.input_)} + style={{height: '0%', width: '0%', marginTop: -20, paddingTop: -20}} + /> + ); + return ( +
    + + + + + + {input} + + + + + + +
    + ); + } +} + +const buttonStyles = { + color: 'white', + marginRight: 5 +}; + +const mapStateToProps = state => { + return { + cfgTable: state.cfg.table, + execVis: state.exec.vis, + cfgVis: state.cfg.vis, + devMode: state.ui.devMode, + cfgState: state.cfg.state, + scenarioName: state.cfg.scenario.name + }; +}; + +const ConnectedCfgPageScenarioButtons = connect( + mapStateToProps, + null +)(CfgPageScenarioButtons); + +export default ConnectedCfgPageScenarioButtons; diff --git a/js-apps/meep-frontend/src/js/containers/cfg/cfg-table.js b/js-apps/meep-frontend/src/js/containers/cfg/cfg-table.js new file mode 100644 index 0000000000000000000000000000000000000000..28b6d9f04425630f6dc125449675e4f2baae95fc --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/cfg/cfg-table.js @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import PropTypes from 'prop-types'; +import { Elevation } from '@rmwc/elevation'; +import Table from '@material-ui/core/Table'; +import TableBody from '@material-ui/core/TableBody'; +import TableCell from '@material-ui/core/TableCell'; +import TableHead from '@material-ui/core/TableHead'; +import TablePagination from '@material-ui/core/TablePagination'; +import TableRow from '@material-ui/core/TableRow'; +import TableSortLabel from '@material-ui/core/TableSortLabel'; +import Paper from '@material-ui/core/Paper'; +import Tooltip from '@material-ui/core/Tooltip'; +import { Grid, GridCell } from '@rmwc/grid'; +import { withStyles } from '@material-ui/core/styles'; +import { connect } from 'react-redux'; +import React, { Component } from 'react'; + +import { updateObject } from '../../util/object-util'; + +import { + cfgChangeTable +} from '../../state/cfg'; + +import { + getSortingByField, + handleRequestSort, + handleChangePage, + handleChangeRowsPerPage, + isRowSelected +} from '../../util/table-utils'; + +import { + FIELD_TYPE, + FIELD_NAME, + FIELD_PARENT, + getElemFieldVal +} from '../../util/elem-utils'; + +// Network Element Cfg Styles & Table +const cfgTableStyles = theme => ({ + root: { + width: '100%', + marginTop: theme.spacing.unit * 3 + }, + table: { + minWidth: 1020 + }, + tableWrapper: { + overflowX: 'auto' + }, + tableHead: { + 'background-color': '#379DD8' + }, + tableHeadColor: { + color: '#FFFFFF' + } +}); + +const cfgTableColumnData = [ + { id: FIELD_NAME, numeric: false, disablePadding: false, label: 'NAME' }, + { id: FIELD_TYPE, numeric: false, disablePadding: false, label: 'TYPE' }, + { id: FIELD_PARENT, numeric: false, disablePadding: false, label: 'PARENT NODE' } +]; + +class CfgTable extends Component { + + constructor(props) { + super(props); + this.state = { + dismissibleOpen: true + }; + this.classes = props.classes; + } + + onRequestSort(event, property) { + var table = updateObject({}, this.props.table); + handleRequestSort(table, event, property); + this.props.changeTable(table); + } + + onClick(/*event, name*/) { + // var table = updateObject({}, this.props.table); + // handleClick(table, event, name); + // this.props.changeTable(table); + } + + onChangePage(event, page) { + var table = updateObject({}, this.props.table); + handleChangePage(table, event, page); + this.props.changeTable(table); + } + + onChangeRowsPerPage(event) { + var table = updateObject({}, this.props.table); + handleChangeRowsPerPage(table, event); + this.props.changeTable(table); + } + + render() { + const classes = this.classes; + const table = this.props.table; + const data = table.entries || []; + const order = table.order; + const orderBy = table.orderBy; + const rowsPerPage = table.rowsPerPage; + const page = table.page; + const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage); + + if (!data || data.length < 1) {return null;} + + return ( + <> + + + +
    + Network Elements +
    + +
    + + + + {cfgTableColumnData.map(column => { + return ( + + + this.onRequestSort(event, column.id)} + className={classes.tableHeadColor} + > + {column.label} + + + + ); + }, this)} + + + + {data.sort(getSortingByField(order, orderBy)) + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) + .map(elem => { + const name = getElemFieldVal(elem, FIELD_NAME); + const type = getElemFieldVal(elem, FIELD_TYPE); + const parent = getElemFieldVal(elem, FIELD_PARENT); + const isSelected = isRowSelected(table, name); + return ( + this.onClick(event, name)} + role="checkbox" + aria-checked={isSelected} + tabIndex={-1} + key={name} + selected={isSelected} + > + {name} + {type} + {parent} + + ); + })} + {emptyRows > 0 && ( + + + + )} + +
    +
    + this.onChangePage(event, page)} + onChangeRowsPerPage={event => this.onChangeRowsPerPage(event)} + /> +
    +
    +
    +
    + + ); + } +} + +const styles = { + cfgTable: { + marginTop: 20, + padding: 10 + } +}; + +CfgTable.propTypes = { + classes: PropTypes.object.isRequired +}; + +const mapStateToProps = (state) => { + return { + table: state.cfg.table + }; +}; + +const mapDispatchToProps = dispatch => { + return { + changeTable: (table) => dispatch(cfgChangeTable(table)) + }; +}; + +export default withStyles(cfgTableStyles)(connect(mapStateToProps, mapDispatchToProps)(CfgTable)); diff --git a/js-apps/meep-frontend/src/js/containers/exec/event-creation-pane.js b/js-apps/meep-frontend/src/js/containers/exec/event-creation-pane.js new file mode 100644 index 0000000000000000000000000000000000000000..a067c52049452daaf6b05649a1e7571c7015ea92 --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/exec/event-creation-pane.js @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import { connect } from 'react-redux'; +import React, { Component } from 'react'; +import { Select } from '@rmwc/select'; +import { Grid, GridCell } from '@rmwc/grid'; +import { Typography } from '@rmwc/typography'; +import { updateObject } from '../../util/object-util'; +import MobilityEventPane from './mobility-event-pane'; +import NetworkCharacteristicsEventPane from './network-characteristics-event-pane'; + +import { uiExecChangeCurrentEvent, UE_MOBILITY_EVENT, NETWORK_CHARACTERISTICS_EVENT } from '../../state/ui'; +import { + execChangeSelectedScenarioElement, + execUEs, + execPOAs +} from '../../state/exec'; + +import { + PAGE_EXECUTE +} from '../../state/ui'; + +import { + EXEC_EVT_TYPE +} from '../../meep-constants'; + +const EventTypeSelect = (props) => { + return ( + + + getElemFieldVal(elem, FIELD_NAME))} + onChange={(event)=>{this.values['eventTarget'] = event.target.value;}} + data-cy={EXEC_EVT_MOB_TARGET} + /> + + + + + + + { + var elem = this.firstElementMatchingType(event.target.value); + this.props.updateElement(elem); + this.setState({currentElementType: event.target.value}); + }} + data-cy={EXEC_EVT_NC_TYPE} + /> + + + + + + + + { + this.props.updateElement(this.getElementByName(event.target.value)); + }} + cydata={EXEC_EVT_NC_NAME} + /> + + + + + + {this.onUpdateElement(name, val, err);}} + parent={this} + element={element} + prefix={this.currentPrefix()} + /> + + {this.props.onClose();}} + onApply={(e) => this.triggerEvent(e)} + saveDisabled={!element.elementType || !this.props.element.name || nbErrors} + /> + + ); + } +} + +const styles = { + block: { + marginBottom: 20 + }, + field: { + marginBottom: 10 + }, + select: { + width: '100%' + } +}; + +export default NetworkCharacteristicsEventPane; diff --git a/js-apps/meep-frontend/src/js/containers/idc-vis.js b/js-apps/meep-frontend/src/js/containers/idc-vis.js new file mode 100644 index 0000000000000000000000000000000000000000..f92b11174a8947b4e7f4ca7b295c1289b17c1b14 --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/idc-vis.js @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import _ from 'lodash'; +import { connect } from 'react-redux'; +import React, { Component, createRef } from 'react'; +import ReactDOM from 'react-dom'; +import { Button } from '@rmwc/button'; +import * as vis from 'vis'; +import { updateObject } from '../util/object-util'; +import { execChangeTable, execChangeVis, execVisFilteredData } from '../state/exec'; +import { cfgChangeTable, cfgChangeVis, cfgElemEdit } from '../state/cfg'; + +import { + TYPE_CFG, + TYPE_EXEC +} from '../meep-constants'; + +import { + FIELD_NAME, + getElemFieldVal +} from '../util/elem-utils'; + +function createBoxGroup(groups, name, bgColor) { + groups[name] = { + borderWidth: 2, + font: { + color: '#ffffff', + size: 18, + face: 'verdana' + }, + shape: 'box', + size: 21, + color: { + background: bgColor, + border: '#000000' + }, + shadow: { + enabled: true, + color: 'rgba(0,0,0,0.5)', + x: 6, + y: 6 + } + }; +} + +// Create image group for setting visualization +function createImageGroup(groups, name) { + groups[name] = { + borderWidth: 0, + font: { + color: '#000000', + size: 18, + bold: true, + face: 'verdana' + }, + color: { + background: '#FFFFFF' + }, + shape: 'image', + shapeProperties: { + useBorderWithImage: true + } + }; +} + +// Set fixed to true for provided group +function setFixedGroup(group) { + group['fixed'] = { + x: true, + y: true + }; +} + +const visFilters = ['nodes', 'edges', 'layout', 'interaction', 'manipulation', 'physics']; + +class IDCVis extends Component { + + constructor(props) { + super(props); + this.state = {}; + + this.thisRef = createRef(); + this.configRef = createRef(); + } + + initializeVisualizationOptions(vis, container) { + + vis.options = { + //clickToUse:true, + configure: { + enabled: false, + filter: '', + container: container, + showButton: true + }, + layout: { + hierarchical: { + enabled: true, + levelSeparation: 320, + nodeSpacing: 130, + treeSpacing: 10, + parentCentralization: false, + direction: 'LR', + sortMethod: 'directed' + } + }, + interaction: { + hideEdgesOnDrag: true, + hover: true, + multiselect: true, + navigationButtons: true + }, + physics: { + enabled: false, + hierarchicalRepulsion: { + centralGravity: 0 + }, + minVelocity: 0.75, + solver: 'hierarchicalRepulsion' + }, + nodes: { + borderWidth: 2, + font: { + color: '#ffffff', + size: 18, + face: 'verdana' + }, + shape: 'box', + size: 21 + }, + edges: { + width: 2, + color: { + color: '#000000' + }, + font: { + color: '#000000', + background: '#FFFFFF', + size: 18, + face: 'verdana' + } + }, + groups: {} + }; + + var groups = vis.options.groups; + + // Scenario + createBoxGroup(groups, 'scenario', '#ffffff'); + groups.scenario.borderWidth = 4; + groups.scenario.font.color = '#000000'; + groups.scenario.font.size = 24; + createImageGroup(groups, 'scenarioImg'); + + // Domains + createBoxGroup(groups, 'domain', '#ff3620'); + createImageGroup(groups, 'domainImg'); + + // Zones + createBoxGroup(groups, 'zone', '#ffa032'); + createImageGroup(groups, 'zoneImg'); + + // Network locations + createBoxGroup(groups, 'nLocPoa', '#7f7f7f'); + setFixedGroup(groups.nLocPoa); + createImageGroup(groups, 'nLocPoaImg'); + setFixedGroup(groups.nLocPoaImg); + + // Physical locations + createBoxGroup(groups, 'pLocIntUE', '#1d8a5c'); + createImageGroup(groups, 'pLocIntUEImg'); + createBoxGroup(groups, 'pLocExtUE', '#373c42'); + createImageGroup(groups, 'pLocExtUEImg'); + createBoxGroup(groups, 'pLocIntFog', '#3ebcfb'); + createImageGroup(groups, 'pLocIntFogImg'); + createBoxGroup(groups, 'pLocExtFog', '#006af8'); + + createBoxGroup(groups, 'pLocIntEdge', '#3ebcfb'); + createImageGroup(groups, 'pLocIntEdgeImg'); + createBoxGroup(groups, 'pLocExtEdge', '#006af8'); + createBoxGroup(groups, 'pLocIntCN', '#ff69f9'); + createBoxGroup(groups, 'pLocExtCN', '#ff00f8'); + createBoxGroup(groups, 'pLocIntDC', '#939393'); + createImageGroup(groups, 'pLocIntDCImg'); + createBoxGroup(groups, 'pLocExtDC', '#252525'); + + // Processes + createBoxGroup(groups, 'procIntUEApp', '#d76a2f'); + createBoxGroup(groups, 'procExtUEApp', '#8e4721'); + createImageGroup(groups, 'procExtUEAppImg'); + createBoxGroup(groups, 'procIntEdgeApp', '#d76a2f'); + createBoxGroup(groups, 'procExtEdgeApp', '#8e4721'); + createBoxGroup(groups, 'procIntMecSvc', '#3ebcfb'); + createBoxGroup(groups, 'procExtMecSvc', '#006af8'); + createBoxGroup(groups, 'procIntCloudApp', '#000000'); + createBoxGroup(groups, 'procExtCloudApp', '#000000'); + } + + componentDidMount() { + + const newVis = updateObject({}, this.getVis()); + if (newVis.data.nodes.length < 1) { + newVis.data.nodes = [ + { + id: 'waiting', + label: 'Waiting for Scenario...', + title: 'Multi-Access Emulation Platform --- The MEEP AdvantEDGE!', + level: 0, + group: 'scenario' + } + ]; + newVis.data.edges = []; + } + + this.initializeVisualizationOptions(newVis, this.configRef.current); + + var domNode = ReactDOM.findDOMNode(this); + newVis.network = new vis.Network(domNode, (this.props.type === TYPE_CFG) ? newVis.data : this.props.execVisData, newVis.options); + + this.table = updateObject(this.getTable(), {data: newVis.data}); + this.changeVis(newVis); + this.changeTable(this.table); + + // Configuration Visualization handlers + if (this.props.type === TYPE_CFG) { + newVis.network.on('click', (obj) => { + if (!this.props.cfgVis.data.nodes.get) {return;} + // meep.cfg.vis.reportContainer.innerHTML = "x:" + obj.pointer.canvas.x + ", y:" + obj.pointer.canvas.y; + + var clickedNodes = this.props.cfgVis.data.nodes.get(obj.nodes); + + // Highlight selected nodes in table + const table = updateObject({}, this.props.cfgTable); + table.selected = []; + for (var i = 0; i < clickedNodes.length; i++) { + var clickedNode = clickedNodes[i]; + table.selected.push(clickedNode.id); + } + + this.changeTable(table); + + // Open first selected element in element configuration pane + if (this.props.type === TYPE_CFG) { + this.props.onEditElement((table.selected.length) ? this.getElementByName(table.entries, table.selected[0]) : null); + } + }); + } + } + + getElementByName(entries, name) { + for (var i = 0; i < entries.length; i++) { + if (getElemFieldVal(entries[i], FIELD_NAME) === name) { + return entries[i]; + } + } + return null; + } + + getTable() { + switch(this.props.type) { + case TYPE_CFG: + return this.props.cfgTable; + case TYPE_EXEC: + return this.props.execTable; + default: + return null; + } + } + + changeTable(table) { + switch(this.props.type) { + case TYPE_CFG: + this.props.changeCfgTable(table); + break; + case TYPE_EXEC: + this.props.changeExecTable(table); + break; + default: + break; + } + } + + changeVis(vis) { + switch(this.props.type) { + case TYPE_CFG: + this.props.changeCfgVis(vis); + break; + case TYPE_EXEC: + this.props.changeExecVis(vis); + break; + default: + break; + } + } + + getVis() { + switch(this.props.type) { + case TYPE_CFG: + return this.props.cfgVis; + case TYPE_EXEC: + return this.props.execVis; + default: + return null; + } + } + + // Toggle visualization controls + toggleConfig(filterStr) { + var vis = this.getVis(); + if (vis.showConfig === false || (vis.showConfig === true && vis.options.configure.filter === filterStr)) { + vis.showConfig = !vis.showConfig; + } + vis.options.configure.enabled = vis.showConfig; + vis.options.configure.filter = filterStr; + vis.network.setOptions(vis.options); + } + + updateConfigVisibility() { + var vis = this.getVis(); + if (vis.options.configure) { + vis.options.configure.enabled = this.props.devMode; + vis.network.setOptions(vis.options); + } + } + + render() { + this.updateConfigVisibility(); + return ( + <> +
    + Vis Component +
    +
    + {(this.props.devMode) ? + _.map(visFilters, (filter) => { + return ( + + ); + }) + : + null + } +
    +
    + + ); + } +} + +const buttonStyles = { + color: 'white', + marginRight: 5 +}; + +const mapStateToProps = state => { + return { + cfgTable: state.cfg.table, + execTable: state.exec.table, + execVis: state.exec.vis, + cfgVis: state.cfg.vis, + devMode: state.ui.devMode, + execVisData: execVisFilteredData(state) + }; +}; + +const mapDispatchToProps = dispatch => { + return { + changeExecTable: (table) => {dispatch(execChangeTable(table));}, + changeCfgTable: (table) => {dispatch(cfgChangeTable(table));}, + changeExecVis: (vis) => dispatch(execChangeVis(vis)), + changeCfgVis: (vis) => dispatch(cfgChangeVis(vis)), + changeCfgElement: (element) => dispatch(cfgElemEdit(element)) + }; +}; + +const ConnectedIDCVis = connect( + mapStateToProps, + mapDispatchToProps +)(IDCVis); + +export default ConnectedIDCVis; diff --git a/js-apps/meep-frontend/src/js/containers/meep-container.js b/js-apps/meep-frontend/src/js/containers/meep-container.js new file mode 100644 index 0000000000000000000000000000000000000000..38471582d529bf519cea2f5f9764b3607795fda0 --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/meep-container.js @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import _ from 'lodash'; +import { connect } from 'react-redux'; +import React, { Component } from 'react'; +import axios from 'axios'; +import { updateObject } from '../util/object-util'; + +// Import JS dependencies +import * as meepCtrlRestApiClient from '../../../../../js-packages/meep-ctrl-engine-client/src/index.js'; + +import MeepDrawer from './meep-drawer'; +import MeepTopBar from '../components/meep-top-bar'; +import CfgPageContainer from './cfg/cfg-page-container'; +import ExecPageContainer from './exec/exec-page-container'; +import SettingsPageContainer from './settings/settings-page-container'; +import MonitorPageContainer from './monitor/monitor-page-container'; + +import { + TYPE_CFG, + TYPE_EXEC, + EXEC_STATE_DEPLOYED, + NO_SCENARIO_NAME +} from '../meep-constants'; + +import { + parseScenario, + createNewScenario, + addElementToScenario, + updateElementInScenario, + removeElementFromScenario +} from '../util/scenario-utils'; + +import { + uiChangeCurrentPage, + uiExecChangeEventCreationMode, + uiToggleMainDrawer +} from '../state/ui'; + +import { + execChangeScenario, + execChangeScenarioState, + execChangeScenarioPodsPhases, + execChangeServiceMaps, + execChangeVisData, + execChangeTable, + execChangeCorePodsPhases, + execChangeOkToTerminate, + corePodsRunning, + corePodsErrors, + execVisFilteredData +} from '../state/exec'; + +import { + cfgChangeScenario, + cfgChangeVisData, + cfgChangeTable +} from '../state/cfg'; + +import { + PAGE_CONFIGURE, + PAGE_EXECUTE, + PAGE_MONITOR, + PAGE_SETTINGS +} from '../state/ui'; + +// MEEP Controller REST API JS client +var basepath = 'http://' + location.host + location.pathname + 'v1'; +// var basepath = 'http://10.3.16.73:30000/v1'; + +meepCtrlRestApiClient.ApiClient.instance.basePath = basepath.replace(/\/+$/, ''); + +class MeepContainer extends Component { + constructor(props) { + super(props); + this.state = {}; + this.refreshIntervalTimer = null; + this.meepSettingsApi = new meepCtrlRestApiClient.MEEPSettingsApi(); + this.meepCfgApi = new meepCtrlRestApiClient.ScenarioConfigurationApi(); + this.meepExecApi = new meepCtrlRestApiClient.ScenarioExecutionApi(); + } + + componentDidMount() { + document.title = 'AdvantEDGE'; + this.props.changeEventCreationMode(false); + this.refreshScenario(); + // -- Migration -- // + this.props.changeCurrentPage(PAGE_CONFIGURE); + this.startRefreshCycle(); + } + + startRefreshCycle() { + this.startPodsPhasesPeriodicCheck(); + this.monitorTabFocus(); + } + + startPodsPhasesPeriodicCheck() { + this.podsPhasesIntervalTimer = setInterval(() => this.checkPodsPhases(), 1000); + } + + stopCorePodsPhasesPeriodicCheck() { + clearInterval(this.podsPhasesIntervalTimer); + } + + monitorTabFocus() { + var hidden, visibilityChange; + if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support + hidden = 'hidden'; + visibilityChange = 'visibilitychange'; + } else if (typeof document.msHidden !== 'undefined') { + hidden = 'msHidden'; + visibilityChange = 'msvisibilitychange'; + } else if (typeof document.webkitHidden !== 'undefined') { + hidden = 'webkitHidden'; + visibilityChange = 'webkitvisibilitychange'; + } + + const handleVisibilityChange = () => { + if (document[hidden]) { + this.stopCorePodsPhasesPeriodicCheck(); + this.stopAutomaticRefresh(); + } else { + this.startPodsPhasesPeriodicCheck(); + + if (this.props.automaticRefresh) { + this.startAutomaticRefresh(); + } + } + }; + + // Warn if the browser doesn't support addEventListener or the Page Visibility API + if (typeof document.addEventListener === 'undefined' || hidden === undefined) { + // TODO: consider showing an alert + // console.log('This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.'); + } else { + // Handle page visibility change + document.addEventListener(visibilityChange, handleVisibilityChange, false); + } + } + + // -- Migration -- + checkPodsPhases() { + // Core pods + axios.get(`${basepath}/states?long=true&type=core`) + .then(res => { + this.props.changeCorePodsPhases(res.data.podStatus); + }).catch(() => { + this.props.changeCorePodsPhases([]); + }); + + // Scenario pods + axios.get(`${basepath}/states?long=true&type=scenario`) + .then(res => { + var scenarioPodsPhases = res.data.podStatus; + this.props.changeScenarioPodsPhases(scenarioPodsPhases); + }).catch(() => { + this.props.changeScenarioPodsPhases([]); + }); + + // Service maps + axios.get(`${basepath}/active/serviceMaps`) + .then(res => { + var serviceMaps = res.data; + this.props.changeServiceMaps(serviceMaps); + }).catch(() => { + this.props.changeServiceMaps([]); + }); + } + + setMainContent(targetId) { + this.props.changeCurrentPage(targetId); + } + + // Periodic visualization update handler + refreshMeepController() { + if ((this.props.page === PAGE_EXECUTE) && this.props.automaticRefresh) { + this.refreshScenario(); + } + } + + startAutomaticRefresh() { + _.defer(() => { + var value = this.props.refreshInterval; + if (isNaN(value) || value < 500 || value > 60000) { + clearInterval(this.refreshIntervalTimer); + } else { + clearInterval(this.refreshIntervalTimer); + this.refreshIntervalTimer = setInterval(() => this.refreshMeepController(), value); + } + }); + } + + stopAutomaticRefresh() { + clearInterval(this.refreshIntervalTimer); + } + + /** + * Callback function to receive the result of the getActiveScenario operation. + * @callback module:api/ScenarioExecutionApi~getActiveScenarioCallback + * @param {String} error Error message, if any. + * @param {module:model/Scenario} data The data returned by the service call. + */ + getActiveScenarioCb(error, data) { + if (error !== null) { + // console.log(error); + // TODO consider showing an alert + return; + } + + if (!data.deployment) { + return; + } + + // Store & Process deployed scenario + this.setScenario(TYPE_EXEC, data); + + // TODO set a timer of 2 seconds + this.props.execChangeScenarioState(EXEC_STATE_DEPLOYED); + setTimeout(() => { + this.props.execChangeOkToTerminate(true); + }, 2000); + } + + // Change & process scenario + changeScenario(pageType, scenario) { + // Change scenario state + if (pageType === TYPE_CFG) { + this.props.cfgChangeScenario(scenario); + } else { + this.props.execChangeScenario(scenario); + } + + // Parse Scenario object to retrieve visualization data and scenario table + var page = (pageType === TYPE_CFG) ? this.props.cfg : this.props.exec; + var parsedScenario = parseScenario(page.scenario); + var updatedVisData = updateObject(page.vis.data, parsedScenario.visData); + var updatedTable = updateObject(page.table, parsedScenario.table); + + // Dispatch state updates + if (pageType === TYPE_CFG) { + this.props.cfgChangeVisData(updatedVisData); + this.props.cfgChangeTable(updatedTable); + + const vis = this.props.cfgVis; + if (vis && vis.network && vis.network.setData) { + vis.network.setData(updatedVisData); + } + } else { + this.props.execChangeVisData(updatedVisData); + this.props.execChangeTable(updatedTable); + + const vis = this.props.execVis; + if (vis && vis.network && vis.network.setData) { + _.defer(() => { + vis.network.setData(this.props.execVisData); + }); + } + } + } + + // Create, store & process new scenario + createScenario(pageType, name) { + var scenario = createNewScenario(name); + this.changeScenario(pageType, scenario); + } + + // Set & process scenario + setScenario(pageType, scenario) { + this.changeScenario(pageType, scenario); + } + + // Delete & process scenario + deleteScenario(pageType) { + var scenario = createNewScenario(NO_SCENARIO_NAME); + this.changeScenario(pageType, scenario); + } + + // Refresh Active scenario + refreshScenario() { + this.meepExecApi.getActiveScenario((error, data) => this.getActiveScenarioCb(error, data)); + } + + // Add new element to scenario + newScenarioElem(pageType, element) { + var scenario = (pageType === TYPE_CFG) ? this.props.cfg.scenario : this.props.exec.scenario; + var updatedScenario = updateObject({}, scenario); + addElementToScenario(updatedScenario, element); + this.changeScenario(pageType, updatedScenario); + } + + // Update element in scenario + updateScenarioElem(pageType, element) { + var scenario = (pageType === TYPE_CFG) ? this.props.cfg.scenario : this.props.exec.scenario; + var updatedScenario = updateObject({}, scenario); + updateElementInScenario(updatedScenario, element); + this.changeScenario(pageType, updatedScenario); + } + + // Delete element in scenario (also deletes child elements) + deleteScenarioElem(pageType, element) { + var scenario = (pageType === TYPE_CFG) ? this.props.cfg.scenario : this.props.exec.scenario; + var updatedScenario = updateObject({}, scenario); + removeElementFromScenario(updatedScenario, element); + this.changeScenario(pageType, updatedScenario); + } + + renderPage() { + switch(this.props.page) { + case PAGE_CONFIGURE: + return ( + {this.createScenario(TYPE_CFG, name);}} + setScenario={(scenario) => {this.setScenario(TYPE_CFG, scenario);}} + deleteScenario={() => {this.deleteScenario(TYPE_CFG);}} + newScenarioElem={(elem) => {this.newScenarioElem(TYPE_CFG, elem);}} + updateScenarioElem={(elem) => {this.updateScenarioElem(TYPE_CFG, elem);}} + deleteScenarioElem={(elem) => {this.deleteScenarioElem(TYPE_CFG, elem);}} + /> + ); + + case PAGE_EXECUTE: + return ( + <> + {this.refreshScenario();}} + deleteScenario={() => {this.deleteScenario(TYPE_EXEC);}} + /> + + ); + + case PAGE_SETTINGS: + return ( + this.startAutomaticRefresh()} + stopRefresh={() => this.stopAutomaticRefresh()} + /> + ); + + case PAGE_MONITOR: + return ( + + ); + + default: + return null; + } + } + + render() { + const flexString = this.props.mainDrawerOpen ? '0 0 250px' : '0 0 0px'; + return ( +
    + this.props.toggleMainDrawer()} + corePodsRunning={this.props.corePodsRunning} + corePodsErrors={this.props.corePodsErrors} + /> + +
    +
    + +
    +
    + {this.renderPage()} +
    +
    +
    + ); + } +} + +const mapStateToProps = state => { + return { + cfg: state.cfg, + cfgVis: state.cfg.vis, + exec: state.exec, + execVis: state.exec.vis, + page: state.ui.page, + automaticRefresh: state.ui.automaticRefresh, + refreshInterval: state.ui.refreshInterval, + devMode: state.ui.devMode, + mainDrawerOpen: state.ui.mainDrawerOpen, + corePodsRunning: corePodsRunning(state), + corePodsErrors: corePodsErrors(state), + execVisData: execVisFilteredData(state) + }; +}; + +const mapDispatchToProps = dispatch => { + return { + changeCurrentPage: (page) => dispatch(uiChangeCurrentPage(page)), + changeEventCreationMode: (mode) => dispatch(uiExecChangeEventCreationMode(mode)), + cfgChangeScenario: (scenario) => dispatch(cfgChangeScenario(scenario)), + execChangeScenario: (scenario) => dispatch(execChangeScenario(scenario)), + execChangeScenarioState: (s) => dispatch(execChangeScenarioState(s)), + changeScenarioPodsPhases: (phases) => dispatch(execChangeScenarioPodsPhases(phases)), + changeCorePodsPhases: (phases) => dispatch(execChangeCorePodsPhases(phases)), + changeServiceMaps: (maps) => dispatch(execChangeServiceMaps(maps)), + execChangeVisData: (data) => dispatch(execChangeVisData(data)), + execChangeTable: (table) => dispatch(execChangeTable(table)), + cfgChangeVisData: (data) => dispatch(cfgChangeVisData(data)), + cfgChangeTable: (data) => dispatch(cfgChangeTable(data)), + execChangeOkToTerminate: (ok) => dispatch(execChangeOkToTerminate(ok)), + toggleMainDrawer: () => dispatch(uiToggleMainDrawer()) + }; +}; + +const ConnectedMeepContainer = connect( + mapStateToProps, + mapDispatchToProps +)(MeepContainer); + +export default ConnectedMeepContainer; diff --git a/js-apps/meep-frontend/src/js/containers/meep-drawer.js b/js-apps/meep-frontend/src/js/containers/meep-drawer.js new file mode 100644 index 0000000000000000000000000000000000000000..8faad3b359c649a861b4d8af80d49cd873c7ae68 --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/meep-drawer.js @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import { connect } from 'react-redux'; +import React, { Component } from 'react'; +import { PAGE_CONFIGURE, PAGE_EXECUTE, PAGE_MONITOR, PAGE_SETTINGS } from '../state/ui'; + +import { + MEEP_TAB_CFG, + MEEP_TAB_EXEC, + MEEP_TAB_MON, + MEEP_TAB_SET +} from '../meep-constants'; + +import { uiChangeCurrentPage } from '../state/ui'; + +import { + List, + ListItem +} from '@rmwc/list'; + +import { Icon } from '@rmwc/icon'; + +class MeepDrawer extends Component { + + constructor(props) { + super(props); + this.state = { + dismissibleOpen: true + }; + } + + handleItemClick(page) { + this.props.changeCurrentPage(page); + } + + styleForPage(page) { + var style = (this.props.currentPage === page) ? {backgroundColor: '#E0F0F9'} : null; + return style; + } + + render() { + return ( +
    +
    +
    +
    + + {this.handleItemClick(PAGE_CONFIGURE);}}> + + Configure + + {this.handleItemClick(PAGE_EXECUTE);}}> + + Execute + + {this.handleItemClick(PAGE_MONITOR);}}> + + Monitor + + {this.handleItemClick(PAGE_SETTINGS);}}> + + Settings + + +
    +
    +
    + ); + } +} + +const containerStyle = { + borderRight: '1px solid #e4e4e4', + height: '100vh' +}; + +const textStyles = { + marginLeft: '30px', + marginRight: '90px', + fontSize: 14 +}; + +const iconStyles = { + color: 'gray' +}; + +const mapDispatchToProps = dispatch => { + return { + changeCurrentPage: (page) => dispatch(uiChangeCurrentPage(page)) + }; +}; + +const mapStateToProps = state => { + return { + currentPage: state.ui.page, + mainDrawerOpen: state.ui.mainDrawerOpen + }; +}; + +const ConnectedMeepDrawer = connect( + mapStateToProps, + mapDispatchToProps +)(MeepDrawer); + +export default ConnectedMeepDrawer; diff --git a/js-apps/meep-frontend/src/js/containers/monitor/list-edit-pane.js b/js-apps/meep-frontend/src/js/containers/monitor/list-edit-pane.js new file mode 100644 index 0000000000000000000000000000000000000000..962735aa7c6f345542ff07405b6cb4b41fe972a9 --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/monitor/list-edit-pane.js @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import React from 'react'; +import _ from 'lodash'; +import { Grid, GridCell } from '@rmwc/grid'; +import { TextField } from '@rmwc/textfield'; +import { Checkbox } from '@rmwc/checkbox'; +import { Button } from '@rmwc/button'; + +export const ListEditPaneRow = ({item, itemLabelLabel, itemValueLabel, updateItemSelection, updateItemValue, updateItemLabel}) => { + return ( + + + { + updateItemLabel(item.index, e.target.value); + }} + /> + + + { + updateItemValue(item.index, e.target.value); + }} + /> + + + { + updateItemSelection(item.index, e.target.checked); + }} + /> + + + ); +}; + +export const ListEditPane = (props) => { + return ( +
    + {_.map(props.items, (item, index) => { + return (); + }) + } + + + + + + + + + + + + + +
    + ); +}; + +const styles = { + button: { + color: 'white', + marginRight: 5 + }, + editListItemCell: { + padding: 5 + } +}; \ No newline at end of file diff --git a/js-apps/meep-frontend/src/js/containers/monitor/monitor-page-container.js b/js-apps/meep-frontend/src/js/containers/monitor/monitor-page-container.js new file mode 100644 index 0000000000000000000000000000000000000000..8dc05c457b5cb31af0bfee16febc0afe44702ce4 --- /dev/null +++ b/js-apps/meep-frontend/src/js/containers/monitor/monitor-page-container.js @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2019 + * InterDigital Communications, Inc. + * All rights reserved. + * + * The information provided herein is the proprietary and confidential + * information of InterDigital Communications, Inc. + */ +import { connect } from 'react-redux'; +import React, { Component } from 'react'; +import _ from 'lodash'; +import { Grid, GridCell, GridInner } from '@rmwc/grid'; +import { Select } from '@rmwc/select'; +import { Elevation } from '@rmwc/elevation'; +import { Button } from '@rmwc/button'; +import Iframe from 'react-iframe'; +import HeadlineBar from '../../components/headline-bar'; +import { ListEditPane } from './list-edit-pane'; +import IDConfirmDialog from '../../components/dialogs/id-confirm-dialog'; + +import { + IDC_DIALOG_CONFIRM, + uiChangeCurrentDialog +} from '../../state/ui'; + +import { + uiSetAutomaticRefresh +} from '../../state/ui'; + +import { + deepCopy +} from '../../util/object-util'; + +import { + pipe, + filter +} from '../../util/functional'; + +import { + changeDashboardUrl, + changeDashboardOptions, + changeEditedDashboardOptions +} from '../../state/monitor'; + +import { + MON_DASHBOARD_SELECT, + MON_DASHBOARD_IFRAME +} from '../../meep-constants'; + +const kibanaDashboardUrl = 'http://' + location.hostname + ':32003/app/kibana#/dashboard'; + +const DashboardContainer = (props) => { + if (!props.dashboardUrl) { + return null; + } + return ( + + + + +
    +
    +