diff --git a/.gitignore b/.gitignore index a776abee952..f16f8214bff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ - # Created by https://www.gitignore.io/api/java,maven,gradle,angular,eclipse,node ### Angular ### @@ -89,7 +88,7 @@ local.properties .project # JDT-specific (Eclipse Java Development Tools) -.classpath +#.classpath # Annotation Processing .apt_generated diff --git a/cnf/central.xml b/cnf/central.xml index b85c1753aa2..e11e5447ca0 100644 --- a/cnf/central.xml +++ b/cnf/central.xml @@ -64,6 +64,11 @@ 1.1 + + org.apache.commons + commons-math3 + 3.6 + org.apache.felix org.apache.felix.gogo.shell diff --git a/doc/OpenEMS_EN.adoc b/doc/OpenEMS_EN.adoc index 61b9ea9eee5..e68376aca94 100644 --- a/doc/OpenEMS_EN.adoc +++ b/doc/OpenEMS_EN.adoc @@ -5,7 +5,7 @@ ifndef::backend-pdf[] = image:OpenEMS-Logo.png[the Feneco - OpenEMS Logo,400,role="related right"] Open Energy Management System endif::[] Stefan Feilmeier (c) 2018 FENECON GmbH -Version 2018.8.0 +Version 2018.9.0 :sectnums: :sectnumlevels: 4 :toc: @@ -82,6 +82,11 @@ For the UI (TypeScript + Angular.io) we recommend https://code.visualstudio.com/ The documentation is generated using http://asciidoc.org[AsciiDoc icon:external-link[]]. For handling git we recommend https://www.sourcetreeapp.com/[Sourctree by Atlassian icon:external-link[]]. +// TODO remove this after migration to OSGi is finished +=== Migration to OSGi + +Starting with version https://github.com/OpenEMS/openems/releases/tag/2018.7[2018.7 icon:github[]] OpenEMS Edge is getting migrated to https://en.wikipedia.org/wiki/OSGi[OSGi icon:external-link[]], a platform to provide a completely modular and dynamic service oriented system. Certain parts of Edge are not yet migrated and for the time being only available in the deprecated https://github.com/OpenEMS/openems/tree/old_master[old_master branch icon:github[]]. + === System architecture OpenEMS is generally used in combination with external hardware and software components @@ -153,11 +158,6 @@ image::eclipse-no-problems.png[Eclipse IDE showing 'no problems'] .io.openems.edge.application project in Eclipse IDE image::eclipse-io.openems.edge.application.png[io.openems.edge.application project in Eclipse IDE] -.. Click on btn:[Resolve] to resolve all dependencies and accept the 'Resolution Results' popup window with btn:[Finish]. -+ -.Resolve OSGi in Eclipse IDE -image::eclipse-resolve-osgi.png[Resolve OSGi in Eclipse IDE] - .. Click on btn:[Run OSGi] to run OpenEMS Edge. You should see log outputs on the console inside Eclipse IDE. + .OpenEMS Edge initial log output @@ -322,13 +322,13 @@ NOTE: OpenEMS UI will complain that "no timedata source is available". Because o This chapter describes some of the core concepts and commonly used terms in OpenEMS: -=== Bundle +=== OSGi Bundle OpenEMS Edge is using the https://en.wikipedia.org/wiki/OSGi[OSGi icon:external-link[]] platform to provide a completely modular and dynamic service oriented system. Logical groups of source code are put into one OSGi Bundle. Every directory in the source code root directory starting with 'io.openems.*' is a bundle. -=== Component +=== OpenEMS Component OpenEMS Edge is built of Components, i.e. every main component implements the link:../io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java[OpenemsComponent interface icon:code[]]. @@ -378,7 +378,7 @@ Example: the state of charge ("Soc") of the first energy storage system ("ess0") === Scheduler -_see <> below +The Scheduler handles the order, in which Controllers are executed. For details see <> below. // TODO: add link to all Schedulers below. Existing Scheduler implementations are described below. @@ -437,362 +437,644 @@ The following example shows, how the link:../io.openems.edge.bridge.modbus/src/i .Synchronize Cycle with Modbus read/write image::cycle-modbus.png[Synchronize Cycle with Modbus read/write] +==== Architecture scheme + +The following scheme shows the abstraction of hardware via Channels, Natures and Devices as well as the execution of control algorithms via Scheduler and Controllers. + +.Architecture scheme +image::device-nature-channel-scheduler-controller.png[Architecture scheme] + === Configuration -// OpenEMS Edge is using a central configuration file in `etc/openems.d/config.json` where all its components - Bridge, Device, Nature, Scheduler, Controller and Peristence - are defined and configured. +OpenEMS Edge and Backend are configured using the standard OSGi configuration admin service. The easiest way to set a configuration is via the http://localhost:8080/system/console/configMgr[Apache Felix Web Console Configuration icon:external-link[]] as described in the <<_getting_started>> guide above. -// As an example we will discuss a stripped down configuration of a 'FENECON Commercial' energy storage system. More example configurations can be found in the link:../setup/templates[setup templates icon:code[]]. +.Apache Felix Web Console Configuration +image::apache-felix-console-configuration.png[Apache Felix Web Console Configuration] -// [source,json] -// ---- -// { -// "things": [ <1> -// ---- -// <1> all Bridges, Devices and Natures are defined within the "things" object. +Configuration via OpenEMS UI is currently not available due to the ongoing <<_migration_to_osgi>>. Once migration is finished, it is going to be possible to change every configuration using the settings menu in OpenEMS UI - directly to OpenEMS Edge and via Backend. -// [source,json] -// ---- -// { -// "class": "io.openems.impl.protocol.modbus.ModbusTcp", <1> -// "ip": "10.4.0.15", <2> -// "devices": [ <3> -// { -// "class": "io.openems.impl.device.commercial.FeneconCommercialAC", <4> -// "modbusUnitId": 100, <5> -// "ess": { <6> -// "id": "ess0", <7> -// "minSoc": 15 -// } -// } -// ] -// }, -// ---- -// <1> defines a Modbus/TCP bridge by its Java implementation class -// // TODO: link to ModbusTcp) -// <2> sets the target IP address of the Modbus/TCP device -// <3> Devices are defined within the "devices" array of a bridge -// <4> defines a 'FENECON Commercial AC' Device by its Java implementation class -// // TODO: link to FeneconCommercialAC -// <5> sets the modbus unit ID (which is always 100 for a FENECON Commercial) -// <6> configures the "Ess" nature of the Device -// <7> sets the unique ID "ess0" for this nature. This ID is going to be used later in the Controllers. +.OpenEMS UI Configuration +image::ui-config.png[OpenEMS UI Configuration] -// [source,json] -// ---- -// { -// "class": "io.openems.impl.protocol.modbus.ModbusRtu", <1> -// "serialinterface": "/dev/ttyUSB0", <2> -// "baudrate": 9600, -// "databits": 8, -// "parity": "none", -// "stopbits": 1, -// "devices": [ -// { -// "class": "io.openems.impl.device.socomec.Socomec", <3> -// "modbusUnitId": 5, -// "meter": { <4> -// "id": "meter0", <5> -// "type": "grid" -// } -// } -// ] -// } -// ---- -// <1> defines a Modbus/RTU bridge by its Java implementation class -// // TODO: link to ModbusRtu -// <2> configures the RS485-connection (interface, baudrate, databits, parity, stopbits) -// <3> defines a 'Socomec Meter' Device by its Java implementation class -// // TODO: link to Socomec -// <4> configures the "Meter" nature of the Device -// <5> sets the unique ID "meter0" for this nature. This ID is going to be used later in the Controllers. +=== Hardware -// [source,json] -// ---- -// ], -// "scheduler": { <1> -// "class": "io.openems.impl.scheduler.SimpleScheduler", <2> -// "controllers": [ -// ---- -// <1> the Scheduler and all Controllers are defined within the "scheduler" object. -// <2> defines the Scheduler by its Java implementation class +This chapter covers hardware related topics around OpenEMS Edge. +It describes how physical hardware is abstracted using _Natures_, how standardized physical connection layers and protocols are implemented using _Bridges_ and shows which _Devices and Services_ are implemented. The chapter concludes with a development tutorial on how to implement a device. -// NOTE: This configuration uses the 'SimpleScheduler' which is executing the Controllers according to their 'priority' - starting with the highest value. -// // TODO: link to SimpleScheduler +==== Natures -// [source,json] -// ---- -// { -// "priority": 150, <1> -// "class": "io.openems.impl.controller.debuglog.DebugLogController", <2> -// "esss": "ess0", <3> -// "meters": "meter0" -// }, -// ---- -// <1> sets the 'priority' of this Controller. '150' is higher than any other priority in this configuration, so it will be executed first. -// <2> defines the 'DebugLogController' by its Java implementation class -// // TODO: link to DebugLogController -// <3> this Controller can be configured to take certain IDs for its output. +Physical hardware is abstracted in OpenEMS Edge using _Natures_. A Nature defines a set of characteristics and attributes which need to be provided by each OpenEMS component that implements it. These characteristics are defined by Channels. For example an implementation of an `Ess` (Energy Storage System), needs to provide an `Soc`-Channel (State of charge of the battery). -// NOTE: The 'DebugLogController' is helpful for debugging as it logs information about each Nature on every execution. The configuration above will produce continuous outputs like this: + -// `[INFO ] [g.DebugLogController:106] + -// meter0 [L:60 W;-2740 var|L1:0 W;0 var|L2:0 W;0 var|L3:0 W;0 var] + -// ess0 [SOC:99 %|L:600 W;300 var|Allowed:-12000 W;40000 W|GridMode:On-Grid]` +Technically Natures are implemented as OSGi API Bundles. -// [source,json] -// ---- -// { -// "priority": 100, -// "class": "io.openems.impl.controller.symmetric.avoidtotaldischarge.AvoidTotalDischargeController", <1> -// "esss": "ess0" -// }, -// ---- -// <1> defines the 'AvoidTotalDischargeController' by its Java implementation class -// // TODO: link to AvoidTotalDischargeController +===== ESS (Energy Storage System) -// NOTE: The 'AvoidTotalDischargeController' takes care of the secure function of a storage system by avoiding total discharging and force charging the battery from the grid if necessary. +An Energy Storage System is an integrated system with battery and battery inverter. -// [source,json] -// ---- -// { -// "priority": 50, -// "class": "io.openems.impl.controller.symmetric.balancing.BalancingController", <1> -// "esss": "ess0", -// "meter": "meter0" -// } -// ---- -// <1> defines the 'BalancingController' by its Java implementation class -// // TODO: link to BalancingController +link:../io.openems.edge.ess.api/src/io/openems/edge/ess/api/Ess.java[Ess icon:code[]]:: +A generic Energy Storage System ++ +|=== +include::_include/nature/Ess.adoc[tag=channels] +|=== -// NOTE: The 'BalancingController' optimizes the self-consumption of a local electric generator like a photovoltaics installation. It watches the grid-meter and tries to keep it on zero by charging or discharching the battery. +link:../io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/readonly/api/SymmetricEssReadonly.java[SymmetricEssReadonly icon:code[]]:: +A symmetric Energy Storage System in readonly-mode. +// TODO add channels -// [source,json] -// ---- -// ] -// }, -// "persistence": [ <1> -// ---- -// <1> the Persistence services are defined within the "persistence" array. +link:../io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/api/SymmetricEss.java[SymmetricEss icon:code[]]:: +A symmetric, controllable Energy Storage System. +// TODO add channels -// [source,json] -// ---- -// { -// "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", <1> -// "ip": "127.0.0.1", <2> -// "fems": "0" <3> -// }, -// ---- -// <1> defines the 'InfluxdbPersistence' by its Java implementation class -// // TODO: link to InfluxdbPersistence -// <2> sets the IP address of the InfluxDB server. -// <3> sets the "fems"-ID which allows multiple OpenEMS instances to store data to the same InfluxDB. +// TODO: describe SymmetricPower 'Active/Reactive Power circle' + callback -// NOTE: The 'InfluxdbPersistence' stores the continuous data of all Channels in an https://www.influxdata.com/[InfluxDB]. +link:../io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java[EssDcCharger icon:code[]]:: +A solar charger that is connected to DC side of an energy storage system. +// TODO add channels -// [source,json] -// ---- -// { -// "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", <1> -// "apikey": "###APIKEY###" <2> -// } -// ---- -// <1> defines the 'FeneconPersistence' by its Java implementation class -// // TODO: link to FeneconPersistence -// <2> sets the apikey which authenticates this OpenEMS at the Backend +===== Meter + +link:../io.openems.edge.meter.api/src/io/openems/edge/meter/api/Meter.java[Meter icon:code[]]:: +A generic electric power meter. +// TODO add channels + +link:../io.openems.edge.meter.api/src/io/openems/edge/meter/symmetric/api/SymmetricMeter.java[SymmetricMeter icon:code[]]:: +A power meter for symmetric metering. +// TODO add channels + +link:../io.openems.edge.meter.api/src/io/openems/edge/meter/asymmetric/api/AsymmetricMeter.java[AsymmetricMeter icon:code[]]:: +A power meter for asymmetric metering. +// TODO add channels + +===== EVCS (Electric Vehicle Charging Station) + +link:../io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java[Evcs icon:code[]]:: +A charging station for electric vehicles like e-cars and e-buses. +// TODO add channels + +===== I/O (Digital Input/Output) + +link:../io.openems.edge.io.api/src/io/openems/edge/io/api/DigitalOutput.java[DigitalOutput icon:code[]]:: +One or more digital outputs or relays. +// TODO add channels + +==== Bridges + +To simplify the implementation of hardware that is connected via certain standardized physical connection layers and protocols, those are implemented as Bridges. + +===== Modbus/TCP -// NOTE: The 'FeneconPersistence' is handling the connection to the OpenEMS Backend server. +link:../io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcp.java[Modbus/TCP icon:code[]]:: +https://en.wikipedia.org/wiki/Modbus[Modbus/TCP icon:external-link[]] is a widely used standard for fieldbus connections via TCP/IP network. It is used by all kinds of hardware devices like photovoltaics inverters, electric meters, and so on. +// TODO add configuration settings +===== Modbus/RTU + +link:../io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusSerial.java[Modbus/Serial icon:code[]]:: +https://en.wikipedia.org/wiki/Modbus[Modbus/RTU icon:external-link[]] is a widely used standard for fieldbus connections via RS485 serial bus. It is used by all kinds of hardware devices like photovoltaics inverters, electric meters, and so on. +// TODO add configuration settings + +==== Devices & Services + +// == KEBA KeContact + +// The KEBA KeContact bridge is an implementation of the UDP protocol for KEBA KeContact electric vehicle charging stations. It has no specific configuration in itself, as the configuration is happening in the DeviceNature. + +// OpenEMS configuration: // [source,json] // ---- +// { +// "class": "io.openems.impl.protocol.keba.KebaBridge", +// "devices": [ +// ... <1> // ] // } // ---- +// <1> Configuration of KEBA deviceNatures (see below) -=== Hardware +// Implementation: link:../edge/src/io/openems/impl/protocol/keba/KebaBridge.java[io.openems.impl.protocol.keba.KebaBridge icon:code[]] -==== Natures +==== Implementing a Device -// === ESS (Energy Storage System) +===== Step-by-step guide -// * link:../edge/src/io/openems/api/device/nature/ess/EssNature.java[EssNature icon:code[]] -// ** Soc -// ** SystemState -// ** AllowedCharge, AllowedDischarge -// ** Capacity -// * link:../edge/src/io/openems/api/device/nature/ess/AsymmetricEssNature.java[AsymmetricEssNature icon:code[]] extends EssNature -// ** ActivePowerL1, ActivePowerL2, ActivePowerL3 -// ** ReactivePowerL1, ReactivePowerL2, ReactivePowerL3 -// * link:../edge/src/io/openems/api/device/nature/ess/SymmetricEssNature.java[SymmetricEssNature icon:code[]] extends EssNature -// ** ActivePower -// ** ReactivePower -// * link:../edge/src/io/openems/impl/device/minireadonly/FeneconMiniEss.java[FENECON Mini (readonly) icon:code[]] implements AsymmetricEssNature -// * link:../edge/src/io/openems/impl/device/pro/FeneconProEss.java[FENECON Pro 9-12 icon:code[]] implements AsymmetricEssNature -// * link:../edge/src/io/openems/impl/device/commercial/FeneconCommercialEss.java[FENECON Commercial 40-40 icon:code[]] implements SymmetricEssNature +This chapter explains the steps required to implement a Device in OpenEMS Edge. The example shows the implementation of a http://www.socomec.co.uk/range-single-circuit-multifunction-meters_en.htlm?product=/diris-a14_en.html[SOCOMEC DIRIS A14 power meter icon:external-link[]]. The communication is via Modbus/RTU. The actual source code of the implementation can be found link:../io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/MeterSocomecDirisA14.java[here icon:code[]]. -// === Meter +The tutorial is based on the <<_getting_started>> guide. -// * link:../edge/src/io/openems/api/device/nature/meter/MeterNature.java[MeterNature icon:code[]] -// ** Type -// * link:../edge/src/io/openems/api/device/nature/meter/AsymmetricMeterNature.java[AsymmetricMeterNature icon:code[]] extends MeterNature -// ** ActivePowerL1, ActivePowerL2, ActivePowerL3 -// ** ReactivePowerL1, ReactivePowerL2, ReactivePowerL3 -// * link:../edge/src/io/openems/api/device/nature/meter/SymmetricMeterNature.java[SymmetricMeterNature icon:code[]] extends MeterNature -// ** ActivePower -// ** ReactivePower -// * link:../edge/src/io/openems/impl/device/socomec/SocomecMeter.java[Socomec icon:code[]] implements SymmetricMeterNature and AsymmetricMeterNature -// * link:../edge/src/io/openems/impl/device/pro/FeneconProPvMeter.java[FENECON Pro production meter icon:code[]] implements SymmetricMeterNature and AsymmetricMeterNature +====== Create a new OSGi Bundle -// The hardware abstraction was briefly discussed in the <<_architecture>> chapter. -// A *Device* represents an external hardware or service as its 'digital twin'. A Nature represents a specific class of hardware or service with a defined set of Channels, like an energy storage system ("EssNature") or an electric meter ("MeterNature"). +For more information see <<_osgi_bundle>>. -// The following natures are currently available in OpenEMS: +. In the menu choose btn:[File] -> btn:[New] -> btn:[Other] ++ +.Creating a new project in Eclipse IDE +image::eclipse-file-new-other.png[Creating a new project in Eclipse IDE] -// == Charger +. Select btn:[Bndtools] -> btn:[Bnd OSGi Project] and press btn:[Next >] ++ +.Creating a Bnd OSGi Project in Eclipse IDE +image::eclipse-bndtools-osgi-project.png[Creating a Bnd OSGi Project in Eclipse IDE] -// A Charger is a solar charger that is connected to DC side of an energy storage system. Example: FENECON Commercial DC comes with two Chargers. +. Select btn:[OSGi enRoute] -> btn:[Provider/Adapter Bundle] and press btn:[Next >] ++ +NOTE: Technically an OpenEMS Edge Device provides implementations of the interfaces of an OSGi _API Bundle_. In OSGi terminology this is called a _Provider/Adapter Bundle_ ++ +.Creating a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE +image::eclipse-new-osgi-provider-bundle.png[Creating a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE] -// * link:../edge/src/io/openems/api/device/nature/charger/ChargerNature.java[ChargerNature icon:code[]] +. Choose a project name and press btn:[Next >] ++ +NOTE: The project name is used as the folder name in OpenEMS source directory. The naming is up to you, but it is good practice to keep the name lower case and use something like *io.openems.[edge/backend].[purpose/nature].[implementation]*. For a SOCOMEC DIRIS A14 that is implementing the Meter nature `io.openems.edge.meter.socomec.dirisa14` is a good choice. ++ +.Naming a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE +image::eclipse-new-osgi-provider-socomec.png[Naming a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE] -// [[EssNature]] -// [[EssSymmetricNature]] -// [[AsymmetricEssNature]] -// == Energy Storage System (ESS) +. Accept defaults for the final screen and press btn:[Finish] ++ +.Java settings for a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE +image::eclipse-new-osgi-provider-socomec-final.png[Java settings for a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE] -// An Energy Storage System is an integrated system with battery and battery inverter. Example: FENECON Pro 9-12, FENECON Mini. +. The assistant closes and you can see your new bundle. -// * link:../edge/src/io/openems/api/device/nature/ess/EssNature.java[EssNature icon:code[]] -// ** *GridMode*: Off-Grid/On-Grid state -// ** *Soc*: State of Charge in percent [%]. -// ** *AllowedCharge*/*AllowedDischarge*: maximum allowed charge/discharge power in Watt [W]. -// ** *Capacity*: capacity of the battery in Watt-hours [Wh]. -// ** *MaxNominalPower*: maximum nominal power in Watt [W]. +====== Define Bundle dependencies -// * link:../edge/src/io/openems/api/device/nature/ess/EssSymmetricNature.java[EssSymmetricNature icon:code[]] -// ** *ActivePower*: charge/discharge active power in Watt [W]. -// ** *ReactivePower*: charge/discharge reactive power in volt-ampere reactive [var]. -// ** *ApparentPower*: apparent power in volt-ampere [VA]. +OSGi Bundles can be dependent on certain other Bundles. This information can be set in a *bnd.bnd* file. -// * link:../edge/src/io/openems/api/device/nature/ess/AsymmetricEssNature.java[AsymmetricEssNature icon:code[]] -// ** *ActivePowerL1*: charge/discharge active power on L1 in Watt [W]. -// ** *ActivePowerL2* -// ** *ActivePowerL3* -// ** *ReactivePowerL1*: charge/discharge reactive power on L1 in volt-ampere reactive [var]. -// ** *ReactivePowerL2* -// ** *ReactivePowerL3* +. Select the component directory btn:[src] -> btn:[io.openems.edge.meter.socomec.dirisa14] ++ +.New SOCOMEC DIRIS A14 Bnd OSGi Provider/Adapter Bundle in Eclipse IDE +image::eclipse-new-socomec-bundle.png[New SOCOMEC DIRIS A14 Bnd OSGi Provider/Adapter Bundle in Eclipse IDE] -// [[EvcsNature]] -// == Electric Vehicle Charging Station (EVCS) +. Open the btn:[bnd.bnd] file by double clicking on it. -// A charging station for electric vehicles like e-cars and e-buses. Example: KEBA KeContact. +. Open the btn:[Build] tab ++ +NOTE: You can see, that the Bundle is currently dependent on a core OSGi API bundle ('osgi.enroute.base.api'). We are going to expand that list. ++ +.Bndtools Build configuration +image::eclipse-bnd-file-build.png[Bndtools Build configuration] -// * link:../edge/src/io/openems/api/device/nature/evcs/EvcsNature.java[EvcsNature icon:code[]] -// ** *SetCurrent*: set the charge current in milliampere [mA] +. Click the btn:[+] symbol next to *Build Path*. ++ +.Bndtools Build Path configuration +image::eclipse-osgi-build-path.png[Bndtools Build Path configuration] -// [[InputNature]] -// [[OutputNature]] -// == Digital Input/Output +. Use the *Project Build Path* assistant to add the following Bundles as dependencies: ++ +io.openems.edge.common:: +The Edge Common Bundle provides implementations and services that are common to all OpenEMS Edge components. ++ +io.openems.edge.meter.api:: +The Meter API Bundle provides the interfaces for OpenEMS Edge Meter Nature. ++ +io.openems.edge.bridge.modbus:: +The Modbus Bundle provides the Bridge services for Modbus/RTU and Modbus/TCP protocols. -// Digital inputs and digital/relay outputs. Example: WAGO 750 Fieldbus, KMTronic Relais Board. +. It is also a good moment to configure the Bundle meta information. Still inside the btn:[bnd.bnd] file open the btn:[Source] tab. Add some meta information - it will help the users of your component: ++ +[source] +---- +Bundle-Name: OpenEMS Edge Meter SOCOMEC DirisA14 +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.meter.api,\ + io.openems.edge.meter.asymmetric.api,\ + io.openems.edge.meter.symmetric.api +Private-Package: io.openems.edge.meter.socomec.dirisa14 + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.meter.api;version=latest,\ + io.openems.edge.bridge.modbus;version=latest,\ + io.openems.edge.common;version=latest + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 +---- -// * link:../edge/src/io/openems/api/device/nature/io/InputNature.java[InputNature icon:code[]] -// * link:../edge/src/io/openems/api/device/nature/io/OutputNature.java[OutputNature icon:code[]] +====== Define configuration parameters -// [[MeterNature]] -// [[SymmetricMeterNature]] -// [[AsymmetricMeterNature]] -// == Electric Meter +OpenEMS Components can have several configuration parameters. They are defined as Java annotations and specific OSGi annotations are used to generate meta information that is used e.g. by Apache Felix Web Console to generate a user interface form (see <<_getting_started>>). -// Electric meter. Example: Meter at grid connection point, Socomec meter. +. Make sure that the component directory is still selected. -// * link:../edge/src/io/openems/api/device/nature/meter/MeterNature.java[MeterNature icon:code[]] -// ** *Type*: type of the meter, e.g. "grid", "production" +. In the menu choose btn:[File] -> btn:[New] -> btn:[Other] -// * link:../edge/src/io/openems/api/device/nature/meter/SymmetricMeterNature.java[SymmetricMeterNature icon:code[]] -// ** *ActivePower*: measured active power in Watt [W]. -// ** *ReactivePower*: measured reactive power in volt-ampere reactive [var]. +. Select btn:[Java] -> btn:[Class] and press btn:[Next >] ++ +.Creating a Java annotation in Eclipse IDE +image::eclipse-new-annotation.png[Creating a Java annotation in Eclipse IDE] -// * link:../edge/src/io/openems/api/device/nature/meter/AsymmetricMeterNature.java[AsymmetricMeterNature icon:code[]] -// ** *ActivePowerL1*: measured active power on L1 in Watt [W]. -// ** *ActivePowerL2* -// ** *ActivePowerL3* -// ** *ReactivePowerL1*: measured reactive power on L1 in volt-ampere reactive [var]. -// ** *ReactivePowerL2* -// ** *ReactivePowerL3* +. Set the name *Config* press btn:[Finish]. ++ +.Creating the Java annotation 'Config' in Eclipse IDE +image::eclipse-new-config-annotation.png[Creating the Java annotation 'Config' in Eclipse IDE] +. A Java annotation template was generated for you: ++ +[source,java] +---- +package io.openems.edge.meter.socomec.dirisa14; -==== Bridges +public @interface Config { -// A *Bridge* represents the connection layer to a physical hardware device and implements communication protocols like Modbus/TCP, Modbus/RTU or other vendor specific implementations. -// == Modbus/TCP +} +---- -// https://en.wikipedia.org/wiki/Modbus[Modbus/TCP icon:external-link[]] is a widely used standard for fieldbus connections via TCP/IP network. It is used by all kinds of hardware devices like photovoltaics inverters, electric meters, and so on. +. Adjust the template to match the following code: ++ +[source,java] +---- +package io.openems.edge.meter.socomec.dirisa14; -// OpenEMS configuration: -// [source,json] -// ---- -// { -// "class": "io.openems.impl.protocol.modbus.ModbusTcp", -// "ip": "192.168.0.1", <1> -// "port": 502, <2> -// "devices": [ -// ... <3> -// ] -// } -// ---- -// <1> IP address -// <2> Port (optional, defaults to `502`) -// <3> Configuration of deviceNatures (see below) +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; -// Implementation: link:../edge/src/io/openems/impl/protocol/modbus/ModbusTcp.java[io.openems.impl.protocol.modbus.ModbusTcp icon:code[]] +@ObjectClassDefinition( // <1> + name = "Meter SOCOMEC Diris A14", // + description = "Implements the SOCOMEC Diris A14 meter.") +@interface Config { + String service_pid(); // <2> -// == Modbus/RTU + String id() default "meter0"; // <3> -// https://en.wikipedia.org/wiki/Modbus[Modbus/RTU icon:external-link[]] is a widely used standard for fieldbus connections via RS485 bus. It is used by all kinds of hardware devices like photovoltaics inverters, electric meters, and so on. + boolean enabled() default true; // <4> -// OpenEMS configuration: -// [source,json] -// ---- -// { -// "class": "io.openems.impl.protocol.modbus.ModbusRtu", -// "serialinterface": "/dev/ttyUSB0", <1> -// "baudrate": 9600, <2> -// "databits": 8, <3> -// "parity": "none", <4> -// "stopbits": 1, <5> -// "devices": [ -// ... <6> -// ] -// } -// ---- -// <1> Serial interface (e.g. `/dev/ttyUSB0`, `COM3`) -// <2> RS485 baudrate (e.g. `9600`, `19200`, `38400`, `115200`) -// <3> RS485 databits (e.g. `8`) -// <4> RS485 parity (e.g. `none`, `even`, `odd`) -// <5> RS485 stopbits (e.g. `1`, `1.5`, `2`) -// <6> Configuration of deviceNatures (see below) + @AttributeDefinition(name = "Meter-Type", description = "Grid, Production (=default), Consumption") <5> + MeterType type() default MeterType.PRODUCTION; <6> -// Implementation: link:../edge/src/io/openems/impl/protocol/modbus/ModbusRtu.java[io.openems.impl.protocol.modbus.ModbusRtu icon:code[]] + @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.") + String modbus_id(); <7> -==== Devices & Services + @AttributeDefinition(name = "Modbus Unit-ID", description = "The Unit-ID of the Modbus device.") + int modbusUnitId(); <8> -// == KEBA KeContact + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default ""; <9> -// The KEBA KeContact bridge is an implementation of the UDP protocol for KEBA KeContact electric vehicle charging stations. It has no specific configuration in itself, as the configuration is happening in the DeviceNature. + @AttributeDefinition(name = "Minimum Ever Active Power", description = "This is automatically updated.") + int minActivePower(); <10> -// OpenEMS configuration: -// [source,json] -// ---- -// { -// "class": "io.openems.impl.protocol.keba.KebaBridge", -// "devices": [ -// ... <1> -// ] -// } -// ---- -// <1> Configuration of KEBA deviceNatures (see below) + @AttributeDefinition(name = "Maximum Ever Active Power", description = "This is automatically updated.") + int maxActivePower(); <10> -// Implementation: link:../edge/src/io/openems/impl/protocol/keba/KebaBridge.java[io.openems.impl.protocol.keba.KebaBridge icon:code[]] + String webconsole_configurationFactory_nameHint() default "Meter SOCOMEC Diris A14 [{id}]"; <11> +} +---- +<1> The *@ObjectClassDefinition* annotation defines this file as a Meta Type Resource for OSGi configuration admin. Use it to set a _name_ and _description_ for this OpenEMS Component. +// TODO add screenshot that shows how the strings are used in Apache +<2> The *service_pid* is used in internally by OpenEMS Edge framework and is automatically filled by OSGi. +<3> The *id* configuration parameter sets the OpenEMS Component-ID (see <<_channel_address>>). _Note_: A *default* ID 'meter0' is defined. It is good practice to define such an ID here, as it simplifies configuration in the UI. +<4> The *enabled* parameter provides a _soft_ way of deactivating an OpenEMS Component programmatically. +<5> The *@AttributeDefinition* annotation provides meta information about a configuration parameter like _name_ and _description_. +<6> The 'Meter' nature requires definition of a MeterType that defines the purpose of the Meter. We will let the user define this type by a configuration parameter. +<7> The 'Modbus-ID' parameter creates the link to a Modbus-Service via its OpenEMS Component-ID. At runtime the user will typically set this configuration parameter to something like 'modbus0'. +<8> The Modbus service implementation requires us to provide the Modbus _Unit-ID_ (also commonly called _Device-ID_ or _Slave-ID_) of the Modbus slave device. This is the ID that is configured at the SOCOMEC DIRIS. +<9> The *Modbus_target* will be automatically set by OpenEMS framework and does usually not need to be configured by the user. _Note_: Linking other OpenEMS Components is implemented using OSGi References. The OpenEMS Edge framework therefor sets the 'target' property of a reference to filter the matched services. +<10> The default Meter implementation uses configuration parameters *minActivePower* and *maxActivePower* to store the minimum/maximum ever experience active power. By providing them here the User can possibly adjust them if required. +<11> The *webconsole_configurationFactory_nameHint* parameter sets a custom name for Apache Felix Web Console, helping the user to find the correct bundle. + +====== Implement the OpenEMS Component + +Next step is to actually implement the OpenEMS Component as an OSGi Bundle. + +. The Bndtools assistant created a `ProviderImpl.java` file. First step is to set a proper name for this file. To rename the file, select it by clicking on it and choose btn:[Refactor] -> btn:[Rename...] in the menu. Write `MeterSocomecDirisA14` as 'New name' and press btn:[Finish]. ++ +.Renaming a Java class in Eclipse IDE +image::eclipse-rename.png[Renaming a Java class in Eclipse IDE] ++ +Afterwards the `MeterSocomecDirisA14.java` file has the following content: ++ +[source,java] +---- +package io.openems.edge.meter.socomec.dirisa14; -==== Implementing a Device +import java.util.Map; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.osgi.service.metatype.annotations.Designate; + +@Designate(ocd = MeterSocomecDirisA14.Config.class, factory = true) // <1> +@Component(name = "io.openems.edge.meter.socomec.dirisa14") // <2> +public class MeterSocomecDirisA14 { + + @ObjectClassDefinition + @interface Config { // <3> + String name() default "World"; + } + + private String name; + + @Activate + void activate(Config config) { <4> + this.name = config.name(); + } + + @Deactivate <5> + void deactivate() { + } + +} +---- +<1> The *@Designate* annotation is used for OSGi to create a connection to a _Config_ annotation class. It also defines this Component as a _factory_, i.e. it can produce multiple instances with different configurations. +<2> The *@Component* annotation marks this class as an OSGi component and sets a unique name. +<3> The template for _OSGi Provider/Adapter Bundles_ comes with an embedded example Config definition. +<4> The *activate()* method (marked by the *@Activate* annotation) is called on activation of an object instance of this Component. It comes with an instance of a configuration in the form of a Config object. +<5> The *deactivate()* method (marked by the *@Deactivate* annotation) is called on deactivation of the Component instance. + +. We can see, that by default there is an embedded '@interface Config' file. Which is referred to by the '@Designate' annotation. As we implemented our own *Config.java* file externally, we can adjust as follows to use our implementation: ++ +[source,java] +---- +package io.openems.edge.meter.socomec.dirisa14; + +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.metatype.annotations.Designate; + +@Designate(ocd = Config.class, factory = true) +@Component(name = "io.openems.edge.meter.socomec.dirisa14") +public class MeterSocomecDirisA14 { + + @Activate + void activate(Config config) { + } + + @Deactivate + void deactivate() { + } + +} +---- + +. It is good practice to adjust the *@Component* annotation a little bit: ++ +[source,java] +---- +@Component(name = "Meter.SOCOMEC.DirisA14", // <1> + immediate = true, // <2> + configurationPolicy = ConfigurationPolicy.REQUIRE) // <3> +---- +<1> Configure a human-readable name in the form *[nature].[vendor].[product]*. +<2> Configure the Component to be started immediately after configuration, i.e. it is not waiting till its service is required by another Component. +<3> Define that the configuration of the Component is required before it gets activated. + +. We have an OSGi Component. To make it an OpenEMS Edge Component, we need to implement the *OpenemsComponent* interface. To ease the implementation of all required functionalities we can simply inherit from the *AbstractOpenemsComponent* class. As our device is connected using Modbus, there is an additional convinience layer in the form of the *AbstractOpenemsModbusComponent* available. ++ +NOTE: In plain Java it is not required to add `implements OpenemsComponent` if we inherit from 'AbstractOpenemsComponent' or 'AbstractOpenemsModbusComponent'. Be aware that for OSGi dependency injection to function properly, it is stil required to mention all implemented interfaces again, as it is not considering the complete inheritance tree. ++ +We adjust the code as follows: ++ +[source,java] +---- +@Designate(ocd = Config.class, factory = true) +@Component(name = "Meter.SOCOMEC.DirisA14", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE) +public class MeterSocomecDirisA14 extends AbstractOpenemsModbusComponent implements OpenemsComponent { <1> + + @Activate + void activate(ComponentContext context, Config config) { <2> + super.activate(context, config.service_pid(), config.id(), config.enabled(), config.modbusUnitId(), this.cm, + "Modbus", config.modbus_id()); <3> + } + + @Deactivate + protected void deactivate() { + super.deactivate(); <3> + } + +} +---- +<1> The class extends *AbstractOpenemsModbusComponent* and specifically implements *OpenemsComponent* again. This makes it an <<_openems_component>>. +<2> The *activate()* method can be adjusted to not only take a Config object, but also provides a _ComponentContext_. OSGi takes care of providing both on activation of the Component. +<3> All logic for activating and deactivating the OpenEMS Component is hidden in the super class and just needs to be called from here. ++ +Note that after this step you will still see two errors: Eclipse complains that we need to implement a method `defineModbusProtocol()` and that it does not know `this.cm`. We will fix that in the next two steps. + +. The `super.activate()` method requires an instance of *ConfigurationAdmin* as a parameter. The ConfigurationAdmin is an external service which can be provided to our Component via dependency injection. Using OSGi Declarative Services annotations we just need to add the following two lines within the class - OSGi takes care of the rest: ++ +[source,java] +---- +@Reference +protected ConfigurationAdmin cm; +---- ++ +This solves the first error. We can now refer to an instance of _ConfigurationAdmin_ via `this.cm`. + +. _AbstractOpenemsModbusComponent_ requires us to implement a *defineModbusProtocol()* method that returns an instance of *ModbusProtocol*. The _ModbusProtocol_ class maps Modbus addresses to OpenEMS <<_channel>>s and provides some conversion utilities. Instantiation of a _ModbusProtocol_ object heavily uses the https://en.wikipedia.org/wiki/Builder_pattern#Java[Builder pattern icon:external-link[]] ++ +[source,java] +---- +@Override +protected ModbusProtocol defineModbusProtocol(int unitId) { + return new ModbusProtocol(unitId, // <1> + new FC3ReadRegistersTask(0xc558, Priority.HIGH, // <2> + ... + m(AsymmetricMeter.ChannelId.CURRENT_L1, new UnsignedDoublewordElement(0xc560)), // <3> + ... + m(SymmetricMeter.ChannelId.ACTIVE_POWER, new SignedDoublewordElement(0xc568),ElementToChannelConverter.SCALE_FACTOR_1), // <4> + ... + new DummyRegisterElement(0xc56C, 0xc56F), // <5> + ... + cm(new UnsignedDoublewordElement(0xc558)) // <6> + .m(AsymmetricMeter.ChannelId.VOLTAGE_L1, ElementToChannelConverter.SCALE_FACTOR_1) // + .m(SymmetricMeter.ChannelId.VOLTAGE, ElementToChannelConverter.SCALE_FACTOR_1) // + .build(), // + )); +} +---- +<1> Creates a *new ModbusProtocol* instance. The Modbus *Unit-ID* - which is provided by the method itself - is the first parameter, followed by an arbitrary number of 'Tasks' (implemented as a Java varags array). +<2> *FC3ReadRegistersTask* is an implementation of Modbus http://www.simplymodbus.ca/FC03.htm[function code 3 "Read Holding Registers" icon:external-link[]]. Its first parameter is the start address of the register block. The second parameter is a priority information that defines how often this register block needs to be queried. Following parameters are an arbitrary number of *ModbusElements* +<3> This command uses the internal *m()* method to make a simple 1-to-1 mapping between the Modbus element at address `0xc560` and the Channel _AsymmetricMeter.ChannelId.CURRENT_L1_. The Modbus element is defined as a 32 bit doubleword element with an unsigned integer value. +<4> The _m()_ method also takes an instance of *ElementToChannelConverter* as an additional parameter. This example uses _ElementToChannelConverter.SCALE_FACTOR_1_ to add a scale factor to the conversion that converts a Modbus read value of "95" to a channel value of "950". +<5> For Modbus registers that are empty or should be ignored, the *DummyRegisterElement* can be used. +<6> This example uses the internal method *cm()* which provides more advanced channel-to-element mapping functionalities. The example maps the Modbus element to two Channels. ++ +Using this principle a complete Modbus table consisting of multiple register blocks that need to be read or written with different Modbus function codes can be defined. For details have a look at the existing implementation classes inside the Modbus Bridge source code. + +. OpenEMS <<_channel>>s have a two-stage implementation. _Declaration_ happens inside the Nature - for common Channels - and the Component - for custom Channels specific to the Device. _Definition_ (i.e. instantiation of the Channel object) happens inside the Component. ++ +For now we only used Channels defined by the Meter Nature, e.g. link:../io.openems.edge.meter.api/src/io/openems/edge/meter/symmetric/api/SymmetricMeter.java[SymmetricMeter.ChannelId.ACTIVE_POWER' icon:code[]]. It is still good practice to add a skeleton for custom Channels *Declaration* to the Component implementation. We therefor add the following _Channel Declaration_ block inside the class: ++ +[source,java] +---- +public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { // <1> + ; // <2> + private final Doc doc; + + private ChannelId(Doc doc) { // <3> + this.doc = doc; + } + + public Doc doc() { + return this.doc; + } +} +---- +<1> Channel declarations are *enum* types implementing the ChannelId interface. +<2> This enum is empty, as we do not have custom Channels here. +<3> ChannelId enums require a Doc object that provides meta information about the Channel - e.g. the above ACTIVE_POWER Channel is defined as `ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)` ++ +After the Declaration of the Channels we also need the *Definition*. +A good place for the Definition of the Channels is inside the object constructor, to be sure that the Channels are always defined and avoid NullPointerExceptions. +It is good practice to move Channel definition to an external static _Utils.initializeChannels()_ method to keep our Component file short and clean. +We use Java Streams to facilitate the Definition of Channels ++ +Create a new file *Utils.java* with the following content: ++ +[source,java] +---- +package io.openems.edge.meter.socomec.dirisa14; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.AbstractReadChannel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.meter.api.Meter; +import io.openems.edge.meter.asymmetric.api.AsymmetricMeter; +import io.openems.edge.meter.symmetric.api.SymmetricMeter; + +public class Utils { + public static Stream> initializeChannels(MeterSocomecDirisA14 c) { // <1> + return Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { // <2> + switch (channelId) { // <3> + case STATE: + return new StateChannel(c, channelId); // <4> + } + return null; + }), Arrays.stream(Meter.ChannelId.values()).map(channelId -> { // <2> + switch (channelId) { // <3> + case FREQUENCY: + return new IntegerReadChannel(c, channelId); // <4> + } + return null; + }), Arrays.stream(SymmetricMeter.ChannelId.values()).map(channelId -> { // <2> + switch (channelId) { // <3> + case ACTIVE_POWER: + return new IntegerReadChannel(c, channelId); // <4> + } + return null; + }), Arrays.stream(AsymmetricMeter.ChannelId.values()).map(channelId -> { // <2> + switch (channelId) { // <3> + case ACTIVE_POWER_L1: + case ACTIVE_POWER_L2: + case ACTIVE_POWER_L3: + return new IntegerReadChannel(c, channelId); // <4> + } + return null; + })/* + * , Arrays.stream(MeterSocomecDirisA14.ChannelId.values()).map(channelId -> { + * switch (channelId) { } return null; }) + */ // + ).flatMap(channel -> channel); + } +} +---- +<1> The static *initializeChannels()* method returns a Java Stream of Channel objects. +<2> Using Streams the Java lambda function is called for each declared ChannelId. This command is repeated for every Nature that is implemented by the OpenEMS Component. +<3> Using a switch-case statement each ChannelId can be evaluated. _Note:_ Because we are using enums together with switch-case, Eclipse IDE is able to find out if we covered every Channel and post a warning if we did not. +<4> This line creates the actual Definition of the Channel and returns a Channel object instance of the required type. ++ +Note that after this step you will see many warnings like 'The enum constant CURRENT needs a corresponding case label in this enum switch on SymmetricMeter.ChannelId'. Eclipse IDE 'Quick Fix' provides an option 'Add missing case statements' that will generate the missing switch-cases for you. ++ +.Eclipse IDE Quick Fix for switch-case +image::eclipse-channels-switch-case.png[Eclipse IDE Quick Fix for switch-case] ++ +Finally we need to call the _Utils.initializeChannels()_ from the Component constructor. Add the following code to the Component code. It receives a Stream of Channel objects and adds all of them to the Component using the `addChannel()` method. ++ +[source,java] +---- +public MeterSocomecDirisA14() { + Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); +} +---- + +. Our OpenEMS Component utilizes an external Modbus Component for the actual Modbus communication. We receive an instance of this service via dependency injection (like we did already for the _ConfigurationAdmin_ service). Most of the magic is handled by the _AbstractOpenemsModbusComponent_ implementation. We only need to add the following code to the Component: ++ +[source,java] +---- +@Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) +protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); +} +---- + +. The Device that we are implementing provides the Natures *SymmetricMeter, AsymmetricMeter and Meter*. We already defined those in the _initializeChannels()_ method. Additionally the Component also needs to implement the Nature interfaces. ++ +Change the class declaration as follows: ++ +[source,java] +---- +public class MeterSocomecDirisA14 extends AbstractOpenemsModbusComponent + implements SymmetricMeter, AsymmetricMeter, Meter, OpenemsComponent { +---- + +. The *Meter* Nature requires us to implement a `MeterType getMeterType()` method. The MeterType was provided by the Config, so we simply take the config parameter inside the _activate()_ method: ++ +[source,java] +---- +private MeterType meterType = MeterType.PRODUCTION; // <1> + +@Activate +void activate(ComponentContext context, Config config) { + // get Meter Type: + this.meterType = config.type(); // <2> + ... +} + +@Override +public MeterType getMeterType() { // <3> + return this.meterType; +} +---- +<1> Declare the class variable _meterType_ with a default value. +<2> Store the config parameter. +<3> Implement the _getMeterType()_ method that returns the meterType. + +. Meter stores the _Min/MaxActivePower_ as configuration parameters. This is handled internally and just needs to be initialized using the *SymmetricMeter._initializeMinMaxActivePower()* method inside the _activate()_ method. ++ +[source,java] +---- +this._initializeMinMaxActivePower(this.cm, config.service_pid(), config.minActivePower(), config.maxActivePower()); +---- + +. Finally it is always a good idea to define a *debugLog()* method. This method is called in each cycle by the *Controller.Debug.Log* and very helpful for continuous debugging: ++ +[source,java] +---- +@Override +public String debugLog() { + return "L:" + this.getActivePower().value().asString(); +} +---- + +. To actually run the Component, open the *io.openems.edge.application* project and open the link:../io.openems.edge.application/EdgeApp.bndrun[EdgeApp.bndrun icon:code[]] file. Search for your Bundle and drag-and-drop it to the *Run Requirements*. ++ +.Eclipse IDE EdgeApp.bndrun +image::eclipse-edgeapp-bndrun.png[Eclipse IDE EdgeApp.bndrun] ++ +Press btn:[Resolve] to dissolve the dependencies and accept the _Resolution Results_ window with btn:[Finish]. ++ +Then press btn:[Run OSGi] to run OpenEMS Edge. From then you can configure your component as shown in <<_getting_started>>. + +===== Synchronize device communication + +===== Active/Reactive power control of a battery inverter === Scheduler diff --git a/doc/OpenEMS_EN.html b/doc/OpenEMS_EN.html index fd96d9e0a53..8cd1732c778 100644 --- a/doc/OpenEMS_EN.html +++ b/doc/OpenEMS_EN.html @@ -425,7 +425,7 @@

the Feneco - OpenEMS Logo Open Energy Management System

Stefan Feilmeier (c) 2018 FENECON GmbH
-Version 2018.8.0 +Version 2018.9.0
-

1.6. System architecture

+

1.6. Migration to OSGi

+
+

Starting with version 2018.7 OpenEMS Edge is getting migrated to OSGi , a platform to provide a completely modular and dynamic service oriented system. Certain parts of Edge are not yet migrated and for the time being only available in the deprecated old_master branch .

+
+
+
+

1.7. System architecture

OpenEMS is generally used in combination with external hardware and software components (the exception is a simulated development environment - see Getting Started) @@ -790,21 +816,12 @@

2.3. Run OpenEMS Edge and start S

  • -

    Click on Resolve to resolve all dependencies and accept the 'Resolution Results' popup window with Finish.

    -
    -
    -Resolve OSGi in Eclipse IDE -
    -
    Figure 8. Resolve OSGi in Eclipse IDE
    -
    -
  • -
  • Click on Run OSGi to run OpenEMS Edge. You should see log outputs on the console inside Eclipse IDE.

    OpenEMS Edge initial log output
    -
    Figure 9. OpenEMS Edge initial log output
    +
    Figure 8. OpenEMS Edge initial log output
  • @@ -823,7 +840,7 @@

    2.3. Run OpenEMS Edge and start S
    Apache Felix Web Console Configuration
    -
    Figure 10. Apache Felix Web Console Configuration
    +
    Figure 9. Apache Felix Web Console Configuration

  • @@ -848,7 +865,7 @@

    2.3. Run OpenEMS Edge and start S
    Configuration of All Alphabetically Scheduler
    -
    Figure 11. Configuration of All Alphabetically Scheduler
    +
    Figure 10. Configuration of All Alphabetically Scheduler

  • @@ -872,7 +889,7 @@

    2.3. Run OpenEMS Edge and start S
    Configuration of Controller Debug Log
    -
    Figure 12. Configuration of Controller Debug Log
    +
    Figure 11. Configuration of Controller Debug Log

    The log shows:

    @@ -905,7 +922,7 @@

    2.3. Run OpenEMS Edge and start S
    Configuration of Simulator DataSource: Standard Load Profile
    -
    Figure 13. Configuration of Simulator DataSource: Standard Load Profile
    +
    Figure 12. Configuration of Simulator DataSource: Standard Load Profile

    The log shows:

    @@ -932,7 +949,7 @@

    2.3. Run OpenEMS Edge and start S
    Configuration of Simulator GridMeter Acting
    -
    Figure 14. Configuration of Simulator GridMeter Acting
    +
    Figure 13. Configuration of Simulator GridMeter Acting

    This time some more logs will show up. Most importantly they show, that the Grid meter now shows a power value.

    @@ -976,7 +993,7 @@

    2.3. Run OpenEMS Edge and start S
    Configuration of Simulator EssSymmetric Reacting
    -
    Figure 15. Configuration of Simulator EssSymmetric Reacting
    +
    Figure 14. Configuration of Simulator EssSymmetric Reacting

    The log shows:

    @@ -994,7 +1011,7 @@

    2.3. Run OpenEMS Edge and start S
    Configuration of Symmetric Balancing Controller
    -
    Figure 16. Configuration of Symmetric Balancing Controller
    +
    Figure 15. Configuration of Symmetric Balancing Controller

    The log shows:

    @@ -1021,7 +1038,7 @@

    2.3. Run OpenEMS Edge and start S
    Configuration of Controller Api Websocket
    -
    Figure 17. Configuration of Controller Api Websocket
    +
    Figure 16. Configuration of Controller Api Websocket

    The log shows:

    @@ -1113,7 +1130,7 @@

    2.5. Run OpenEMS UI

    OpenEMS UI Login screen
    -
    Figure 18. OpenEMS UI Login screen
    +
    Figure 17. OpenEMS UI Login screen

  • @@ -1122,7 +1139,7 @@

    2.5. Run OpenEMS UI

    OpenEMS UI Overview screen
    -
    Figure 19. OpenEMS UI Overview screen
    +
    Figure 18. OpenEMS UI Overview screen
  • @@ -1131,7 +1148,7 @@

    2.5. Run OpenEMS UI

    OpenEMS UI Energymonitor screen
    -
    Figure 20. OpenEMS UI Energymonitor screen
    +
    Figure 19. OpenEMS UI Energymonitor screen
    @@ -1158,7 +1175,7 @@

    3. Core concepts & terminology

    This chapter describes some of the core concepts and commonly used terms in OpenEMS:

    -

    3.1. Bundle

    +

    3.1. OSGi Bundle

    OpenEMS Edge is using the OSGi platform to provide a completely modular and dynamic service oriented system.

    @@ -1167,7 +1184,7 @@

    3.1. Bundle

    -

    3.2. Component

    +

    3.2. OpenEMS Component

    OpenEMS Edge is built of Components, i.e. every main component implements the OpenemsComponent interface .

    @@ -1260,7 +1277,7 @@

    3.5. Channel Address

    3.6. Scheduler

    -

    _see Scheduler and Controller below

    +

    The Scheduler handles the order, in which Controllers are executed. For details see Scheduler and Controller below.

    @@ -1291,7 +1308,7 @@

    4.1.1. Input-Process-Output

    Input-Process-Output model
    -
    Figure 21. Input-Process-Output model
    +
    Figure 20. Input-Process-Output model
    @@ -1322,7 +1339,7 @@

    4.1.2. Scheduler and Controller

    IPO model with Scheduler and Controllers
    -
    Figure 22. IPO model with Scheduler and Controllers
    +
    Figure 21. IPO model with Scheduler and Controllers
    @@ -1334,7 +1351,7 @@

    4.1.3. Cycle

    OpenEMS Edge Cycle
    -
    Figure 23. OpenEMS Edge Cycle
    +
    Figure 22. OpenEMS Edge Cycle
    @@ -1349,23 +1366,184 @@

    4.1.4. Asynchronous thr
    Synchronize Cycle with Modbus read/write
    -
    Figure 24. Synchronize Cycle with Modbus read/write
    +
    Figure 23. Synchronize Cycle with Modbus read/write
    +

    + +
    +

    4.1.5. Architecture scheme

    +
    +

    The following scheme shows the abstraction of hardware via Channels, Natures and Devices as well as the execution of control algorithms via Scheduler and Controllers.

    +
    +
    +
    +Architecture scheme +
    +
    Figure 24. Architecture scheme

    4.2. Configuration

    - +
    +

    OpenEMS Edge and Backend are configured using the standard OSGi configuration admin service. The easiest way to set a configuration is via the Apache Felix Web Console Configuration as described in the Getting Started guide above.

    +
    +
    +
    +Apache Felix Web Console Configuration +
    +
    Figure 25. Apache Felix Web Console Configuration
    +
    +
    +

    Configuration via OpenEMS UI is currently not available due to the ongoing Migration to OSGi. Once migration is finished, it is going to be possible to change every configuration using the settings menu in OpenEMS UI - directly to OpenEMS Edge and via Backend.

    +
    +
    +
    +OpenEMS UI Configuration +
    +
    Figure 26. OpenEMS UI Configuration
    +

    4.3. Hardware

    +
    +

    This chapter covers hardware related topics around OpenEMS Edge. +It describes how physical hardware is abstracted using Natures, how standardized physical connection layers and protocols are implemented using Bridges and shows which Devices and Services are implemented. The chapter concludes with a development tutorial on how to implement a device.

    +

    4.3.1. Natures

    - +
    +

    Physical hardware is abstracted in OpenEMS Edge using Natures. A Nature defines a set of characteristics and attributes which need to be provided by each OpenEMS component that implements it. These characteristics are defined by Channels. For example an implementation of an Ess (Energy Storage System), needs to provide an Soc-Channel (State of charge of the battery).

    +
    +
    +

    Technically Natures are implemented as OSGi API Bundles.

    +
    +
    +
    4.3.1.1. ESS (Energy Storage System)
    +
    +

    An Energy Storage System is an integrated system with battery and battery inverter.

    +
    +
    +
    +
    Ess
    +
    +

    A generic Energy Storage System

    +
    ++++++ + + + + + + + + + + + + + + + + + + + + +

    Soc

    %

    0..100

    State of Charge

    GridMode

    0=Undefined, 1=On-Grid, 2=Off-Grid

    MaxActivePower

    W

    Maximum possible Active Power

    + +
    SymmetricEssReadonly
    +
    +

    A symmetric Energy Storage System in readonly-mode.

    +
    +
    SymmetricEss
    +
    +

    A symmetric, controllable Energy Storage System.

    +
    + +
    +
    +
    +
    EssDcCharger
    +
    +

    A solar charger that is connected to DC side of an energy storage system.

    +
    +
    +
    + +
    +
    4.3.1.2. Meter
    +
    +
    +
    Meter
    +
    +

    A generic electric power meter.

    +
    +
    SymmetricMeter
    +
    +

    A power meter for symmetric metering.

    +
    +
    AsymmetricMeter
    +
    +

    A power meter for asymmetric metering.

    +
    +
    +
    +
    +
    +
    4.3.1.3. EVCS (Electric Vehicle Charging Station)
    +
    +
    +
    Evcs
    +
    +

    A charging station for electric vehicles like e-cars and e-buses.

    +
    +
    +
    +
    +
    +
    4.3.1.4. I/O (Digital Input/Output)
    +
    +
    +
    DigitalOutput
    +
    +

    One or more digital outputs or relays.

    +
    +
    +
    +

    4.3.2. Bridges

    - +
    +

    To simplify the implementation of hardware that is connected via certain standardized physical connection layers and protocols, those are implemented as Bridges.

    +
    +
    +
    4.3.2.1. Modbus/TCP
    +
    +
    +
    Modbus/TCP
    +
    +

    Modbus/TCP is a widely used standard for fieldbus connections via TCP/IP network. It is used by all kinds of hardware devices like photovoltaics inverters, electric meters, and so on.

    +
    +
    +
    +
    +
    +
    4.3.2.2. Modbus/RTU
    +
    +
    +
    Modbus/Serial
    +
    +

    Modbus/RTU is a widely used standard for fieldbus connections via RS485 serial bus. It is used by all kinds of hardware devices like photovoltaics inverters, electric meters, and so on.

    +
    +
    +
    +

    4.3.3. Devices & Services

    @@ -1373,7 +1551,832 @@

    4.3.3. Devices & Services

    4.3.4. Implementing a Device

    +
    +
    4.3.4.1. Step-by-step guide
    +
    +

    This chapter explains the steps required to implement a Device in OpenEMS Edge. The example shows the implementation of a SOCOMEC DIRIS A14 power meter . The communication is via Modbus/RTU. The actual source code of the implementation can be found here .

    +
    +
    +

    The tutorial is based on the Getting Started guide.

    +
    +
    +
    Create a new OSGi Bundle
    +
    +

    For more information see OSGi Bundle.

    +
    +
    +
      +
    1. +

      In the menu choose FileNewOther

      +
      +
      +Creating a new project in Eclipse IDE +
      +
      Figure 27. Creating a new project in Eclipse IDE
      +
      +
    2. +
    3. +

      Select BndtoolsBnd OSGi Project and press Next >

      +
      +
      +Creating a Bnd OSGi Project in Eclipse IDE +
      +
      Figure 28. Creating a Bnd OSGi Project in Eclipse IDE
      +
      +
    4. +
    5. +

      Select OSGi enRouteProvider/Adapter Bundle and press Next >

      +
      + + + + + +
      + + +Technically an OpenEMS Edge Device provides implementations of the interfaces of an OSGi API Bundle. In OSGi terminology this is called a Provider/Adapter Bundle +
      +
      +
      +
      +Creating a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE +
      +
      Figure 29. Creating a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE
      +
      +
    6. +
    7. +

      Choose a project name and press Next >

      +
      + + + + + +
      + + +The project name is used as the folder name in OpenEMS source directory. The naming is up to you, but it is good practice to keep the name lower case and use something like io.openems.[edge/backend].[purpose/nature].[implementation]. For a SOCOMEC DIRIS A14 that is implementing the Meter nature io.openems.edge.meter.socomec.dirisa14 is a good choice. +
      +
      +
      +
      +Naming a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE +
      +
      Figure 30. Naming a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE
      +
      +
    8. +
    9. +

      Accept defaults for the final screen and press Finish

      +
      +
      +Java settings for a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE +
      +
      Figure 31. Java settings for a Bnd OSGi Provider/Adapter Bundle in Eclipse IDE
      +
      +
    10. +
    11. +

      The assistant closes and you can see your new bundle.

      +
    12. +
    +
    +
    +
    +
    Define Bundle dependencies
    +
    +

    OSGi Bundles can be dependent on certain other Bundles. This information can be set in a bnd.bnd file.

    +
    +
    +
      +
    1. +

      Select the component directory srcio.openems.edge.meter.socomec.dirisa14

      +
      +
      +New SOCOMEC DIRIS A14 Bnd OSGi Provider/Adapter Bundle in Eclipse IDE +
      +
      Figure 32. New SOCOMEC DIRIS A14 Bnd OSGi Provider/Adapter Bundle in Eclipse IDE
      +
      +
    2. +
    3. +

      Open the bnd.bnd file by double clicking on it.

      +
    4. +
    5. +

      Open the Build tab

      +
      + + + + + +
      + + +You can see, that the Bundle is currently dependent on a core OSGi API bundle ('osgi.enroute.base.api'). We are going to expand that list. +
      +
      +
      +
      +Bndtools Build configuration +
      +
      Figure 33. Bndtools Build configuration
      +
      +
    6. +
    7. +

      Click the + symbol next to Build Path.

      +
      +
      +Bndtools Build Path configuration +
      +
      Figure 34. Bndtools Build Path configuration
      +
      +
    8. +
    9. +

      Use the Project Build Path assistant to add the following Bundles as dependencies:

      +
      +
      +
      io.openems.edge.common
      +
      +

      The Edge Common Bundle provides implementations and services that are common to all OpenEMS Edge components.

      +
      +
      io.openems.edge.meter.api
      +
      +

      The Meter API Bundle provides the interfaces for OpenEMS Edge Meter Nature.

      +
      +
      io.openems.edge.bridge.modbus
      +
      +

      The Modbus Bundle provides the Bridge services for Modbus/RTU and Modbus/TCP protocols.

      +
      +
      +
      +
    10. +
    11. +

      It is also a good moment to configure the Bundle meta information. Still inside the bnd.bnd file open the Source tab. Add some meta information - it will help the users of your component:

      +
      +
      +
      Bundle-Name: OpenEMS Edge Meter SOCOMEC DirisA14
      +Bundle-Vendor: FENECON GmbH
      +Bundle-License: https://opensource.org/licenses/EPL-2.0
      +Bundle-Version: 1.0.0.${tstamp}
      +Export-Package: \
      +	io.openems.edge.meter.api,\
      +	io.openems.edge.meter.asymmetric.api,\
      +	io.openems.edge.meter.symmetric.api
      +Private-Package: io.openems.edge.meter.socomec.dirisa14
       
      +-includeresource: {readme.md}
      +
      +-buildpath: \
      +	osgi.enroute.base.api;version=2.1,\
      +	io.openems.edge.meter.api;version=latest,\
      +	io.openems.edge.bridge.modbus;version=latest,\
      +	io.openems.edge.common;version=latest
      +
      +-testpath: \
      +	osgi.enroute.junit.wrapper;version=4.12, \
      +	osgi.enroute.hamcrest.wrapper;version=1.3
      +
      +
      +
    12. +
    +
    +
    +
    +
    Define configuration parameters
    +
    +

    OpenEMS Components can have several configuration parameters. They are defined as Java annotations and specific OSGi annotations are used to generate meta information that is used e.g. by Apache Felix Web Console to generate a user interface form (see Getting Started).

    +
    +
    +
      +
    1. +

      Make sure that the component directory is still selected.

      +
    2. +
    3. +

      In the menu choose FileNewOther

      +
    4. +
    5. +

      Select JavaClass and press Next >

      +
      +
      +Creating a Java annotation in Eclipse IDE +
      +
      Figure 35. Creating a Java annotation in Eclipse IDE
      +
      +
    6. +
    7. +

      Set the name Config press Finish.

      +
      +
      +Creating the Java annotation 'Config' in Eclipse IDE +
      +
      Figure 36. Creating the Java annotation 'Config' in Eclipse IDE
      +
      +
    8. +
    9. +

      A Java annotation template was generated for you:

      +
      +
      +
      package io.openems.edge.meter.socomec.dirisa14;
      +
      +public @interface Config {
      +
      +}
      +
      +
      +
    10. +
    11. +

      Adjust the template to match the following code:

      +
      +
      +
      package io.openems.edge.meter.socomec.dirisa14;
      +
      +import org.osgi.service.metatype.annotations.AttributeDefinition;
      +import org.osgi.service.metatype.annotations.ObjectClassDefinition;
      +
      +@ObjectClassDefinition( (1)
      +		name = "Meter SOCOMEC Diris A14", //
      +		description = "Implements the SOCOMEC Diris A14 meter.")
      +@interface Config {
      +	String service_pid(); (2)
      +
      +	String id() default "meter0"; (3)
      +
      +	boolean enabled() default true; (4)
      +
      +	@AttributeDefinition(name = "Meter-Type", description = "Grid, Production (=default), Consumption") (5)
      +	MeterType type() default MeterType.PRODUCTION; (6)
      +
      +	@AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.")
      +	String modbus_id(); (7)
      +
      +	@AttributeDefinition(name = "Modbus Unit-ID", description = "The Unit-ID of the Modbus device.")
      +	int modbusUnitId(); (8)
      +
      +	@AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.")
      +	String Modbus_target() default ""; (9)
      +
      +	@AttributeDefinition(name = "Minimum Ever Active Power", description = "This is automatically updated.")
      +	int minActivePower(); (10)
      +
      +	@AttributeDefinition(name = "Maximum Ever Active Power", description = "This is automatically updated.")
      +	int maxActivePower(); (10)
      +
      +	String webconsole_configurationFactory_nameHint() default "Meter SOCOMEC Diris A14 [{id}]"; (11)
      +}
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      1The @ObjectClassDefinition annotation defines this file as a Meta Type Resource for OSGi configuration admin. Use it to set a name and description for this OpenEMS Component.
      2The service_pid is used in internally by OpenEMS Edge framework and is automatically filled by OSGi.
      3The id configuration parameter sets the OpenEMS Component-ID (see Channel Address). Note: A default ID 'meter0' is defined. It is good practice to define such an ID here, as it simplifies configuration in the UI.
      4The enabled parameter provides a soft way of deactivating an OpenEMS Component programmatically.
      5The @AttributeDefinition annotation provides meta information about a configuration parameter like name and description.
      6The 'Meter' nature requires definition of a MeterType that defines the purpose of the Meter. We will let the user define this type by a configuration parameter.
      7The 'Modbus-ID' parameter creates the link to a Modbus-Service via its OpenEMS Component-ID. At runtime the user will typically set this configuration parameter to something like 'modbus0'.
      8The Modbus service implementation requires us to provide the Modbus Unit-ID (also commonly called Device-ID or Slave-ID) of the Modbus slave device. This is the ID that is configured at the SOCOMEC DIRIS.
      9The Modbus_target will be automatically set by OpenEMS framework and does usually not need to be configured by the user. Note: Linking other OpenEMS Components is implemented using OSGi References. The OpenEMS Edge framework therefor sets the 'target' property of a reference to filter the matched services.
      10The default Meter implementation uses configuration parameters minActivePower and maxActivePower to store the minimum/maximum ever experience active power. By providing them here the User can possibly adjust them if required.
      11The webconsole_configurationFactory_nameHint parameter sets a custom name for Apache Felix Web Console, helping the user to find the correct bundle.
      +
      +
    12. +
    +
    +
    +
    +
    Implement the OpenEMS Component
    +
    +

    Next step is to actually implement the OpenEMS Component as an OSGi Bundle.

    +
    +
    +
      +
    1. +

      The Bndtools assistant created a ProviderImpl.java file. First step is to set a proper name for this file. To rename the file, select it by clicking on it and choose RefactorRename…​ in the menu. Write MeterSocomecDirisA14 as 'New name' and press Finish.

      +
      +
      +Renaming a Java class in Eclipse IDE +
      +
      Figure 37. Renaming a Java class in Eclipse IDE
      +
      +
      +

      Afterwards the MeterSocomecDirisA14.java file has the following content:

      +
      +
      +
      +
      package io.openems.edge.meter.socomec.dirisa14;
      +
      +import java.util.Map;
      +
      +import org.osgi.service.component.annotations.Activate;
      +import org.osgi.service.component.annotations.Component;
      +import org.osgi.service.component.annotations.Deactivate;
      +import org.osgi.service.metatype.annotations.ObjectClassDefinition;
      +import org.osgi.service.metatype.annotations.Designate;
      +
      +@Designate(ocd = MeterSocomecDirisA14.Config.class, factory = true) (1)
      +@Component(name = "io.openems.edge.meter.socomec.dirisa14") (2)
      +public class MeterSocomecDirisA14 {
      +
      +	@ObjectClassDefinition
      +	@interface Config { (3)
      +		String name() default "World";
      +	}
      +
      +	private String name;
      +
      +	@Activate
      +	void activate(Config config) { (4)
      +		this.name = config.name();
      +	}
      +
      +	@Deactivate (5)
      +	void deactivate() {
      +	}
      +
      +}
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + +
      1The @Designate annotation is used for OSGi to create a connection to a Config annotation class. It also defines this Component as a factory, i.e. it can produce multiple instances with different configurations.
      2The @Component annotation marks this class as an OSGi component and sets a unique name.
      3The template for OSGi Provider/Adapter Bundles comes with an embedded example Config definition.
      4The activate() method (marked by the @Activate annotation) is called on activation of an object instance of this Component. It comes with an instance of a configuration in the form of a Config object.
      5The deactivate() method (marked by the @Deactivate annotation) is called on deactivation of the Component instance.
      +
      +
    2. +
    3. +

      We can see, that by default there is an embedded '@interface Config' file. Which is referred to by the '@Designate' annotation. As we implemented our own Config.java file externally, we can adjust as follows to use our implementation:

      +
      +
      +
      package io.openems.edge.meter.socomec.dirisa14;
      +
      +import org.osgi.service.component.annotations.Activate;
      +import org.osgi.service.component.annotations.Component;
      +import org.osgi.service.component.annotations.Deactivate;
      +import org.osgi.service.metatype.annotations.Designate;
      +
      +@Designate(ocd = Config.class, factory = true)
      +@Component(name = "io.openems.edge.meter.socomec.dirisa14")
      +public class MeterSocomecDirisA14 {
      +
      +	@Activate
      +	void activate(Config config) {
      +	}
      +
      +	@Deactivate
      +	void deactivate() {
      +	}
      +
      +}
      +
      +
      +
    4. +
    5. +

      It is good practice to adjust the @Component annotation a little bit:

      +
      +
      +
      @Component(name = "Meter.SOCOMEC.DirisA14", (1)
      +		immediate = true, (2)
      +		configurationPolicy = ConfigurationPolicy.REQUIRE) (3)
      +
      +
      +
      + + + + + + + + + + + + + +
      1Configure a human-readable name in the form [nature].[vendor].[product].
      2Configure the Component to be started immediately after configuration, i.e. it is not waiting till its service is required by another Component.
      3Define that the configuration of the Component is required before it gets activated.
      +
      +
    6. +
    7. +

      We have an OSGi Component. To make it an OpenEMS Edge Component, we need to implement the OpenemsComponent interface. To ease the implementation of all required functionalities we can simply inherit from the AbstractOpenemsComponent class. As our device is connected using Modbus, there is an additional convinience layer in the form of the AbstractOpenemsModbusComponent available.

      +
      + + + + + +
      + + +In plain Java it is not required to add implements OpenemsComponent if we inherit from 'AbstractOpenemsComponent' or 'AbstractOpenemsModbusComponent'. Be aware that for OSGi dependency injection to function properly, it is stil required to mention all implemented interfaces again, as it is not considering the complete inheritance tree. +
      +
      +
      +

      We adjust the code as follows:

      +
      +
      +
      +
      @Designate(ocd = Config.class, factory = true)
      +@Component(name = "Meter.SOCOMEC.DirisA14", //
      +		immediate = true, //
      +		configurationPolicy = ConfigurationPolicy.REQUIRE)
      +public class MeterSocomecDirisA14 extends AbstractOpenemsModbusComponent implements OpenemsComponent { (1)
      +
      +	@Activate
      +	void activate(ComponentContext context, Config config) { (2)
      +		super.activate(context, config.service_pid(), config.id(), config.enabled(), config.modbusUnitId(), this.cm,
      +				"Modbus", config.modbus_id()); (3)
      +	}
      +
      +	@Deactivate
      +	protected void deactivate() {
      +		super.deactivate(); (3)
      +	}
      +
      +}
      +
      +
      +
      + + + + + + + + + + + + + +
      1The class extends AbstractOpenemsModbusComponent and specifically implements OpenemsComponent again. This makes it an OpenEMS Component.
      2The activate() method can be adjusted to not only take a Config object, but also provides a ComponentContext. OSGi takes care of providing both on activation of the Component.
      3All logic for activating and deactivating the OpenEMS Component is hidden in the super class and just needs to be called from here.
      +
      +
      +

      Note that after this step you will still see two errors: Eclipse complains that we need to implement a method defineModbusProtocol() and that it does not know this.cm. We will fix that in the next two steps.

      +
      +
    8. +
    9. +

      The super.activate() method requires an instance of ConfigurationAdmin as a parameter. The ConfigurationAdmin is an external service which can be provided to our Component via dependency injection. Using OSGi Declarative Services annotations we just need to add the following two lines within the class - OSGi takes care of the rest:

      +
      +
      +
      @Reference
      +protected ConfigurationAdmin cm;
      +
      +
      +
      +

      This solves the first error. We can now refer to an instance of ConfigurationAdmin via this.cm.

      +
      +
    10. +
    11. +

      AbstractOpenemsModbusComponent requires us to implement a defineModbusProtocol() method that returns an instance of ModbusProtocol. The ModbusProtocol class maps Modbus addresses to OpenEMS Channels and provides some conversion utilities. Instantiation of a ModbusProtocol object heavily uses the Builder pattern

      +
      +
      +
      @Override
      +protected ModbusProtocol defineModbusProtocol(int unitId) {
      +    return new ModbusProtocol(unitId, (1)
      +            new FC3ReadRegistersTask(0xc558, Priority.HIGH, (2)
      +                    ...
      +                    m(AsymmetricMeter.ChannelId.CURRENT_L1, new UnsignedDoublewordElement(0xc560)), (3)
      +                    ...
      +                    m(SymmetricMeter.ChannelId.ACTIVE_POWER, new SignedDoublewordElement(0xc568),ElementToChannelConverter.SCALE_FACTOR_1), (4)
      +                    ...
      +                    new DummyRegisterElement(0xc56C, 0xc56F), (5)
      +                    ...
      +                    cm(new UnsignedDoublewordElement(0xc558)) (6)
      +                        .m(AsymmetricMeter.ChannelId.VOLTAGE_L1, ElementToChannelConverter.SCALE_FACTOR_1) //
      +                        .m(SymmetricMeter.ChannelId.VOLTAGE, ElementToChannelConverter.SCALE_FACTOR_1) //
      +                        .build(), //
      +            ));
      +}
      +
      +
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + +
      1Creates a new ModbusProtocol instance. The Modbus Unit-ID - which is provided by the method itself - is the first parameter, followed by an arbitrary number of 'Tasks' (implemented as a Java varags array).
      2FC3ReadRegistersTask is an implementation of Modbus function code 3 "Read Holding Registers" . Its first parameter is the start address of the register block. The second parameter is a priority information that defines how often this register block needs to be queried. Following parameters are an arbitrary number of ModbusElements
      3This command uses the internal m() method to make a simple 1-to-1 mapping between the Modbus element at address 0xc560 and the Channel AsymmetricMeter.ChannelId.CURRENT_L1. The Modbus element is defined as a 32 bit doubleword element with an unsigned integer value.
      4The m() method also takes an instance of ElementToChannelConverter as an additional parameter. This example uses ElementToChannelConverter.SCALE_FACTOR_1 to add a scale factor to the conversion that converts a Modbus read value of "95" to a channel value of "950".
      5For Modbus registers that are empty or should be ignored, the DummyRegisterElement can be used.
      6This example uses the internal method cm() which provides more advanced channel-to-element mapping functionalities. The example maps the Modbus element to two Channels.
      +
      +
      +

      Using this principle a complete Modbus table consisting of multiple register blocks that need to be read or written with different Modbus function codes can be defined. For details have a look at the existing implementation classes inside the Modbus Bridge source code.

      +
      +
    12. +
    13. +

      OpenEMS Channels have a two-stage implementation. Declaration happens inside the Nature - for common Channels - and the Component - for custom Channels specific to the Device. Definition (i.e. instantiation of the Channel object) happens inside the Component.

      +
      +

      For now we only used Channels defined by the Meter Nature, e.g. SymmetricMeter.ChannelId.ACTIVE_POWER' . It is still good practice to add a skeleton for custom Channels Declaration to the Component implementation. We therefor add the following Channel Declaration block inside the class:

      +
      +
      +
      +
      public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { (1)
      +    ; (2)
      +    private final Doc doc;
      +
      +    private ChannelId(Doc doc) { (3)
      +        this.doc = doc;
      +    }
      +
      +    public Doc doc() {
      +        return this.doc;
      +    }
      +}
      +
      +
      +
      + + + + + + + + + + + + + +
      1Channel declarations are enum types implementing the ChannelId interface.
      2This enum is empty, as we do not have custom Channels here.
      3ChannelId enums require a Doc object that provides meta information about the Channel - e.g. the above ACTIVE_POWER Channel is defined as ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)
      +
      +
      +

      After the Declaration of the Channels we also need the Definition. +A good place for the Definition of the Channels is inside the object constructor, to be sure that the Channels are always defined and avoid NullPointerExceptions. +It is good practice to move Channel definition to an external static Utils.initializeChannels() method to keep our Component file short and clean. +We use Java Streams to facilitate the Definition of Channels

      +
      +
      +

      Create a new file Utils.java with the following content:

      +
      +
      +
      +
      package io.openems.edge.meter.socomec.dirisa14;
      +
      +import java.util.Arrays;
      +import java.util.stream.Stream;
      +
      +import io.openems.edge.common.channel.AbstractReadChannel;
      +import io.openems.edge.common.channel.IntegerReadChannel;
      +import io.openems.edge.common.channel.StateChannel;
      +import io.openems.edge.common.component.OpenemsComponent;
      +import io.openems.edge.meter.api.Meter;
      +import io.openems.edge.meter.asymmetric.api.AsymmetricMeter;
      +import io.openems.edge.meter.symmetric.api.SymmetricMeter;
      +
      +public class Utils {
      +	public static Stream<? extends AbstractReadChannel<?>> initializeChannels(MeterSocomecDirisA14 c) { (1)
      +		return Stream.of( //
      +				Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { (2)
      +					switch (channelId) { (3)
      +					case STATE:
      +						return new StateChannel(c, channelId); (4)
      +					}
      +					return null;
      +				}), Arrays.stream(Meter.ChannelId.values()).map(channelId -> { (2)
      +					switch (channelId) { (3)
      +					case FREQUENCY:
      +						return new IntegerReadChannel(c, channelId); (4)
      +					}
      +					return null;
      +				}), Arrays.stream(SymmetricMeter.ChannelId.values()).map(channelId -> { (2)
      +					switch (channelId) { (3)
      +					case ACTIVE_POWER:
      +						return new IntegerReadChannel(c, channelId); (4)
      +					}
      +					return null;
      +				}), Arrays.stream(AsymmetricMeter.ChannelId.values()).map(channelId -> { (2)
      +					switch (channelId) { (3)
      +					case ACTIVE_POWER_L1:
      +					case ACTIVE_POWER_L2:
      +					case ACTIVE_POWER_L3:
      +						return new IntegerReadChannel(c, channelId); (4)
      +					}
      +					return null;
      +				})/*
      +					 * , Arrays.stream(MeterSocomecDirisA14.ChannelId.values()).map(channelId -> {
      +					 * switch (channelId) { } return null; })
      +					 */ //
      +		).flatMap(channel -> channel);
      +	}
      +}
      +
      +
      +
      + + + + + + + + + + + + + + + + + +
      1The static initializeChannels() method returns a Java Stream of Channel objects.
      2Using Streams the Java lambda function is called for each declared ChannelId. This command is repeated for every Nature that is implemented by the OpenEMS Component.
      3Using a switch-case statement each ChannelId can be evaluated. Note: Because we are using enums together with switch-case, Eclipse IDE is able to find out if we covered every Channel and post a warning if we did not.
      4This line creates the actual Definition of the Channel and returns a Channel object instance of the required type.
      +
      +
      +

      Note that after this step you will see many warnings like 'The enum constant CURRENT needs a corresponding case label in this enum switch on SymmetricMeter.ChannelId'. Eclipse IDE 'Quick Fix' provides an option 'Add missing case statements' that will generate the missing switch-cases for you.

      +
      +
      +
      +Eclipse IDE Quick Fix for switch-case +
      +
      Figure 38. Eclipse IDE Quick Fix for switch-case
      +
      +
      +

      Finally we need to call the Utils.initializeChannels() from the Component constructor. Add the following code to the Component code. It receives a Stream of Channel objects and adds all of them to the Component using the addChannel() method.

      +
      +
      +
      +
      public MeterSocomecDirisA14() {
      +    Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel));
      +}
      +
      +
      +
    14. +
    15. +

      Our OpenEMS Component utilizes an external Modbus Component for the actual Modbus communication. We receive an instance of this service via dependency injection (like we did already for the ConfigurationAdmin service). Most of the magic is handled by the AbstractOpenemsModbusComponent implementation. We only need to add the following code to the Component:

      +
      +
      +
      @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
      +protected void setModbus(BridgeModbus modbus) {
      +    super.setModbus(modbus);
      +}
      +
      +
      +
    16. +
    17. +

      The Device that we are implementing provides the Natures SymmetricMeter, AsymmetricMeter and Meter. We already defined those in the initializeChannels() method. Additionally the Component also needs to implement the Nature interfaces.

      +
      +

      Change the class declaration as follows:

      +
      +
      +
      +
      public class MeterSocomecDirisA14 extends AbstractOpenemsModbusComponent
      +		implements SymmetricMeter, AsymmetricMeter, Meter, OpenemsComponent {
      +
      +
      +
    18. +
    19. +

      The Meter Nature requires us to implement a MeterType getMeterType() method. The MeterType was provided by the Config, so we simply take the config parameter inside the activate() method:

      +
      +
      +
      private MeterType meterType = MeterType.PRODUCTION; (1)
      +
      +@Activate
      +void activate(ComponentContext context, Config config) {
      +    // get Meter Type:
      +    this.meterType = config.type(); (2)
      +    ...
      +}
      +
      +@Override
      +public MeterType getMeterType() { (3)
      +    return this.meterType;
      +}
      +
      +
      +
      + + + + + + + + + + + + + +
      1Declare the class variable meterType with a default value.
      2Store the config parameter.
      3Implement the getMeterType() method that returns the meterType.
      +
      +
    20. +
    21. +

      Meter stores the Min/MaxActivePower as configuration parameters. This is handled internally and just needs to be initialized using the SymmetricMeter.initializeMinMaxActivePower() method inside the _activate() method.

      +
      +
      +
      this._initializeMinMaxActivePower(this.cm, config.service_pid(), config.minActivePower(), config.maxActivePower());
      +
      +
      +
    22. +
    23. +

      Finally it is always a good idea to define a debugLog() method. This method is called in each cycle by the Controller.Debug.Log and very helpful for continuous debugging:

      +
      +
      +
      @Override
      +public String debugLog() {
      +    return "L:" + this.getActivePower().value().asString();
      +}
      +
      +
      +
    24. +
    25. +

      To actually run the Component, open the io.openems.edge.application project and open the EdgeApp.bndrun file. Search for your Bundle and drag-and-drop it to the Run Requirements.

      +
      +
      +Eclipse IDE EdgeApp.bndrun +
      +
      Figure 39. Eclipse IDE EdgeApp.bndrun
      +
      +
      +

      Press Resolve to dissolve the dependencies and accept the Resolution Results window with Finish.

      +
      +
      +

      Then press Run OSGi to run OpenEMS Edge. From then you can configure your component as shown in Getting Started.

      +
      +
    26. +
    +
    +
    +
    +
    +
    4.3.4.2. Synchronize device communication
    + +
    +
    +
    4.3.4.3. Active/Reactive power control of a battery inverter
    + +
    @@ -1433,7 +2436,7 @@

    6.2. Configuration

    diff --git a/doc/_include/header.adoc b/doc/_include/header.adoc deleted file mode 100644 index 22fcd5cc37e..00000000000 --- a/doc/_include/header.adoc +++ /dev/null @@ -1,12 +0,0 @@ -ifndef::toc[] -Stefan Feilmeier (c) 2018 FENECON GmbH -Version 2018.8.0 -:sectnums: -:sectnumlevels: 4 -:toc: -:toclevels: 4 -:experimental: -:keywords: AsciiDoc -:source-highlighter: highlight.js -:icons: font -endif::toc[] \ No newline at end of file diff --git a/doc/_include/nature/Ess.adoc b/doc/_include/nature/Ess.adoc new file mode 100644 index 00000000000..7defbf4d0e3 --- /dev/null +++ b/doc/_include/nature/Ess.adoc @@ -0,0 +1,6 @@ +4+|*link:../io.openems.edge.ess.api/src/io/openems/edge/ess/api/Ess.java[Ess icon:code[]]* +// tag::channels[] +|Soc |% |0..100 | State of Charge +|GridMode | |0=Undefined, 1=On-Grid, 2=Off-Grid | +|MaxActivePower |W | | Maximum possible Active Power +// end::channels[] \ No newline at end of file diff --git a/doc/img/device-nature-channel-scheduler-controller.png b/doc/img/device-nature-channel-scheduler-controller.png new file mode 100644 index 00000000000..7faa0e172e8 Binary files /dev/null and b/doc/img/device-nature-channel-scheduler-controller.png differ diff --git a/doc/img/eclipse-bnd-file-build.png b/doc/img/eclipse-bnd-file-build.png new file mode 100644 index 00000000000..4d001233bc2 Binary files /dev/null and b/doc/img/eclipse-bnd-file-build.png differ diff --git a/doc/img/eclipse-bndtools-osgi-project.png b/doc/img/eclipse-bndtools-osgi-project.png new file mode 100644 index 00000000000..5397bd6620d Binary files /dev/null and b/doc/img/eclipse-bndtools-osgi-project.png differ diff --git a/doc/img/eclipse-channels-switch-case.png b/doc/img/eclipse-channels-switch-case.png new file mode 100644 index 00000000000..f21877b56b2 Binary files /dev/null and b/doc/img/eclipse-channels-switch-case.png differ diff --git a/doc/img/eclipse-edgeapp-bndrun.png b/doc/img/eclipse-edgeapp-bndrun.png new file mode 100644 index 00000000000..d7d0816ea95 Binary files /dev/null and b/doc/img/eclipse-edgeapp-bndrun.png differ diff --git a/doc/img/eclipse-file-new-other.png b/doc/img/eclipse-file-new-other.png new file mode 100644 index 00000000000..ac376ddc05d Binary files /dev/null and b/doc/img/eclipse-file-new-other.png differ diff --git a/doc/img/eclipse-new-annotation.png b/doc/img/eclipse-new-annotation.png new file mode 100644 index 00000000000..007658fc3d3 Binary files /dev/null and b/doc/img/eclipse-new-annotation.png differ diff --git a/doc/img/eclipse-new-class.png b/doc/img/eclipse-new-class.png new file mode 100644 index 00000000000..61e597f73c4 Binary files /dev/null and b/doc/img/eclipse-new-class.png differ diff --git a/doc/img/eclipse-new-config-annotation.png b/doc/img/eclipse-new-config-annotation.png new file mode 100644 index 00000000000..c6eafba3b39 Binary files /dev/null and b/doc/img/eclipse-new-config-annotation.png differ diff --git a/doc/img/eclipse-new-osgi-provider-bundle.png b/doc/img/eclipse-new-osgi-provider-bundle.png new file mode 100644 index 00000000000..2e115fb6880 Binary files /dev/null and b/doc/img/eclipse-new-osgi-provider-bundle.png differ diff --git a/doc/img/eclipse-new-osgi-provider-socomec-final.png b/doc/img/eclipse-new-osgi-provider-socomec-final.png new file mode 100644 index 00000000000..14ab86c46d9 Binary files /dev/null and b/doc/img/eclipse-new-osgi-provider-socomec-final.png differ diff --git a/doc/img/eclipse-new-osgi-provider-socomec.png b/doc/img/eclipse-new-osgi-provider-socomec.png new file mode 100644 index 00000000000..62e1120f9ae Binary files /dev/null and b/doc/img/eclipse-new-osgi-provider-socomec.png differ diff --git a/doc/img/eclipse-new-socomec-bundle.png b/doc/img/eclipse-new-socomec-bundle.png new file mode 100644 index 00000000000..e4aacc12a99 Binary files /dev/null and b/doc/img/eclipse-new-socomec-bundle.png differ diff --git a/doc/img/eclipse-osgi-build-path.png b/doc/img/eclipse-osgi-build-path.png new file mode 100644 index 00000000000..0e85ddbdebc Binary files /dev/null and b/doc/img/eclipse-osgi-build-path.png differ diff --git a/doc/img/eclipse-rename.png b/doc/img/eclipse-rename.png new file mode 100644 index 00000000000..2e64ca91f9e Binary files /dev/null and b/doc/img/eclipse-rename.png differ diff --git a/doc/img/eclipse-resolve-osgi.png b/doc/img/eclipse-resolve-osgi.png deleted file mode 100644 index 14afa261f00..00000000000 Binary files a/doc/img/eclipse-resolve-osgi.png and /dev/null differ diff --git a/doc/img/ui-config.png b/doc/img/ui-config.png new file mode 100644 index 00000000000..4431eb29176 Binary files /dev/null and b/doc/img/ui-config.png differ diff --git a/edge/README.md b/edge/README.md deleted file mode 100644 index 33a58c44e88..00000000000 --- a/edge/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# OpenEMS - Open Source Energy Management System - -## Architecture - -![Architecture](../doc/architecture.jpg) - -- Hardware (battery systems, inverters, meters,…) or external services are at the bottom of the graph. -- “Bridges” are the physical connection layer to a device (like Modbus/TCP or RTU). There can be several devices per Bridge. -- “Devices” are representing an external hardware or service. -- A device can have several “DeviceNatures”. For example a FENECON Pro storage system is integrating a battery as well as a meter. -- A nature has a “Channel” for each single information, which can be readonly (State of charge of a battery, current active power,…) and writable (set active power, switch of relay output) -- Central interface is the “Databus”, where all events (like changed values of a channels) are registered and commands are forwarded. -- The actual business logic is in the “Controllers”, where each of them holds specific, encapsulated tasks: - - “Controllers are Apps that are logically binding the Channels and the functionality.” For example: switching a relay output, charging the battery,… - - “AvoidTotalDischargeController” takes care of the secure function of a storage system - - “BalancingController” optimizes the self-consumption at the grid meter - - “ApiController” receives commands from external control units -- The “Scheduler” is planning and executing the controllers according to the defined, dynamic priorities. -- The configuration sits in a central JSON config file. - - -## Contact - -For more information or support, please contact us at [fems@fenecon.de](mailto:fems@fenecon.de). diff --git a/edge/etc/openems.d/.gitignore b/edge/etc/openems.d/.gitignore deleted file mode 100644 index 5e7d2734cfc..00000000000 --- a/edge/etc/openems.d/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Ignore everything in this directory -* -# Except this file -!.gitignore diff --git a/edge/pom.xml b/edge/pom.xml deleted file mode 100644 index 3be64f08a75..00000000000 --- a/edge/pom.xml +++ /dev/null @@ -1,150 +0,0 @@ - - OpenEMS Edge - Open Source Energy Management System - http://openems.io - io.openems - edge - 2018.8.0-SNAPSHOT - jar - - https://github.com/OpenEMS/openems - scm:git:git://github.com/OpenEMS/openems.git - - - UTF-8 - 1.4 - 2.8.2 - 23.1-jre - 2.7 - 2.3.4 - 1.2.3 - 1.8 - 1.8 - 3.1.0 - 3.0.2 - 2.3.10 - 1.1 - 1.7.25 - 1.3.7 - - - - maven-restlet - Public online Restlet repository - http://maven.restlet.com - - - - - com.google.code.gson - gson - ${gson.version} - - - com.google.guava - guava - ${guava.version} - - - com.ghgande - j2mod - ${j2mod.version} - - - ch.qos.logback - logback-classic - ${logback.version} - - - org.restlet.jse - org.restlet - ${restlet.version} - - - org.restlet.jse - org.restlet.ext.slf4j - ${restlet.version} - - - info.faljse - SDNotify - ${sdnotify.version} - - - org.slf4j - slf4j-api - ${slf4j.version} - - - org.java-websocket - Java-WebSocket - ${websocket.version} - - - commons-cli - commons-cli - ${commons-cli.version} - - - org.apache.servicemix.bundles - org.apache.servicemix.bundles.influxdb-java - 2.3_1 - - - org.apache.servicemix.bundles - org.apache.servicemix.bundles.retrofit - 1.9.0_1 - - - org.apache.servicemix.bundles - org.apache.servicemix.bundles.influxdb-java - 2.3_1 - - - org.apache.servicemix.bundles - org.apache.servicemix.bundles.okhttp - 2.7.5_1 - - - org.apache.servicemix.bundles - org.apache.servicemix.bundles.okio - 1.13.0_1 - - - - - - maven-jar-plugin - ${maven-jar-plugin.version} - - - default-jar - none - - - - - maven-assembly-plugin - ${maven-assembly-plugin.version} - - openems - false - - jar-with-dependencies - - - - - make-assembly - package - - single - - - - - - - 4.0.0 - diff --git a/edge/resources/logback.xml b/edge/resources/logback.xml deleted file mode 100644 index a90c6acdfdd..00000000000 --- a/edge/resources/logback.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - [%-8.8thread] [%-5level] [%-20.20logger{36}:%-3line]%msg%ex{10}%n - - - - - - /var/log/openems.log - - /var/log/openems.%i.log.zip - - 1 - 3 - 10MB - - - 1MB - - - %d{"yyyy/MM/dd HH:mm:ss"} : [%-8.8thread] [%-5level] [%-20.20logger{36}:%-3line]%msg%ex{10}%n - - - - - - - - diff --git a/edge/src/io/openems/impl/controller/symmetric/fixvalue/Ess.java b/edge/src/io/openems/impl/controller/symmetric/fixvalue/Ess.java deleted file mode 100644 index 1bee9bb0d40..00000000000 --- a/edge/src/io/openems/impl/controller/symmetric/fixvalue/Ess.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.fixvalue; - -import io.openems.api.controller.IsThingMap; -import io.openems.api.controller.ThingMap; -import io.openems.api.device.nature.ess.SymmetricEssNature; -import io.openems.core.utilities.power.symmetric.PEqualLimitation; -import io.openems.core.utilities.power.symmetric.QEqualLimitation; -import io.openems.core.utilities.power.symmetric.SymmetricPower; - -@IsThingMap(type = SymmetricEssNature.class) -public class Ess extends ThingMap { - - public final SymmetricPower power; - public final PEqualLimitation activePowerLimit; - public final QEqualLimitation reactivePowerLimit; - public final String id; - - public Ess(SymmetricEssNature ess) { - super(ess); - id = ess.id(); - power = ess.getPower(); - activePowerLimit = new PEqualLimitation(power); - reactivePowerLimit = new QEqualLimitation(power); - } - -} diff --git a/edge/src/io/openems/impl/controller/symmetric/fixvalue/FixValueReactivePowerController.java b/edge/src/io/openems/impl/controller/symmetric/fixvalue/FixValueReactivePowerController.java deleted file mode 100644 index 619eecac1c9..00000000000 --- a/edge/src/io/openems/impl/controller/symmetric/fixvalue/FixValueReactivePowerController.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.controller.symmetric.fixvalue; - -import java.util.List; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.channel.thingstate.ThingStateChannels; -import io.openems.api.controller.Controller; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.InvalidValueException; -import io.openems.core.utilities.power.symmetric.PowerException; - -@ThingInfo(title = "Fixed active and reactive power (Symmetric)", description = "Charges or discharges the battery with a predefined, fixed power. For symmetric Ess.") -public class FixValueReactivePowerController extends Controller { - - private ThingStateChannels thingState = new ThingStateChannels(this); - /* - * Constructors - */ - public FixValueReactivePowerController() { - super(); - } - - public FixValueReactivePowerController(String thingId) { - super(thingId); - } - - /* - * Config - */ - @ChannelInfo(title = "Ess", description = "Sets the Ess devices.", type = Ess.class, isArray = true) - public ConfigChannel> esss = new ConfigChannel>("esss", this); - - @ChannelInfo(title = "ReactivePower", description = "The reactive power to set for each Ess.", type = Long.class, isOptional = true) - public ConfigChannel q = new ConfigChannel("q", this); - - /* - * Methods - */ - @Override - public void run() { - try { - for (Ess ess : esss.value()) { - ess.reactivePowerLimit.setQ(q.valueOptional().orElse(null)); - ess.power.applyLimitation(ess.reactivePowerLimit); - } - } catch (InvalidValueException e) { - log.error("No ess found.", e); - } catch (PowerException e) { - log.error("Failed to set Power!",e); - } - } - - @Override - public ThingStateChannels getStateChannel() { - return this.thingState; - } - -} diff --git a/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300.java b/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300.java deleted file mode 100644 index c9f84010c23..00000000000 --- a/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.device.carlogavazzi.em300series; - -import java.util.HashSet; -import java.util.Set; - -import io.openems.api.bridge.Bridge; -import io.openems.api.channel.ConfigChannel; -import io.openems.api.device.nature.DeviceNature; -import io.openems.api.doc.ChannelInfo; -import io.openems.api.doc.ThingInfo; -import io.openems.common.exceptions.OpenemsException; -import io.openems.impl.protocol.modbus.ModbusDevice; - -@ThingInfo(title = "Carlog Gavazzi EM300") -public class EM300 extends ModbusDevice { - - /* - * Constructors - */ - public EM300(Bridge parent) throws OpenemsException { - super(parent); - } - - /* - * Config - */ - @ChannelInfo(title = "Meter", description = "Sets the meter nature.", type = EM300Meter.class) - public final ConfigChannel meter = new ConfigChannel("meter", this).addChangeListener(this); - - /* - * Methods - */ - @Override - protected Set getDeviceNatures() { - Set natures = new HashSet<>(); - if (meter.valueOptional().isPresent()) { - natures.add(meter.valueOptional().get()); - } - return natures; - } - -} diff --git a/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300Meter.java b/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300Meter.java deleted file mode 100644 index 64a2b4456b8..00000000000 --- a/edge/src/io/openems/impl/device/carlogavazzi/em300series/EM300Meter.java +++ /dev/null @@ -1,258 +0,0 @@ -/******************************************************************************* - * OpenEMS - Open Source Energy Management System - * Copyright (c) 2016, 2017 FENECON GmbH and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * Contributors: - * FENECON GmbH - initial API and implementation and initial documentation - *******************************************************************************/ -package io.openems.impl.device.carlogavazzi.em300series; - -import io.openems.api.channel.ConfigChannel; -import io.openems.api.channel.ReadChannel; -import io.openems.api.channel.thingstate.ThingStateChannels; -import io.openems.api.device.Device; -import io.openems.api.device.nature.meter.AsymmetricMeterNature; -import io.openems.api.device.nature.meter.SymmetricMeterNature; -import io.openems.api.doc.ThingInfo; -import io.openems.api.exception.ConfigException; -import io.openems.impl.protocol.modbus.ModbusDeviceNature; -import io.openems.impl.protocol.modbus.ModbusReadLongChannel; -import io.openems.impl.protocol.modbus.internal.DummyElement; -import io.openems.impl.protocol.modbus.internal.ModbusProtocol; -import io.openems.impl.protocol.modbus.internal.SignedDoublewordElement; -import io.openems.impl.protocol.modbus.internal.SignedWordElement; -import io.openems.impl.protocol.modbus.internal.UnsignedDoublewordElement; -import io.openems.impl.protocol.modbus.internal.range.ModbusInputRegisterRange; -import io.openems.impl.protocol.modbus.internal.range.ModbusRegisterRange; - -@ThingInfo(title = "Socomec Meter") -public class EM300Meter extends ModbusDeviceNature implements SymmetricMeterNature, AsymmetricMeterNature { - - private ThingStateChannels thingState; - - /* - * Constructors - */ - public EM300Meter(String thingId, Device parent) throws ConfigException { - super(thingId, parent); - this.thingState = new ThingStateChannels(this); - } - - /* - * Config - */ - private final ConfigChannel type = new ConfigChannel("type", this); - - @Override - public ConfigChannel type() { - return type; - } - - private final ConfigChannel maxActivePower = new ConfigChannel("maxActivePower", this); - - @Override - public ConfigChannel maxActivePower() { - return maxActivePower; - } - - private final ConfigChannel minActivePower = new ConfigChannel("minActivePower", this); - - @Override - public ConfigChannel minActivePower() { - return minActivePower; - } - - /* - * Inherited Channels - */ - private ModbusReadLongChannel activePower; - private ModbusReadLongChannel apparentPower; - private ModbusReadLongChannel reactivePower; - private ModbusReadLongChannel activePowerL1; - private ModbusReadLongChannel activePowerL2; - private ModbusReadLongChannel activePowerL3; - private ModbusReadLongChannel reactivePowerL1; - private ModbusReadLongChannel reactivePowerL2; - private ModbusReadLongChannel reactivePowerL3; - private ModbusReadLongChannel voltageL1; - private ModbusReadLongChannel voltageL2; - private ModbusReadLongChannel voltageL3; - private ModbusReadLongChannel currentL1; - private ModbusReadLongChannel currentL2; - private ModbusReadLongChannel currentL3; - private ModbusReadLongChannel frequency; - - @Override - public ModbusReadLongChannel activePower() { - return activePower; - } - - @Override - public ModbusReadLongChannel apparentPower() { - return apparentPower; - } - - @Override - public ModbusReadLongChannel reactivePower() { - return reactivePower; - } - - @Override - public ReadChannel activePowerL1() { - return activePowerL1; - } - - @Override - public ReadChannel activePowerL2() { - return activePowerL2; - } - - @Override - public ReadChannel activePowerL3() { - return activePowerL3; - } - - @Override - public ReadChannel reactivePowerL1() { - return reactivePowerL1; - } - - @Override - public ReadChannel reactivePowerL2() { - return reactivePowerL2; - } - - @Override - public ReadChannel reactivePowerL3() { - return reactivePowerL3; - } - - @Override - public ReadChannel currentL1() { - return currentL1; - } - - @Override - public ReadChannel currentL2() { - return currentL2; - } - - @Override - public ReadChannel currentL3() { - return currentL3; - } - - @Override - public ReadChannel voltageL1() { - return voltageL1; - } - - @Override - public ReadChannel voltageL2() { - return voltageL2; - } - - @Override - public ReadChannel voltageL3() { - return voltageL3; - } - - @Override - public ReadChannel frequency() { - return frequency; - } - - @Override - public ReadChannel voltage() { - return voltageL1; - } - - /* - * This Channels - */ - public ModbusReadLongChannel activeNegativeEnergy; - public ModbusReadLongChannel activePositiveEnergy; - public ModbusReadLongChannel reactiveNegativeEnergy; - public ModbusReadLongChannel reactivePositiveEnergy; - - /* - * Methods - */ - @Override - protected ModbusProtocol defineModbusProtocol() throws ConfigException { - return new ModbusProtocol( // - new ModbusInputRegisterRange(1, // - - new SignedDoublewordElement(1, // - voltageL1 = new ModbusReadLongChannel("VoltageL1", this).unit("mV").multiplier(2)), - new SignedDoublewordElement(3, // - voltageL2 = new ModbusReadLongChannel("VoltageL2", this).unit("mV").multiplier(2)), - new SignedDoublewordElement(5, // - voltageL3 = new ModbusReadLongChannel("VoltageL3", this).unit("mV").multiplier(2))), - new ModbusInputRegisterRange(13, new SignedDoublewordElement(13, // - currentL1 = new ModbusReadLongChannel("CurrentL1", this).unit("mA")), - new SignedDoublewordElement(15, // - currentL2 = new ModbusReadLongChannel("CurrentL2", this).unit("mA")), - new SignedDoublewordElement(17, // - currentL3 = new ModbusReadLongChannel("CurrentL3", this).unit("mA")), - new SignedDoublewordElement(19, // - activePowerL1 = new ModbusReadLongChannel("ActivePowerL1", this).unit("W") - .multiplier(-1)), - new SignedDoublewordElement(21, // - activePowerL2 = new ModbusReadLongChannel("ActivePowerL2", this).unit("W") - .multiplier(-1)), - new SignedDoublewordElement(23, // - activePowerL3 = new ModbusReadLongChannel("ActivePowerL3", this).unit("W") - .multiplier(-1)), - new SignedDoublewordElement(25, // - reactivePowerL1 = new ModbusReadLongChannel("ReactivePowerL1", this).unit("var") - .multiplier(-1)), - new SignedDoublewordElement(27, // - reactivePowerL2 = new ModbusReadLongChannel("ReactivePowerL2", this).unit("var") - .multiplier(-1)), - new SignedDoublewordElement(29, // - reactivePowerL3 = new ModbusReadLongChannel("ReactivePowerL3", this) - .unit("var").multiplier(-1)), - new DummyElement(31, 40), new SignedDoublewordElement(41, // - activePower = new ModbusReadLongChannel("ActivePower", this).unit("W").multiplier(-1)), - new SignedDoublewordElement(43, // - apparentPower = new ModbusReadLongChannel("ApparentPower", this).unit("VA") - .multiplier(-1)), - new SignedDoublewordElement(45, // - reactivePower = new ModbusReadLongChannel("ReactivePower", this) - .unit("var").multiplier(-1))), - new ModbusInputRegisterRange(52, new SignedWordElement(52, // - frequency = new ModbusReadLongChannel("Frequency", this).unit("mHZ").multiplier(2)), - new UnsignedDoublewordElement(53, // - activePositiveEnergy = new ModbusReadLongChannel("ActivePositiveEnergy", this) - .unit("kWh").multiplier(1)), - new UnsignedDoublewordElement(55, // - reactivePositiveEnergy = new ModbusReadLongChannel("ReactivePositiveEnergy", this) - .unit("kvarh").multiplier(-1))), - new ModbusRegisterRange(79, // - new UnsignedDoublewordElement(79, // - activeNegativeEnergy = new ModbusReadLongChannel( - "ActiveNegativeEnergy", this).unit("kWh").multiplier(-1)), - new UnsignedDoublewordElement(81, // - reactiveNegativeEnergy = new ModbusReadLongChannel("ReactiveNegativeEnergy", this) - .unit("kvarh").multiplier(-1)))); - } - - @Override - public ThingStateChannels getStateChannel() { - return this.thingState; - } -} diff --git a/edge/src/io/openems/impl/device/carlogavazzi/em300series/Readme.md b/edge/src/io/openems/impl/device/carlogavazzi/em300series/Readme.md deleted file mode 100644 index 235877c287e..00000000000 --- a/edge/src/io/openems/impl/device/carlogavazzi/em300series/Readme.md +++ /dev/null @@ -1,32 +0,0 @@ -# Socomec Meter - - -Following Values are implemented: - -|ChannelName|Unit| -|---|---| -|ActiveNegativeEnergy|kWh| -|ActivePositiveEnergy|kWh| -|ActivePower|W| -|ActivePowerL1|W| -|ActivePowerL2|W| -|ActivePowerL3|W| -|alias|| -|ApparentPower|VA| -|CurrentL1|mA| -|CurrentL2|mA| -|CurrentL3|mA| -|Frequency|mHZ| -|maxActivePower|| -|minActivePower|| -|ReactiveNegativeEnergy|kvarh| -|ReactivePositiveEnergy|kvarh| -|ReactivePower|var| -|ReactivePowerL1|var| -|ReactivePowerL2|var| -|ReactivePowerL3|var| -|type|| -|VoltageL1|mV| -|VoltageL1|mV| -|VoltageL2|mV| -|VoltageL3|mV| diff --git a/edge/src/org/slf4j/impl/StaticLoggerBinder.java b/edge/src/org/slf4j/impl/StaticLoggerBinder.java deleted file mode 100644 index d6c18ccbad2..00000000000 --- a/edge/src/org/slf4j/impl/StaticLoggerBinder.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.slf4j.impl; - -import org.slf4j.ILoggerFactory; -import org.slf4j.helpers.Util; -import org.slf4j.spi.LoggerFactoryBinder; - -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.util.ContextInitializer; -import ch.qos.logback.classic.util.ContextSelectorStaticBinder; -import ch.qos.logback.core.CoreConstants; -import ch.qos.logback.core.joran.spi.JoranException; -import ch.qos.logback.core.status.StatusUtil; -import ch.qos.logback.core.util.StatusPrinter; - -public class StaticLoggerBinder implements LoggerFactoryBinder { - - /** - * Declare the version of the SLF4J API this implementation is compiled - * against. The value of this field is usually modified with each release. - */ - // to avoid constant folding by the compiler, this field must *not* be final - public static String REQUESTED_API_VERSION = "1.7.16"; // !final - - final static String NULL_CS_URL = CoreConstants.CODES_URL + "#null_CS"; - - /** - * The unique instance of this class. - */ - private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); - - private static Object KEY = new Object(); - - static { - SINGLETON.init(); - } - - private boolean initialized = false; - private LoggerContext defaultLoggerContext = new LoggerContext(); - private final ContextSelectorStaticBinder contextSelectorBinder = ContextSelectorStaticBinder.getSingleton(); - - private StaticLoggerBinder() { - defaultLoggerContext.setName(CoreConstants.DEFAULT_CONTEXT_NAME); - } - - public static StaticLoggerBinder getSingleton() { - return SINGLETON; - } - - /** - * Package access for testing purposes. - */ - static void reset() { - SINGLETON = new StaticLoggerBinder(); - SINGLETON.init(); - } - - /** - * Package access for testing purposes. - */ - void init() { - try { - try { - new ContextInitializer(defaultLoggerContext).autoConfig(); - } catch (JoranException je) { - Util.report("Failed to auto configure default logger context", je); - } - // logback-292 - if (!StatusUtil.contextHasStatusListener(defaultLoggerContext)) { - StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext); - } - contextSelectorBinder.init(defaultLoggerContext, KEY); - initialized = true; - } catch (Exception t) { // see LOGBACK-1159 - Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", t); - } - } - - @Override - public ILoggerFactory getLoggerFactory() { - if (!initialized) { - return defaultLoggerContext; - } - - if (contextSelectorBinder.getContextSelector() == null) { - throw new IllegalStateException("contextSelector cannot be null. See also " + NULL_CS_URL); - } - return contextSelectorBinder.getContextSelector().getLoggerContext(); - } - - @Override - public String getLoggerFactoryClassStr() { - return contextSelectorBinder.getClass().getName(); - } - -} \ No newline at end of file diff --git a/edge/template/Bem125ktla01.json b/edge/template/Bem125ktla01.json deleted file mode 100644 index 942e298f788..00000000000 --- a/edge/template/Bem125ktla01.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "things": [ - { - "class": "io.openems.impl.protocol.modbus.ModbusRtu", - "serialinterface": "COM8", - "baudrate": 19200, - "databits": 8, - "parity": "none", - "stopbits": 1, - "devices": [ - { - "class": "io.openems.impl.device.byd.Bem125ktla01", - "modbusUnitId": 10, - "ess": { - "id": "ess0", - "minSoc": 15 - }, - "meter": { - "id": "meter0" - } - } - ] - } - ], - "scheduler": { - "class": "io.openems.impl.scheduler.SimpleScheduler", - "controllers": [ - { - "priority": 150, - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "esss": ["ess0"] - } - ] - }, - "persistence": [ - { - "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "BAm6jQt50MsjMCRYlgs6" - } - ] -} diff --git a/edge/template/Fenecon-Pro-18-24.json b/edge/template/Fenecon-Pro-18-24.json deleted file mode 100644 index 326fb7e70c0..00000000000 --- a/edge/template/Fenecon-Pro-18-24.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "things": [ - { - "class": "io.openems.impl.protocol.modbus.ModbusRtu", - "serialinterface": "/dev/ttyUSB0", - "baudrate": 9600, - "databits": 8, - "parity": "none", - "stopbits": 1, - "devices": [ - { - "class": "io.openems.impl.device.pro.FeneconPro", - "modbusUnitId": 4, - "ess": { - "id": "ess0", - "minSoc": 15 - }, - "meter": { - "id": "meter1" - } - }, - { - "class": "io.openems.impl.device.socomec.Socomec", - "modbusUnitId": 5, - "meter": { - "id": "meter0", - "type": "grid" - } - } - ] - }, - { - "class": "io.openems.impl.protocol.modbus.ModbusRtu", - "serialinterface": "/dev/ttyUSB1", - "baudrate": 9600, - "databits": 8, - "parity": "none", - "stopbits": 1, - "devices": [ - { - "class": "io.openems.impl.device.pro.FeneconPro", - "modbusUnitId": 4, - "ess": { - "id": "ess1", - "minSoc": 15 - }, - "meter": { - "id": "meter2" - } - } - ] - } - ], - "scheduler": { - "class": "io.openems.impl.scheduler.SimpleScheduler", - "controllers": [ - { - "priority": 150, - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "esss": [ "ess0", "ess1" ], - "meters": [ "meter0", "meter1", "meter2" ], - "rtc": "ess0" - }, - { - "priority": 100, - "class": "io.openems.impl.controller.asymmetric.avoidtotaldischarge.AvoidTotalDischargeController", - "esss": [ "ess0", "ess1" ] - }, - { - "priority": 50, - "class": "io.openems.impl.controller.asymmetric.balancing.BalancingController", - "esss": [ "ess0", "ess1" ], - "meter": "meter0" - }, - { - "priority": 1, - "class": "io.openems.impl.controller.clocksync.ClockSyncController", - "rtc": "ess0" - } - ] - }, - "persistence": [ - { - "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", - "ip": "127.0.0.1", - "fems": 0 - }, - { - "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "" - } - ] -} diff --git a/edge/template/FeneconCommercialHybrid.json b/edge/template/FeneconCommercialHybrid.json deleted file mode 100644 index 50056fbb781..00000000000 --- a/edge/template/FeneconCommercialHybrid.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "things": [ - { - "class": "io.openems.impl.protocol.modbus.ModbusTcp", - "ip": "10.4.0.15", - "port": 502, - "devices": [ - { - "class": "io.openems.impl.device.commercial.FeneconCommercialDC", - "ess": { - "id": "ess0", - "minSoc": 15, - "chargeSoc": 10 - }, - "charger": { - "id": "charger0" - }, - "modbusUnitId": 100 - } - ] - }, - { - "class": "io.openems.impl.protocol.modbus.ModbusRtu", - "serialinterface": "/dev/ttyUSB0", - "baudrate": 9600, - "databits": 8, - "parity": "none", - "stopbits": 1, - "devices": [ - { - "class": "io.openems.impl.device.socomec.Socomec", - "modbusUnitId": 5, - "meter": { - "id": "meter0", - "type": "grid" - } - } - ] - } - ], - "scheduler": { - "class": "io.openems.impl.scheduler.SimpleScheduler", - "controllers": [ - { - "class": "io.openems.impl.controller.symmetric.commercialworkstate.AlwaysOnController", - "priority": 0, - "esss": [ - "ess0" - ] - }, - { - "class": "io.openems.impl.controller.symmetric.avoidtotaldischarge.AvoidTotalDischargeController", - "priority": 100, - "esss": [ - "ess0" - ], - "maxSoc": 95 - }, - { - "class": "io.openems.impl.controller.symmetric.balancingsurplus.BalancingSurplusController", - "meter": "meter0", - "ess": "ess0", - "priority": 50, - "surplusMinSoc": 85, - "chargers": [ - "charger0" - ] - }, - { - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "priority": 151, - "esss": [ - "ess0" - ], - "meters": [ - "meter0", - "meter1" - ] - }, - { - "class": "io.openems.impl.controller.api.websocket.WebsocketApiController", - "port": 8085, - "priority": -2147483648 - }, - { - "class": "io.openems.impl.controller.api.rest.RestApiController", - "priority": -2147483648, - "port": 8084 - } - ] - }, - "persistence": [ - { - "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "" - }, - { - "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", - "ip": "127.0.0.1", - "fems": 0 - } - ] -} diff --git a/edge/template/FeneconMini.json b/edge/template/FeneconMini.json deleted file mode 100644 index 04c255848ac..00000000000 --- a/edge/template/FeneconMini.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "things": [ - { - "class": "io.openems.impl.protocol.modbus.ModbusRtu", - "serialinterface": "/dev/ttyUSB0", - "baudrate": 9600, - "databits": 8, - "parity": "none", - "stopbits": 1, - "devices": [ - { - "class": "io.openems.impl.device.minireadonly.FeneconMini", - "modbusUnitId": 4, - "ess": { - "id": "ess0", - "minSoc": 15 - }, - "gridMeter": { - "id": "meter0" - }, - "productionMeter": { - "id": "meter1" - }, - "consumptionMeter": { - "id": "meter2" - } - } - ] - } - ], - "scheduler": { - "class": "io.openems.impl.scheduler.SimpleScheduler", - "cycleTime": 10000, - "controllers": [ - { - "priority": 150, - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "esss": [ - "ess0" - ], - "meters": [ - "meter0", - "meter1", - "meter2" - ] - } - ] - }, - "persistence": [ - { - "class": "io.openems.impl.persistence.influxdb.InfluxdbPersistence", - "ip": "127.0.0.1", - "fems": "###FEMS###" - }, - { - "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "###APIKEY###" - } - ] -} diff --git a/edge/template/Simulator.json b/edge/template/Simulator.json deleted file mode 100644 index bd161547431..00000000000 --- a/edge/template/Simulator.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "things": [ - { - "class": "io.openems.impl.protocol.system.SystemBridge", - "devices": [ - { - "class": "io.openems.impl.device.system.System", - "system": { - "id": "system0" - } - } - ] - }, - { - "class": "io.openems.impl.protocol.simulator.SimulatorBridge", - "devices": [ - { - "class": "io.openems.impl.device.simulator.Simulator", - "symmetricEss": { - "id": "ess0", - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": -500, - "max": 1000, - "delta": 100 - } - }, - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000, - "delta": 50 - } - }, - "minSoc": 15, - "chargeSoc": 13 - }, - "productionMeter": { - "id": "meter1", - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000, - "delta": 50 - } - }, - "voltage": 230000, - "minActivePower": -259, - "maxActivePower": 11000, - "frequency": 50000, - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 10000, - "delta": 120 - } - } - }, - "gridMeter": { - "id": "meter0", - "minActivePower": -15000, - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 5000, - "delta": 250 - } - }, - "voltage": 230000, - "producer": [ - "meter1" - ], - "type": "grid", - "esss": [ - "ess0" - ], - "maxActivePower": 15000, - "frequency": 50000, - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000, - "delta": 100 - } - } - } - } - ] - } - ], - "scheduler": { - "class": "io.openems.impl.scheduler.SimpleScheduler", - "controllers": [ - { - "class": "io.openems.impl.controller.api.rest.RestApiController", - "priority": 150 - }, - { - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "meters": [ - "meter0", - "meter1" - ], - "priority": 10, - "esss": [ - "ess0" - ] - }, - { - "class": "io.openems.impl.controller.symmetric.avoidtotaldischarge.AvoidTotalDischargeController", - "priority": 100, - "esss": [ - "ess0" - ] - }, - { - "class": "io.openems.impl.controller.symmetric.balancing.BalancingController", - "esss": [ - "ess0" - ], - "meter": "meter0", - "priority": 50 - }, - { - "class": "io.openems.impl.controller.api.websocket.WebsocketApiController", - "priority": 0 - } - ] - }, - "persistence": [], - "users": { - "admin": { - "password": "txASlUVQkEI9Bxa/IZOJe8l3+R4lMzFTShz27vK44go\u003d", - "salt": "YWRtaW4\u003d" - }, - "installer": { - "password": "2O1dMlsFdwafy58ehrT+X+0CEWaAmBRad5JFbTLx/Wo\u003d", - "salt": "aW5zdGFsbGVy" - }, - "owner": { - "password": "eJgLBfHTmehv4S1whsfjeE3q3AJmJCBabV59Y65eoYI\u003d", - "salt": "b3duZXI\u003d" - }, - "guest": { - "password": "IcIzJSOvNM1PvQ8v5ypFvPoTZyHw3Knob+zi7d+WspU\u003d", - "salt": "dXNlcg\u003d\u003d" - } - } -} \ No newline at end of file diff --git a/edge/template/app/FEMS App AC-Insel.json b/edge/template/app/FEMS App AC-Insel.json deleted file mode 100644 index 7b23f559d44..00000000000 --- a/edge/template/app/FEMS App AC-Insel.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "class": "io.openems.impl.device.kmtronic.KMTronicRelayRev1", - "output": { - "id": "output0" - }, - "modbusUnitId": 1 -} - - -{ - "class": "io.openems.impl.controller.acisland.AcIsland", - "minSoc": 90, - "onGridOutputChannelAddress": "output0/2", - "offGridOutputChannelAddress": "output0/3", - "maxSoc": 95, - "switchDelay": 10000, - "ess": "ess0", - "priority": 0 -} diff --git a/edge/template/app/FEMS App Heizstab.json b/edge/template/app/FEMS App Heizstab.json deleted file mode 100644 index b2dbc59e34f..00000000000 --- a/edge/template/app/FEMS App Heizstab.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "class": "io.openems.impl.device.kmtronic.KMTronicRelayRev1", - "output": { - "id": "output0" - }, - "modbusUnitId": 1 -} - - - - - -{ - "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", - "priority": 60, - "thresholdChannelAddress": "ess0/Soc", - "outputChannelAddress": "output0/2", - "lowerThreshold": 92, - "upperThreshold": 100, - "hysteresis": 5 -}, -{ - "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", - "priority": 59, - "thresholdChannelAddress": "ess0/Soc", - "outputChannelAddress": "output0/3", - "lowerThreshold": 94, - "upperThreshold": 100, - "hysteresis": 5 -}, -{ - "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", - "priority": 58, - "thresholdChannelAddress": "ess0/Soc", - "outputChannelAddress": "output0/4", - "lowerThreshold": 96, - "upperThreshold": 100, - "hysteresis": 5 -} \ No newline at end of file diff --git a/edge/template/app/FEMS App Ladestation Typ2.json b/edge/template/app/FEMS App Ladestation Typ2.json deleted file mode 100644 index 5e96fe5abe7..00000000000 --- a/edge/template/app/FEMS App Ladestation Typ2.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "ACHTUNG": "IP-Adresse 192.168.25.11 muss erreichbar sein!" -}, -{ - "class": "io.openems.impl.protocol.keba.KebaBridge", - "devices": [ - { - "class": "io.openems.impl.device.keba.Keba", - "ip": "192.168.25.11", - "evcs": { - "id": "evcs0" - } - } - ] -}, -{ - "class": "io.openems.impl.controller.evcs.EvcsController", - "meter": "meter0", - "ess": "ess0", - "priority": 10, - "forceCharge": false, - "evcs": "evcs0" -}, -{ - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "evcss": [ - "evcs0" - ], - "priority": 150 -} diff --git "a/edge/template/app/FEMS App SG-Ready W\303\244rmepumpe.json" "b/edge/template/app/FEMS App SG-Ready W\303\244rmepumpe.json" deleted file mode 100644 index 52a33605fb7..00000000000 --- "a/edge/template/app/FEMS App SG-Ready W\303\244rmepumpe.json" +++ /dev/null @@ -1,19 +0,0 @@ -{ - "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", - "priority": 60, - "thresholdChannelAddress": "ess0/Soc", - "outputChannelAddress": "output0/0", - "lowerThreshold": 0, - "upperThreshold": 40, - "hysteresis": 5 -}, -{ - "class": "io.openems.impl.controller.channelthreshold.ChannelThresholdController", - "priority": 65, - "thresholdChannelAddress": "ess0/Soc", - "outputChannelAddress": "output0/1", - "lowerThreshold": 80, - "upperThreshold": 100, - "invertOutput": true, - "hysteresis": 5 -} \ No newline at end of file diff --git a/edge/template/bridge/ModbusTcp.json b/edge/template/bridge/ModbusTcp.json deleted file mode 100644 index eca0a9bacbe..00000000000 --- a/edge/template/bridge/ModbusTcp.json +++ /dev/null @@ -1,7 +0,0 @@ - { - "class": "io.openems.impl.protocol.modbus.ModbusTcp", - "ip": "10.0.0.1", - "port": 502, - "cycleTime": 1000, - "devices": [] -} diff --git a/edge/template/controller/DebugLogController.json b/edge/template/controller/DebugLogController.json deleted file mode 100644 index 496d1f261af..00000000000 --- a/edge/template/controller/DebugLogController.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "esss": [ - "ess0" - ], - "priority": 150, - "meters": [ - "meter0" - ] -} diff --git a/edge/template/controller/ModbusTcpController.json b/edge/template/controller/ModbusTcpController.json deleted file mode 100644 index 5d5b866cf23..00000000000 --- a/edge/template/controller/ModbusTcpController.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "class": "io.openems.impl.controller.api.modbustcp.ModbusTcpApiController", - "priority": 150, - "mapping": { - "0": "system0/OpenemsVersionMajor", - "2": "meter0/ActivePowerL1", - "6": "meter0/ActivePowerL2", - "10": "meter0/ActivePowerL3", - "14": "meter0/ActivePowerL1", - "18": "meter0/ActivePowerL2", - "22": "meter0/ActivePowerL3", - "26": "ess0/Soc", - "30": "ess0/ActivePower", - "34": "ess0/ActivePowerL2", - "38": "ess0/ActivePowerL3" - } -}, diff --git a/edge/template/controller/asymmetric/FixValueActivePowerController.json b/edge/template/controller/asymmetric/FixValueActivePowerController.json deleted file mode 100644 index a2bc8960fea..00000000000 --- a/edge/template/controller/asymmetric/FixValueActivePowerController.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "class": "io.openems.impl.controller.asymmetric.fixvalue.FixValueActivePowerController", - "esss": [ - "ess0" - ], - "priority": 150, - "activePowerL1": 2000, - "activePowerL2": 2000, - "activePowerL3": 2000 -} \ No newline at end of file diff --git a/edge/template/controller/symmetric/BalancingBandgapController.json b/edge/template/controller/symmetric/BalancingBandgapController.json deleted file mode 100644 index e59eb89f1a4..00000000000 --- a/edge/template/controller/symmetric/BalancingBandgapController.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "peakshaving0", - "class": "io.openems.impl.controller.symmetric.balancingbandgap.BalancingBandgapController", - "ess": "ess0", - "priority": 150, - "meter": "meter0", - "minActivePower": 0, - "maxActivePower": 33000, - "minReactivePower": 0, - "maxReactivePower": 0, - "activePowerActivated": true, - "reactivePowerActivated": false -} \ No newline at end of file diff --git a/edge/template/controller/symmetric/FixValueActivePowerController.json b/edge/template/controller/symmetric/FixValueActivePowerController.json deleted file mode 100644 index 691f1133706..00000000000 --- a/edge/template/controller/symmetric/FixValueActivePowerController.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "class": "io.openems.impl.controller.symmetric.fixvalue.FixValueActivePowerController", - "esss": [ - "ess0" - ], - "priority": 150, - "activePower": 2000 -} diff --git a/edge/template/device/BControl.json b/edge/template/device/BControl.json deleted file mode 100644 index fcccfa7c26b..00000000000 --- a/edge/template/device/BControl.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "class": "io.openems.impl.protocol.modbus.ModbusTcp", - "ip": "10.0.1.81", - "devices": [ - { - "class": "io.openems.impl.device.bcontrol.BControl", - "modbusUnitId": 1, - "meter": { - "id": "meter0", - "class": "io.openems.impl.device.bcontrol.BControlMeter", - "maxActivePower": 2196, - "minActivePower": -1995, - "type": "grid" - } - } - ] - }, \ No newline at end of file diff --git a/edge/template/device/JanitzaUMG96RME.json b/edge/template/device/JanitzaUMG96RME.json deleted file mode 100644 index 6e4ecb9993e..00000000000 --- a/edge/template/device/JanitzaUMG96RME.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "class": "io.openems.impl.device.janitza.JanitzaUMG96RME", - "modbusUnitId": 1, - "meter": { - "id": "meter0", - "type": "grid" - } -} diff --git a/edge/template/device/KMTronicRelayRev1.json b/edge/template/device/KMTronicRelayRev1.json deleted file mode 100644 index a6680940ce5..00000000000 --- a/edge/template/device/KMTronicRelayRev1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "class": "io.openems.impl.device.kmtronic.KMTronicRelayRev1", - "modbusUnitId": 1, - "output": { - "id": "output0" - } -} diff --git a/edge/template/persistence/openems-backend-dev.json b/edge/template/persistence/openems-backend-dev.json deleted file mode 100644 index edd8cc28a3a..00000000000 --- a/edge/template/persistence/openems-backend-dev.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "persistence": [ - { - "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "", - "uri": "wss://fenecon.de:443/openems-backend-dev" - } - ] -} diff --git a/edge/template/persistence/openems-backend.json b/edge/template/persistence/openems-backend.json deleted file mode 100644 index 8551d81a3bd..00000000000 --- a/edge/template/persistence/openems-backend.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "persistence": [ - { - "class": "io.openems.impl.persistence.fenecon.FeneconPersistence", - "apikey": "" - } - ] -} diff --git a/edge/template/sambia.json b/edge/template/sambia.json deleted file mode 100644 index c991f51eb8f..00000000000 --- a/edge/template/sambia.json +++ /dev/null @@ -1,402 +0,0 @@ -{ - "things": [ - { - "class": "io.openems.impl.protocol.simulator.SimulatorBridge", - "devices": [ - { - "class": "io.openems.impl.device.simulator.Simulator", - "gridMeter": { - "id": "meter0", - "esss": [ - "ess0", - "ess1", - "ess2", - "ess3" - ], - "frequency": 50000, - "voltage": 230000, - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": -500, - "max": 0 - } - }, - "producer": [ - "meter1" - ], - "minActivePower": -25676, - "type": "grid", - "maxActivePower": 64437, - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000 - } - } - }, - "productionMeter": { - "id": "meter1", - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": -500, - "max": 0 - } - }, - "maxActivePower": 11000, - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000 - } - }, - "voltage": 230000, - "minActivePower": -500, - "frequency": 50000 - }, - "charger": { - "id": "charger0", - "powerConfig": 0, - "maxActualPower": 20100 - }, - "symmetricEss": { - "id": "ess0", - "minSoc": 15, - "chargeSoc": 13, - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000 - } - }, - "charger": [ - "charger0" - ], - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": -500, - "max": 0 - } - } - }, - "output": { - "id": "output0" - }, - "sps": { - "id": "sps0" - } - } - ] - }, - { - "class": "io.openems.impl.protocol.simulator.SimulatorBridge", - "devices": [ - { - "class": "io.openems.impl.device.simulator.Simulator", - "symmetricEss": { - "id": "ess2", - "charger": [ - "charger2" - ], - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000 - } - }, - "chargeSoc": 13, - "minSoc": 15, - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": -500, - "max": 0 - } - } - }, - "charger": { - "id": "charger2", - "maxActualPower": 38100, - "powerConfig": 0 - } - } - ] - }, - { - "class": "io.openems.impl.protocol.system.SystemBridge", - "devices": [ - { - "class": "io.openems.impl.device.system.System", - "system": { - "id": "system0" - } - }, - { - "class": "io.openems.impl.device.system.esscluster.EssCluster", - "cluster": { - "id": "cluster0", - "minSoc": 20, - "chargeSoc": 10, - "esss": [ - "ess0", - "ess1", - "ess2", - "ess3" - ] - } - } - ] - }, - { - "class": "io.openems.impl.protocol.simulator.SimulatorBridge", - "devices": [ - { - "class": "io.openems.impl.device.simulator.Simulator", - "symmetricEss": { - "id": "ess1", - "chargeSoc": 13, - "charger": [ - "charger1" - ], - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": -500, - "max": 0 - } - }, - "SystemState": 5, - "minSoc": 15, - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000 - } - } - }, - "charger": { - "id": "charger1", - "maxActualPower": 50100, - "powerConfig": 10000 - } - } - ] - }, - { - "class": "io.openems.impl.protocol.simulator.SimulatorBridge", - "devices": [ - { - "class": "io.openems.impl.device.simulator.Simulator", - "symmetricEss": { - "id": "ess3", - "charger": [ - "charger3" - ], - "minSoc": 15, - "activePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": -500, - "max": 0 - } - }, - "reactivePowerGeneratorConfig": { - "className": "io.openems.impl.device.simulator.RandomLoadGenerator", - "config": { - "min": 0, - "max": 1000 - } - }, - "chargeSoc": 13 - }, - "charger": { - "id": "charger3", - "maxActualPower": 50100, - "powerConfig": 1000 - } - } - ] - } - ], - "scheduler": { - "class": "io.openems.impl.scheduler.SimpleScheduler", - "controllers": [ - { - "class": "io.openems.impl.controller.api.websocket.WebsocketApiController", - "priority": -2147483648 - }, - { - "class": "io.openems.impl.controller.supplybusswitch.SupplyBusSwitchController", - "supplyBusConfig": [ - { - "bus": "bus1", - "primaryEss": "ess0", - "supplybusOnIndication": "sps0/SignalBus1On", - "switches": [ - { - "ess": "ess0", - "switchAddress": "output0/DO1" - }, - { - "ess": "ess1", - "switchAddress": "output0/DO2" - }, - { - "ess": "ess2", - "switchAddress": "output0/DO3" - }, - { - "ess": "ess3", - "switchAddress": "output0/DO4" - } - ] - }, - { - "bus": "bus2", - "primaryEss": "ess0", - "supplybusOnIndication": "sps0/SignalBus2On", - "switches": [ - { - "ess": "ess0", - "switchAddress": "output0/DO5" - }, - { - "ess": "ess1", - "switchAddress": "output0/DO6" - }, - { - "ess": "ess2", - "switchAddress": "output0/DO7" - }, - { - "ess": "ess3", - "switchAddress": "output0/DO8" - } - ] - } - ], - "priority": 100, - "esss": [ - "ess0", - "ess3", - "ess2", - "ess1" - ], - "switchDelay": 5000 - }, - { - "class": "io.openems.impl.controller.api.rest.RestApiController", - "priority": -2147483648 - }, - { - "class": "io.openems.impl.controller.debuglog.DebugLogController", - "esss": [ - "cluster0" - ], - "priority": 150, - "meters": [ - "meter0" - ] - }, - { - "class": "io.openems.impl.controller.riedmann.RiedmannController", - "socLoad1Off": 40, - "socLoad3Off": 20, - "socLoad4Off": 10, - "sps": "sps0", - "socLoad2Off": 30, - "priority": 500, - "ess": "cluster0" - }, - { - "class": "io.openems.impl.controller.symmetric.timelinecharge.TimelineChargeController", - "saturday": [ - { - "time": "11:30:00", - "soc": 80 - } - ], - "thursday": [ - { - "time": "11:30:00", - "soc": 50 - } - ], - "tuesday": [ - { - "time": "11:30:00", - "soc": 80 - } - ], - "priority": 200, - "sunday": [ - { - "time": "11:30:00", - "soc": 30 - } - ], - "allowedApparent": 10000, - "ess": "cluster0", - "wednesday": [ - { - "time": "17:20:00", - "soc": 90 - } - ], - "friday": [ - { - "time": "11:30:00", - "soc": 60 - } - ], - "monday": [ - { - "time": "11:30:00", - "soc": 60 - } - ], - "chargers": [ - "charger2", - "charger1", - "charger0", - "charger3" - ], - "meter": "meter0" - }, - { - "class": "io.openems.impl.controller.symmetric.balancing.BalancingController", - "esss": [ - "cluster0" - ], - "priority": 50, - "meter": "meter0" - } - ] - }, - "persistence": [], - "users": { - "admin": { - "password": "txASlUVQkEI9Bxa/IZOJe8l3+R4lMzFTShz27vK44go\u003d", - "salt": "YWRtaW4\u003d" - }, - "installer": { - "password": "2O1dMlsFdwafy58ehrT+X+0CEWaAmBRad5JFbTLx/Wo\u003d", - "salt": "aW5zdGFsbGVy" - }, - "owner": { - "password": "eJgLBfHTmehv4S1whsfjeE3q3AJmJCBabV59Y65eoYI\u003d", - "salt": "b3duZXI\u003d" - }, - "guest": { - "password": "IcIzJSOvNM1PvQ8v5ypFvPoTZyHw3Knob+zi7d+WspU\u003d", - "salt": "dXNlcg\u003d\u003d" - } - } -} \ No newline at end of file diff --git a/edge/template/scheduler/ChannelThresholdScheduler.json b/edge/template/scheduler/ChannelThresholdScheduler.json deleted file mode 100644 index 138db7980b9..00000000000 --- a/edge/template/scheduler/ChannelThresholdScheduler.json +++ /dev/null @@ -1,58 +0,0 @@ -"scheduler": { - "class": "io.openems.impl.scheduler.channelthreshold.ChannelThresholdScheduler", - "controllers": [ - { - "id": "rest", - "class": "io.openems.impl.controller.api.rest.RestApiController", - "priority": 150 - }, - { - "id": "websocketApi0", - "class": "io.openems.impl.controller.api.websocket.WebsocketApiController", - "priority": 100 - }, - { - "id": "charge", - "class": "io.openems.impl.controller.asymmetric.fixvalue.FixValueActivePowerController", - "esss": [ - "ess0" - ], - "priority": 150, - "activePowerL1": -2000, - "activePowerL2": -2000, - "activePowerL3": -2000 - }, - { - "id": "discharge", - "class": "io.openems.impl.controller.asymmetric.fixvalue.FixValueActivePowerController", - "esss": [ - "ess0" - ], - "priority": 150, - "activePowerL1": 2000, - "activePowerL2": 2000, - "activePowerL3": 2000 - } - ], - "always": [ - "websocketApi0", - "rest" - ], - "thresholds": [ - { - "threshold": 20, - "hysteresis": 60, - "controller": [ - "charge" - ] - }, - { - "threshold": 22, - "hysteresis": 60, - "controller": [ - "discharge" - ] - } - ], - "thresholdChannelAddress": "ess0/Soc" -} \ No newline at end of file diff --git a/edge/template/scheduler/WeekTimeScheduler.json b/edge/template/scheduler/WeekTimeScheduler.json deleted file mode 100644 index d53a627da7f..00000000000 --- a/edge/template/scheduler/WeekTimeScheduler.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "scheduler": { - "class": "io.openems.impl.scheduler.time.WeekTimeScheduler", - "controllers": [ - { - "class": "io.openems.impl.controller.api.rest.RestApiController", - "priority": 150 - }, - { - "id": "websocketApi0", - "class": "io.openems.impl.controller.api.websocket.WebsocketApiController", - "priority": 100 - } - ], - "always": ["websocketApi0"], - "monday": [], - "tuesday": [], - "wednesday": [], - "thursday": [], - "friday": [], - "saturday": [], - "sunday": [] - } -} \ No newline at end of file diff --git a/io.openems.backend.application/BackendApp.bndrun b/io.openems.backend.application/BackendApp.bndrun index 515d96fe106..c31c74097b0 100644 --- a/io.openems.backend.application/BackendApp.bndrun +++ b/io.openems.backend.application/BackendApp.bndrun @@ -16,7 +16,8 @@ JPM-Command: openems-backend bnd.identity;id='io.openems.backend.timedata.influx',\ bnd.identity;id='io.openems.backend.uiwebsocket.impl',\ bnd.identity;id='org.apache.felix.webconsole',\ - bnd.identity;id='osgi.enroute.webconsole.xray.provider' + bnd.identity;id='osgi.enroute.webconsole.xray.provider',\ + bnd.identity;id='io.openems.backend.metadata.dummy' -runproperties: \ felix.cm.dir=c:/openems-backend-config,\ org.ops4j.pax.logging.service.frameworkEventsLogLevel="DISABLED",\ @@ -61,4 +62,7 @@ JPM-Command: openems-backend osgi.enroute.executor.simple.provider;version='[2.1.0,2.1.1)',\ osgi.enroute.web.simple.provider;version='[2.1.0,2.1.1)',\ osgi.enroute.webconsole.xray.provider;version='[2.1.0,2.1.1)',\ - com.google.guava;version='[25.1.0,25.1.1)' \ No newline at end of file + com.google.guava;version='[25.1.0,25.1.1)',\ + org.osgi.compendium;version='[4.1.0,4.1.1)',\ + io.openems.shared.influxdb;version=snapshot,\ + io.openems.backend.metadata.dummy;version=snapshot \ No newline at end of file diff --git a/io.openems.backend.common/test/.gitkeep b/io.openems.backend.application/test/.gitignore similarity index 100% rename from io.openems.backend.common/test/.gitkeep rename to io.openems.backend.application/test/.gitignore diff --git a/io.openems.backend.common/bnd.bnd b/io.openems.backend.common/bnd.bnd index b574b8f5496..a185b151b51 100644 --- a/io.openems.backend.common/bnd.bnd +++ b/io.openems.backend.common/bnd.bnd @@ -2,9 +2,7 @@ Bundle-Name: OpenEMS Backend Commons Bundle-Vendor: FENECON GmbH Bundle-License: https://opensource.org/licenses/EPL-2.0 Bundle-Version: 1.0.0.${tstamp} -Export-Package: \ - io.openems.backend.common.session,\ - io.openems.backend.common.events +Export-Package: io.openems.backend.common.session -includeresource: {readme.md} diff --git a/io.openems.backend.common/src/io/openems/backend/common/events/BackendEventConstants.java b/io.openems.backend.common/src/io/openems/backend/common/events/BackendEventConstants.java deleted file mode 100644 index c6ca183253a..00000000000 --- a/io.openems.backend.common/src/io/openems/backend/common/events/BackendEventConstants.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.openems.backend.common.events; - -public final class BackendEventConstants { - - private BackendEventConstants() { - // avoid inheritance - } - - public static final String TOPIC_BASE = "io/openems/backend/"; - - public static final String TOPIC_EDGE = "io/openems/backend/edge/"; - - public static final String TOPIC_EDGE_ONLINE = TOPIC_EDGE + "ONLINE"; - - public static final String TOPIC_EDGE_OFFLINE = TOPIC_EDGE + "OFFLINE"; - - public static final String PROPERTY_KEY_EDGE_ID = "edgeId"; - -} diff --git a/io.openems.backend.edgewebsocket.api/test/.gitkeep b/io.openems.backend.common/test/.gitignore similarity index 100% rename from io.openems.backend.edgewebsocket.api/test/.gitkeep rename to io.openems.backend.common/test/.gitignore diff --git a/io.openems.backend.metadata.api/test/.gitkeep b/io.openems.backend.edgewebsocket.api/test/.gitignore similarity index 100% rename from io.openems.backend.metadata.api/test/.gitkeep rename to io.openems.backend.edgewebsocket.api/test/.gitignore diff --git a/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/EdgeWebsocket.java b/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/EdgeWebsocket.java index 6926d3623e2..7c769235b6c 100644 --- a/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/EdgeWebsocket.java +++ b/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/EdgeWebsocket.java @@ -7,7 +7,6 @@ import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.event.EventAdmin; import org.osgi.service.metatype.annotations.Designate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,9 +36,6 @@ public class EdgeWebsocket implements EdgeWebsocketService { @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) protected volatile TimedataService timedataService; - @Reference - protected EventAdmin eventAdmin; - @Activate void activate(Config config) { log.info("Activate EdgeWebsocket [port=" + config.port() + "]"); diff --git a/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/OnClose.java b/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/OnClose.java index 269caf92629..f441133a49c 100644 --- a/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/OnClose.java +++ b/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/OnClose.java @@ -1,14 +1,12 @@ package io.openems.backend.edgewebsocket.impl; -import java.util.HashMap; -import java.util.Map; +import java.util.Optional; import org.java_websocket.WebSocket; -import org.osgi.service.event.Event; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.backend.common.events.BackendEventConstants; +import io.openems.backend.metadata.api.Edge; import io.openems.common.websocket.AbstractOnClose; public class OnClose extends AbstractOnClose { @@ -35,12 +33,21 @@ protected void run(WebSocket websocket, int code, String reason, boolean remote) } } - // announce Edge as offline for (int edgeId : edgeIds) { - Map properties = new HashMap<>(); - properties.put(BackendEventConstants.PROPERTY_KEY_EDGE_ID, edgeId); - Event event = new Event(BackendEventConstants.TOPIC_EDGE_OFFLINE, properties); - this.parent.parent.eventAdmin.postEvent(event); + /* + * if there is no other websocket connection for this edgeId -> announce Edge as + * offline (Another connection could have been opened in the meantime when the + * Edge reconnected) + */ + synchronized (this.parent.websocketsMap) { + if (this.parent.websocketsMap.containsKey(edgeId)) { + continue; + } + } + Optional edgeOpt = this.parent.parent.metadataService.getEdgeOpt(edgeId); + if (edgeOpt.isPresent()) { + edgeOpt.get().setOnline(false); + } } // log diff --git a/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/OnOpen.java b/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/OnOpen.java index a80a9602726..442b0315bbb 100644 --- a/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/OnOpen.java +++ b/io.openems.backend.edgewebsocket.impl/src/io/openems/backend/edgewebsocket/impl/OnOpen.java @@ -1,19 +1,17 @@ package io.openems.backend.edgewebsocket.impl; -import java.util.HashMap; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import org.java_websocket.WebSocket; import org.java_websocket.framing.CloseFrame; import org.java_websocket.handshake.ClientHandshake; -import org.osgi.service.event.Event; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.JsonObject; -import io.openems.backend.common.events.BackendEventConstants; import io.openems.backend.metadata.api.Edge; import io.openems.common.exceptions.OpenemsException; import io.openems.common.websocket.AbstractOnOpen; @@ -54,6 +52,12 @@ protected void run(WebSocket websocket, ClientHandshake handshake) { throw new OpenemsException("Unable to authenticate this Apikey."); } + // get Edge object for edgeIds + List edges = new ArrayList<>(); + for (int edgeId : edgeIds) { + edges.add(this.parent.parent.metadataService.getEdge(edgeId)); // throws Exception if Edge is not found + } + // add edgeIds to websocket attachment attachment.setEdgeIds(edgeIds); @@ -75,27 +79,17 @@ protected void run(WebSocket websocket, ClientHandshake handshake) { WebSocketUtils.send(websocket, jReply); // announce Edge as online - for (int edgeId : edgeIds) { - Map properties = new HashMap<>(); - properties.put(BackendEventConstants.PROPERTY_KEY_EDGE_ID, edgeId); - Event event = new Event(BackendEventConstants.TOPIC_EDGE_ONLINE, properties); - this.parent.parent.eventAdmin.postEvent(event); + for (Edge edge : edges) { + edge.setOnline(true); } // log - for (int edgeId : edgeIds) { - Optional edgeOpt = this.parent.parent.metadataService.getEdgeOpt(edgeId); - if (edgeOpt.isPresent()) { - Edge edge = edgeOpt.get(); - log.info("Edge [" + edge.getName() + "]" // - + (edgeIds.length > 1 ? ", ID [" + edgeId + "]" : "") // - + " connected."); - // set last update timestamps in MetadataService - edge.setLastMessage(); - } else { - log.info("Edge [ID:" + edgeId + "] connected. Apikey [" + apikey + "]. Websocket [" + websocket - + "]."); - } + for (Edge edge : edges) { + log.info("Edge [" + edge.getName() + "]" // + + (edgeIds.length > 1 ? ", ID [" + edge.getId() + "]" : "") // + + " connected."); + // set last update timestamps in MetadataService + edge.setLastMessage(); } } catch (OpenemsException e) { log.warn(e.getMessage()); diff --git a/io.openems.backend.edgewebsocket.impl/test/.gitignore b/io.openems.backend.edgewebsocket.impl/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.backend.metadata.api/src/io/openems/backend/metadata/api/EdgeOnlineHandler.java b/io.openems.backend.metadata.api/src/io/openems/backend/metadata/api/EdgeOnlineHandler.java deleted file mode 100644 index ca003e6615b..00000000000 --- a/io.openems.backend.metadata.api/src/io/openems/backend/metadata/api/EdgeOnlineHandler.java +++ /dev/null @@ -1,45 +0,0 @@ -package io.openems.backend.metadata.api; - -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.event.Event; -import org.osgi.service.event.EventConstants; -import org.osgi.service.event.EventHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.openems.backend.common.events.BackendEventConstants; -import io.openems.common.exceptions.OpenemsException; - -@Component(property = { // - EventConstants.EVENT_TOPIC + "=" + BackendEventConstants.TOPIC_EDGE_ONLINE, - EventConstants.EVENT_TOPIC + "=" + BackendEventConstants.TOPIC_EDGE_OFFLINE }) -public class EdgeOnlineHandler implements EventHandler { - - private final Logger log = LoggerFactory.getLogger(EdgeOnlineHandler.class); - - @Reference - private MetadataService metadataService; - - @Override - public void handleEvent(Event event) { - int edgeId = (int) event.getProperty("edgeId"); - Edge edge; - try { - edge = this.metadataService.getEdge(edgeId); - } catch (OpenemsException e) { - log.warn(e.getMessage()); - return; - } - String topic = (String) event.getProperty("event.topics"); - if (topic.equals(BackendEventConstants.TOPIC_EDGE_ONLINE)) { - edge.setOnline(true); - log.debug("Marked Edge [" + edge.getName() + "] as Online"); - } else if (topic.equals(BackendEventConstants.TOPIC_EDGE_OFFLINE)) { - edge.setOnline(false); - log.debug("Marked Edge [" + edge.getName() + "] as Offline"); - } else { - log.warn("Unknown Topic: " + topic); - } - } -} diff --git a/io.openems.backend.metadata.api/test/.gitignore b/io.openems.backend.metadata.api/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.backend.metadata.dummy/test/.gitignore b/io.openems.backend.metadata.dummy/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.backend.metadata.file/test/.gitignore b/io.openems.backend.metadata.file/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.backend.metadata.odoo/test/.gitignore b/io.openems.backend.metadata.odoo/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.backend.timedata.api/src/io/openems/backend/timedata/api/TimedataService.java b/io.openems.backend.timedata.api/src/io/openems/backend/timedata/api/TimedataService.java index 2623dd68fe9..45638036219 100644 --- a/io.openems.backend.timedata.api/src/io/openems/backend/timedata/api/TimedataService.java +++ b/io.openems.backend.timedata.api/src/io/openems/backend/timedata/api/TimedataService.java @@ -1,22 +1,17 @@ package io.openems.backend.timedata.api; -import java.time.Period; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; -import com.google.gson.JsonArray; import com.google.gson.JsonObject; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.timedata.CommonTimedataService; import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.JsonUtils; @ProviderType -public interface TimedataService { +public interface TimedataService extends CommonTimedataService { /** * Takes a JsonObject and writes the points to database. * @@ -44,68 +39,4 @@ public interface TimedataService { */ public Optional getChannelValue(int edgeId, ChannelAddress channelAddress); - /** - * Queries the database and returns a JsonArray of the form - * - *
    -	 *	[{
    -	 *  	timestamp: "2017-03-21T08:55:20Z",
    -	 *  	channels: {
    -	 *			'thing': {
    -	 *				'channel': 'value'
    -	 *			}
    -	 *		}
    -	 * 	}]
    -	 * 
    - * - * @param edgeId - * @param fromDate - * @param toDate - * @param channels - * @param resolution - * @return - * @throws OpenemsException - */ - public JsonArray queryHistoricData(Optional edgeIdOpt, ZonedDateTime fromDate, ZonedDateTime toDate, - JsonObject channels, int resolution/* , JsonObject kWh */) throws OpenemsException; - - public default JsonArray queryHistoricData(int edgeId, ZonedDateTime fromDate, ZonedDateTime toDate, - JsonObject channels, int resolution/* , JsonObject kWh */) throws OpenemsException { - return this.queryHistoricData(Optional.of(edgeId), fromDate, toDate, channels, resolution); - } - - public default JsonArray queryHistoricData(ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, - int resolution/* , JsonObject kWh */) throws OpenemsException { - return this.queryHistoricData(Optional.empty(), fromDate, toDate, channels, resolution); - } - - public default JsonArray queryHistoricData(int edgeId, JsonObject jHistoricData) throws OpenemsException { - return this.queryHistoricData(Optional.of(edgeId), jHistoricData); - } - - public default JsonArray queryHistoricData(JsonObject jHistoricData) throws OpenemsException { - return this.queryHistoricData(Optional.empty(), jHistoricData); - } - - public default JsonArray queryHistoricData(Optional edgeIdOpt, JsonObject jHistoricData) - throws OpenemsException { - int timezoneDiff = JsonUtils.getAsInt(jHistoricData, "timezone"); - ZoneId timezone = ZoneId.ofOffset("", ZoneOffset.ofTotalSeconds(timezoneDiff * -1)); - ZonedDateTime fromDate = JsonUtils.getAsZonedDateTime(jHistoricData, "fromDate", timezone); - ZonedDateTime toDate = JsonUtils.getAsZonedDateTime(jHistoricData, "toDate", timezone).plusDays(1); - JsonObject channels = JsonUtils.getAsJsonObject(jHistoricData, "channels"); - // TODO check if role is allowed to read these channels - // JsonObject kWh = JsonUtils.getAsJsonObject(jQuery, "kWh"); - int days = Period.between(fromDate.toLocalDate(), toDate.toLocalDate()).getDays(); - // TODO better calculation of sensible resolution - int resolution = 10 * 60; // 10 Minutes - if (days > 25) { - resolution = 24 * 60 * 60; // 1 Day - } else if (days > 6) { - resolution = 3 * 60 * 60; // 3 Hours - } else if (days > 2) { - resolution = 60 * 60; // 60 Minutes - } - return this.queryHistoricData(edgeIdOpt, fromDate, toDate, channels, resolution); - } } diff --git a/io.openems.backend.timedata.influx/bnd.bnd b/io.openems.backend.timedata.influx/bnd.bnd index 1fed1c52d6a..ac0520a4c58 100644 --- a/io.openems.backend.timedata.influx/bnd.bnd +++ b/io.openems.backend.timedata.influx/bnd.bnd @@ -16,7 +16,8 @@ Private-Package: \ io.openems.backend.metadata.api;version=latest,\ com.google.gson;version=2.8,\ com.google.guava;version=19.0,\ - io.openems.wrapper.influxdb-java;version=latest + io.openems.wrapper.influxdb-java;version=latest,\ + io.openems.shared.influxdb;version=latest -testpath: \ osgi.enroute.junit.wrapper;version=4.12, \ diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Influx.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Influx.java index 34b382bca1a..caa1794dd4a 100644 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Influx.java +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Influx.java @@ -9,7 +9,6 @@ import java.util.concurrent.TimeUnit; import org.influxdb.InfluxDB; -import org.influxdb.InfluxDBFactory; import org.influxdb.dto.BatchPoints; import org.influxdb.dto.Point; import org.influxdb.dto.Point.Builder; @@ -33,8 +32,11 @@ import io.openems.backend.metadata.api.MetadataService; import io.openems.backend.timedata.api.TimedataService; import io.openems.common.exceptions.OpenemsException; +import io.openems.common.timedata.Tag; +import io.openems.common.timedata.TimedataUtils; import io.openems.common.types.ChannelAddress; import io.openems.common.utils.JsonUtils; +import io.openems.shared.influxdb.InfluxConnector; @Designate(ocd = Config.class, factory = false) @Component(name = "Timedata.InfluxDB", configurationPolicy = ConfigurationPolicy.REQUIRE) @@ -42,20 +44,13 @@ public class Influx implements TimedataService { private final Logger log = LoggerFactory.getLogger(Influx.class); + private InfluxConnector influxConnector = null; + private final String TMP_MINI_MEASUREMENT = "minies"; @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) protected volatile MetadataService metadataService; - private String database; - private String url; - private int port; - private String username; - private String password; - private String measurement; - - private Optional influxDbOpt = Optional.empty(); - private final Map deviceCacheMap = new HashMap<>(); @Activate @@ -63,51 +58,31 @@ void activate(Config config) throws OpenemsException { log.info("Activate Timedata.InfluxDB [url=" + config.url() + ";port=" + config.port() + ";database=" + config.database() + ";username=" + config.username() + ";password=" + (config.password() != null ? "ok" : "NOT_SET") + ";measurement=" + config.measurement() + "]"); - this.database = config.database(); - this.url = config.url(); - this.port = config.port(); - this.username = config.username(); - this.password = config.password(); - this.measurement = config.measurement(); + + this.influxConnector = new InfluxConnector(config.url(), config.port(), config.username(), config.password(), + config.database()); } @Deactivate void deactivate() { log.info("Deactivate Timedata.InfluxDB"); - if (this.influxDbOpt.isPresent()) { - this.influxDbOpt.get().close(); - - // TODO this works only with a more recent version of Influxdb-Java - // this.influxDbOpt.get().close(); - - } - } - - private synchronized InfluxDB getInfluxDbConnection() throws OpenemsException { - if (!this.influxDbOpt.isPresent()) { - InfluxDB influxDB = InfluxDBFactory.connect("http://" + url + ":" + port, username, password); - try { - influxDB.ping(); - this.influxDbOpt = Optional.of(influxDB); - } catch (RuntimeException e) { - throw new OpenemsException("Unable to connect to InfluxDB: " + e.getMessage()); - } + if (this.influxConnector != null) { + this.influxConnector.deactivate(); } - return this.influxDbOpt.get(); } private void writeData(int influxId, TreeBasedTable data) throws OpenemsException { - InfluxDB influxDB = this.getInfluxDbConnection(); + InfluxDB influxDB = this.influxConnector.getConnection(); - BatchPoints batchPoints = BatchPoints.database(database) // + BatchPoints batchPoints = BatchPoints.database(this.influxConnector.getDatabase()) // .tag("fems", String.valueOf(influxId)) // .build(); for (Entry> entry : data.rowMap().entrySet()) { Long timestamp = entry.getKey(); - Builder builder = Point.measurement(this.measurement) // this builds an InfluxDB record ("point") for a - // given timestamp - .time(timestamp, TimeUnit.MILLISECONDS).fields(entry.getValue()); + // this builds an InfluxDB record ("point") for a given timestamp + Builder builder = Point.measurement(InfluxConnector.MEASUREMENT).time(timestamp, TimeUnit.MILLISECONDS) + .fields(entry.getValue()); batchPoints.point(builder.build()); } @@ -126,9 +101,9 @@ private void writeData(int influxId, TreeBasedTable data) */ private void writeDataToOldMiniMonitoring(Edge edge, int influxId, TreeBasedTable data) throws OpenemsException { - InfluxDB influxDB = getInfluxDbConnection(); + InfluxDB influxDB = this.influxConnector.getConnection(); - BatchPoints batchPoints = BatchPoints.database(database) // + BatchPoints batchPoints = BatchPoints.database(this.influxConnector.getDatabase()) // .tag("fems", String.valueOf(influxId)) // .build(); @@ -184,21 +159,6 @@ private void writeDataToOldMiniMonitoring(Edge edge, int influxId, TreeBasedTabl influxDB.write(batchPoints); } - @Override - public JsonArray queryHistoricData(Optional edgeIdOpt, ZonedDateTime fromDate, ZonedDateTime toDate, - JsonObject channels, int resolution) throws OpenemsException { - Optional influxIdOpt = Optional.empty(); // if given, query only this id. If not given, do not apply - // filter - if (edgeIdOpt.isPresent()) { - Edge edge = this.metadataService.getEdge(edgeIdOpt.get()); - influxIdOpt = Optional.of(InfluxdbUtils.parseNumberFromName(edge.getName())); - } - InfluxDB influxDB = getInfluxDbConnection(); - return InfluxdbUtils.queryHistoricData(influxDB, this.database, influxIdOpt, fromDate, toDate, channels, - resolution); - } - - @Override public Optional getChannelValue(int edgeId, ChannelAddress channelAddress) { DeviceCache deviceCache = this.deviceCacheMap.get(edgeId); if (deviceCache != null) { @@ -211,13 +171,23 @@ public Optional getChannelValue(int edgeId, ChannelAddress channelAddres /** * Takes a JsonObject and writes the points to influxDB. * - * Format: { "timestamp1" { "channel1": value, "channel2": value }, "timestamp2" - * { "channel1": value, "channel2": value } } + * Format: + * + *
    +	 * {
    +	 *   "timestamp1" {
    +	 * 	   "channel1": value,
    +	 *     "channel2": value 
    +	 *   }, "timestamp2" {
    +	 *     "channel1": value,
    +	 *     "channel2": value
    +	 *   }
    +	 * }
    +	 * 
    */ - @Override public void write(int edgeId, JsonObject jData) throws OpenemsException { Edge edge = this.metadataService.getEdge(edgeId); - int influxId = InfluxdbUtils.parseNumberFromName(edge.getName()); + int influxId = TimedataUtils.parseNumberFromName(edge.getName()); TreeBasedTable data = TreeBasedTable.create(); // get existing or create new DeviceCache @@ -282,7 +252,7 @@ public void write(int edgeId, JsonObject jData) throws OpenemsException { // add incoming data to cache (this replaces already existing cache values) for (Entry channelEntry : jChannels.entrySet()) { String channel = channelEntry.getKey(); - Optional valueOpt = InfluxdbUtils.parseValue(channel, channelEntry.getValue()); + Optional valueOpt = Utils.parseValue(channel, channelEntry.getValue()); if (valueOpt.isPresent()) { Object value = valueOpt.get(); deviceCache.putToChannelCache(channel, value); @@ -293,7 +263,7 @@ public void write(int edgeId, JsonObject jData) throws OpenemsException { // add incoming data to write data for (Entry channelEntry : jChannels.entrySet()) { String channel = channelEntry.getKey(); - Optional valueOpt = InfluxdbUtils.parseValue(channel, channelEntry.getValue()); + Optional valueOpt = Utils.parseValue(channel, channelEntry.getValue()); if (valueOpt.isPresent()) { Object value = valueOpt.get(); data.put(timestamp, channel, value); @@ -309,4 +279,10 @@ public void write(int edgeId, JsonObject jData) throws OpenemsException { writeDataToOldMiniMonitoring(edge, influxId, data); } } + + @Override + public JsonArray queryHistoricData(ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, + int resolution, Tag... tags) throws OpenemsException { + return this.influxConnector.queryHistoricData(fromDate, toDate, channels, resolution, tags); + } } diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/InfluxdbUtils.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/InfluxdbUtils.java deleted file mode 100644 index 5d6cb4a823a..00000000000 --- a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/InfluxdbUtils.java +++ /dev/null @@ -1,394 +0,0 @@ -package io.openems.backend.timedata.influx; - -import java.text.NumberFormat; -import java.text.ParseException; -import java.time.Instant; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.influxdb.InfluxDB; -import org.influxdb.dto.Query; -import org.influxdb.dto.QueryResult; -import org.influxdb.dto.QueryResult.Result; -import org.influxdb.dto.QueryResult.Series; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; - -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.JsonUtils; - -public class InfluxdbUtils { - - private final static Logger log = LoggerFactory.getLogger(InfluxdbUtils.class); - - public static JsonArray queryHistoricData(InfluxDB influxdb, String database, Optional influxIdOpt, - ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, int resolution) throws OpenemsException { - // Prepare query string - StringBuilder query = new StringBuilder("SELECT "); - query.append(toChannelAddressList(channels)); - query.append(" FROM data WHERE "); - if (influxIdOpt.isPresent()) { - query.append("fems = '" + influxIdOpt.get() + "' AND "); - } - query.append("time > "); - query.append(String.valueOf(fromDate.toEpochSecond())); - query.append("s"); - query.append(" AND time < "); - query.append(String.valueOf(toDate.toEpochSecond())); - query.append("s"); - query.append(" GROUP BY time("); - query.append(resolution); - query.append("s) fill(null)"); - - QueryResult queryResult = executeQuery(influxdb, database, query.toString()); - - JsonArray j = new JsonArray(); - for (Result result : queryResult.getResults()) { - List seriess = result.getSeries(); - if (seriess != null) { - for (Series series : seriess) { - // create thing/channel index - ArrayList addressIndex = new ArrayList<>(); - for (String column : series.getColumns()) { - if (column.equals("time")) { - continue; - } - addressIndex.add(ChannelAddress.fromString(column)); - } - // first: create empty timestamp objects - for (List values : series.getValues()) { - JsonObject jTimestamp = new JsonObject(); - // get timestamp - Instant timestampInstant = Instant.ofEpochMilli((long) ((Double) values.get(0)).doubleValue()); - ZonedDateTime timestamp = ZonedDateTime.ofInstant(timestampInstant, fromDate.getZone()); - String timestampString = timestamp.format(DateTimeFormatter.ISO_INSTANT); - jTimestamp.addProperty("time", timestampString); - // add empty channels by copying "channels" parameter - JsonObject jChannels = new JsonObject(); - for (Entry entry : channels.entrySet()) { - String thingId = entry.getKey(); - JsonObject jThing = new JsonObject(); - JsonArray channelIds = JsonUtils.getAsJsonArray(entry.getValue()); - for (JsonElement channelElement : channelIds) { - String channelId = JsonUtils.getAsString(channelElement); - jThing.add(channelId, JsonNull.INSTANCE); - } - jChannels.add(thingId, jThing); - } - jTimestamp.add("channels", jChannels); - j.add(jTimestamp); - } - // then: add all data - for (int columnIndex = 1; columnIndex < series.getColumns().size(); columnIndex++) { - for (int timeIndex = 0; timeIndex < series.getValues().size(); timeIndex++) { - Double value = (Double) series.getValues().get(timeIndex).get(columnIndex); - ChannelAddress address = addressIndex.get(columnIndex - 1); - j.get(timeIndex).getAsJsonObject().get("channels").getAsJsonObject() - .get(address.getComponentId()).getAsJsonObject() - .addProperty(address.getChannelId(), value); - } - } - } - } - } - return j; - } - - /** - * Add value to Influx Builder in the correct data format - * - * @param builder - * @param channel - * @param value - * @return - */ - protected static Optional parseValue(String channel, Object value) { - if (value == null) { - return Optional.empty(); - } - // convert JsonElement - if (value instanceof JsonElement) { - JsonElement jValueElement = (JsonElement) value; - if (jValueElement.isJsonPrimitive()) { - JsonPrimitive jValue = jValueElement.getAsJsonPrimitive(); - if (jValue.isNumber()) { - try { - // Avoid GSONs LazilyParsedNumber - value = NumberFormat.getInstance().parse(jValue.toString()); - } catch (ParseException e) { - log.error("Unable to parse Number: " + e.getMessage()); - value = jValue.getAsNumber(); - } - } else if (jValue.isBoolean()) { - value = jValue.getAsBoolean(); - } else if (jValue.isString()) { - value = jValue.getAsString(); - } - } - } - if (value instanceof Number) { - Number numberValue = (Number) value; - if (numberValue instanceof Integer) { - return Optional.of(numberValue.intValue()); - } else if (numberValue instanceof Double) { - return Optional.of(numberValue.doubleValue()); - } else { - return Optional.of(numberValue); - } - } else if (value instanceof Boolean) { - return Optional.of((Boolean) value); - } else if (value instanceof String) { - return Optional.of((String) value); - } - log.warn("Unknown type of value [" + value + "] channel [" + channel + "]. This should never happen."); - return Optional.empty(); - } - - // private static JsonObject querykWh(InfluxDB influxdb, String database, - // Optional fems, - // ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, int - // resolution, JsonObject kWh) - // throws OpenemsException { - // JsonArray gridThing = getGridThing(kWh); - // JsonArray storageThing = getStorageThing(kWh); - // JsonArray things = new JsonArray(); - // things.addAll(storageThing); - // things.addAll(gridThing); - // - // JsonObject jThing = new JsonObject(); - // ArrayList productionChannels = toChannelAddressListAvg(channels, - // things); - // - // for (int i = 0; i < productionChannels.size(); i++) { - // /* - // * SUM data - // */ - // StringBuilder query = new StringBuilder("SELECT SUM(AP) FROM (SELECT - // MEAN(\""); - // query.append(productionChannels.get(i)); - // query.append("\") AS AP FROM data WHERE "); - // if (fems.isPresent()) { - // query.append("fems = '"); - // query.append(fems.get()); - // query.append("' AND "); - // } - // query.append("time > "); - // query.append(String.valueOf(fromDate.toEpochSecond())); - // query.append("s"); - // query.append(" AND time < "); - // query.append(String.valueOf(toDate.toEpochSecond())); - // query.append("s"); - // query.append(" GROUP BY time(1s) fill(previous))"); - // - // QueryResult queryResult = executeQuery(influxdb, database, query.toString()); - // - // Double sumProduction = 0.0; - // try { - // for (Result result : queryResult.getResults()) { - // for (Series serie : result.getSeries()) { - // for (List l : serie.getValues()) { - // sumProduction = (Double) l.get(1); - // } - // } - // } - // } catch (Exception e) { - // System.out.println("Error parsing SUM production: " + e); - // } - // - // /* - // * FIRST production data - // */ - // query = new StringBuilder("SELECT FIRST(\""); - // query.append(productionChannels.get(i)); - // query.append("\") FROM data WHERE "); - // if (fems.isPresent()) { - // query.append("fems = '"); - // query.append(fems.get()); - // query.append("' AND "); - // } - // query.append("time > "); - // query.append(String.valueOf(fromDate.toEpochSecond())); - // query.append("s"); - // query.append(" AND time < "); - // query.append(String.valueOf(toDate.toEpochSecond())); - // query.append("s"); - // - // queryResult = executeQuery(influxdb, database, query.toString()); - // - // int second = 0; - // try { - // for (Result result : queryResult.getResults()) { - // for (Series serie : result.getSeries()) { - // for (List l : serie.getValues()) { - // Instant timestampInstant = Instant.ofEpochMilli((long) ((Double) - // l.get(0)).doubleValue()); - // ZonedDateTime timestamp = ZonedDateTime.ofInstant(timestampInstant, - // fromDate.getZone()); - // if (timestamp.equals(fromDate)) { - // System.out.println("Parsing FIRST: nothing null"); - // } else { - // second = timestamp.getSecond(); - // } - // } - // } - // } - // } catch (Exception e) { - // System.out.println("Error parsing FIRST production: " + e); - // } - // - // /* - // * LAST data - // */ - // query = new StringBuilder("SELECT LAST(\""); - // query.append(productionChannels.get(i)); - // query.append("\") FROM data WHERE "); - // if (fems.isPresent()) { - // query.append("fems = '"); - // query.append(fems.get()); - // query.append("' AND "); - // } - // query.append("time < "); - // query.append(String.valueOf(fromDate.toEpochSecond())); - // query.append("s"); - // - // queryResult = executeQuery(influxdb, query.toString(), database); - // - // try { - // if (queryResult.getResults() != null) { - // for (Result result : queryResult.getResults()) { - // if (result.getSeries() != null) { - // for (Series serie : result.getSeries()) { - // if (serie.getValues() != null) { - // for (List l : serie.getValues()) { - // if (l.get(1) != null) { - // sumProduction += (Double) l.get(1) * second; - // } - // } - // } - // } - // } - // } - // } - // } catch (Exception e) { - // System.out.println("Error parsing LAST production: " + e); - // } - // - // Double avg = sumProduction / 3600 / 1000; - // - // JsonObject element = new JsonObject(); - // element.addProperty("value", avg); - // element.addProperty("type", - // JsonUtils.getAsString(kWh.get(productionChannels.get(i)))); - // jThing.add(productionChannels.get(i).toString(), element); - // } - // - // return jThing; - // } - - // private static JsonArray getGridThing(JsonObject kWh) throws OpenemsException - // { - // JsonArray gridThing = new JsonArray(); - // for (Entry entry : kWh.entrySet()) { - // String thingId = entry.getKey(); - // if (JsonUtils.getAsString(entry.getValue()).equals("grid")) { - // gridThing.add(thingId); - // } - // } - // return gridThing; - // } - // - // private static JsonArray getStorageThing(JsonObject kWh) throws - // OpenemsException { - // JsonArray storageThing = new JsonArray(); - // for (Entry entry : kWh.entrySet()) { - // String thingId = entry.getKey(); - // if (JsonUtils.getAsString(entry.getValue()).equals("storage")) { - // storageThing.add(thingId); - // } - // } - // return storageThing; - // } - // - // private static ArrayList toChannelAddressListAvg(JsonObject channels, - // JsonArray things) - // throws OpenemsException { - // ArrayList channelAddresses = new ArrayList<>(); - // for (Entry entry : channels.entrySet()) { - // String thingId = entry.getKey(); - // JsonArray channelIds = JsonUtils.getAsJsonArray(entry.getValue()); - // for (JsonElement channelElement : channelIds) { - // String channelId = JsonUtils.getAsString(channelElement); - // if (channelId.contains("ActivePower")) { - // String name = thingId + "/" + channelId; - // boolean isGridOrStorage = false; - // for (int i = 0; i < things.size(); i++) { - // if (JsonUtils.getAsString(things.get(i)).equals(name)) { - // isGridOrStorage = true; - // } - // } - // if (!isGridOrStorage) { - // channelAddresses.add(thingId + "/" + channelId); - // } - // } - // } - // } - // return channelAddresses; - // } - - private static String toChannelAddressList(JsonObject channels) throws OpenemsException { - ArrayList channelAddresses = new ArrayList<>(); - for (Entry entry : channels.entrySet()) { - String thingId = entry.getKey(); - JsonArray channelIds = JsonUtils.getAsJsonArray(entry.getValue()); - for (JsonElement channelElement : channelIds) { - String channelId = JsonUtils.getAsString(channelElement); - channelAddresses - .add("MEAN(\"" + thingId + "/" + channelId + "\") AS \"" + thingId + "/" + channelId + "\""); - } - } - return String.join(", ", channelAddresses); - } - - private static QueryResult executeQuery(InfluxDB influxdb, String database, String query) throws OpenemsException { - // Parse result - QueryResult queryResult; - try { - queryResult = influxdb.query(new Query(query, database), TimeUnit.MILLISECONDS); - } catch (RuntimeException e) { - throw new OpenemsException("InfluxDB query runtime error. Query: " + query + ", Error: " + e.getMessage()); - } - if (queryResult.hasError()) { - throw new OpenemsException("InfluxDB query error. Query: " + query + ", Error: " + queryResult.getError()); - } - return queryResult; - } - - private final static Pattern NAME_NUMBER_PATTERN = Pattern.compile("[^0-9]+([0-9]+)$"); - - public static Integer parseNumberFromName(String name) throws OpenemsException { - try { - Matcher matcher = NAME_NUMBER_PATTERN.matcher(name); - if (matcher.find()) { - String nameNumberString = matcher.group(1); - return Integer.parseInt(nameNumberString); - } - } catch (NullPointerException e) { - /* ignore */ - } - throw new OpenemsException("Unable to parse number from name [" + name + "]"); - } -} diff --git a/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Utils.java b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Utils.java new file mode 100644 index 00000000000..ebf8e842806 --- /dev/null +++ b/io.openems.backend.timedata.influx/src/io/openems/backend/timedata/influx/Utils.java @@ -0,0 +1,66 @@ +package io.openems.backend.timedata.influx; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +public class Utils { + + private final static Logger log = LoggerFactory.getLogger(Utils.class); + + /** + * Add value to Influx Builder in the correct data format + * + * @param builder + * @param channel + * @param value + * @return + */ + protected static Optional parseValue(String channel, Object value) { + if (value == null) { + return Optional.empty(); + } + // convert JsonElement + if (value instanceof JsonElement) { + JsonElement jValueElement = (JsonElement) value; + if (jValueElement.isJsonPrimitive()) { + JsonPrimitive jValue = jValueElement.getAsJsonPrimitive(); + if (jValue.isNumber()) { + try { + // Avoid GSONs LazilyParsedNumber + value = NumberFormat.getInstance().parse(jValue.toString()); + } catch (ParseException e) { + log.error("Unable to parse Number: " + e.getMessage()); + value = jValue.getAsNumber(); + } + } else if (jValue.isBoolean()) { + value = jValue.getAsBoolean(); + } else if (jValue.isString()) { + value = jValue.getAsString(); + } + } + } + if (value instanceof Number) { + Number numberValue = (Number) value; + if (numberValue instanceof Integer) { + return Optional.of(numberValue.intValue()); + } else if (numberValue instanceof Double) { + return Optional.of(numberValue.doubleValue()); + } else { + return Optional.of(numberValue); + } + } else if (value instanceof Boolean) { + return Optional.of((Boolean) value); + } else if (value instanceof String) { + return Optional.of((String) value); + } + log.warn("Unknown type of value [" + value + "] channel [" + channel + "]. This should never happen."); + return Optional.empty(); + } +} diff --git a/io.openems.backend.timedata.influx/test/.gitignore b/io.openems.backend.timedata.influx/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.backend.uiwebsocket.impl/src/io/openems/backend/uiwebsocket/impl/provider/OnMessage.java b/io.openems.backend.uiwebsocket.impl/src/io/openems/backend/uiwebsocket/impl/provider/OnMessage.java index bc18352b061..e873ec456e2 100644 --- a/io.openems.backend.uiwebsocket.impl/src/io/openems/backend/uiwebsocket/impl/provider/OnMessage.java +++ b/io.openems.backend.uiwebsocket.impl/src/io/openems/backend/uiwebsocket/impl/provider/OnMessage.java @@ -7,13 +7,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonArray; import com.google.gson.JsonObject; import io.openems.backend.metadata.api.Edge; import io.openems.backend.metadata.api.User; import io.openems.common.exceptions.OpenemsException; import io.openems.common.session.Role; +import io.openems.common.timedata.Tag; +import io.openems.common.timedata.TimedataUtils; import io.openems.common.utils.JsonUtils; import io.openems.common.utils.StringUtils; import io.openems.common.websocket.AbstractOnMessage; @@ -178,16 +179,11 @@ private synchronized void currentData(WebSocket websocket, WebsocketData data, J */ private void historicData(WebSocket websocket, JsonObject jMessageId, int edgeId, JsonObject jHistoricData) { try { - String mode = JsonUtils.getAsString(jHistoricData, "mode"); - - if (mode.equals("query")) { - /* - * Query historic data - */ - JsonArray jData = this.parent.parent.timeDataService.queryHistoricData(edgeId, jHistoricData); - WebSocketUtils.sendOrLogError(websocket, DefaultMessages.historicDataQueryReply(jMessageId, jData)); - return; - } + Edge edge = this.parent.parent.metadataService.getEdge(edgeId); + Tag[] tags = new Tag[] { new Tag("fems", TimedataUtils.parseNumberFromName(edge.getName())) }; + JsonObject j = TimedataUtils.handle(this.parent.parent.timeDataService, jMessageId, jHistoricData, tags); + WebSocketUtils.sendOrLogError(websocket, j); + return; } catch (Exception e) { WebSocketUtils.sendNotificationOrLogError(websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.UNABLE_TO_QUERY_HISTORIC_DATA, "Edge [ID:" + edgeId + "] " + e.getMessage()); diff --git a/io.openems.backend.uiwebsocket.impl/test/.gitignore b/io.openems.backend.uiwebsocket.impl/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.common/bnd.bnd b/io.openems.common/bnd.bnd index 9959ace11aa..4da5fdf2fb4 100644 --- a/io.openems.common/bnd.bnd +++ b/io.openems.common/bnd.bnd @@ -10,7 +10,8 @@ Export-Package: \ io.openems.common.api,\ io.openems.common.websocket,\ io.openems.common.config,\ - io.openems.common + io.openems.common,\ + io.openems.common.timedata -includeresource: {readme.md} diff --git a/io.openems.common/src/io/openems/common/OpenemsConstants.java b/io.openems.common/src/io/openems/common/OpenemsConstants.java index bcad465108d..4bcd3689873 100644 --- a/io.openems.common/src/io/openems/common/OpenemsConstants.java +++ b/io.openems.common/src/io/openems/common/OpenemsConstants.java @@ -2,7 +2,7 @@ public class OpenemsConstants { - public final static String OPENEMS_VERSION = "2018.8.0"; + public final static String OPENEMS_VERSION = "2018.9.0"; // public final static String OPENEMS_VERSION = "2018.9.0-SNAPSHOT"; diff --git a/io.openems.common/src/io/openems/common/timedata/CommonTimedataService.java b/io.openems.common/src/io/openems/common/timedata/CommonTimedataService.java new file mode 100644 index 00000000000..71a8d623553 --- /dev/null +++ b/io.openems.common/src/io/openems/common/timedata/CommonTimedataService.java @@ -0,0 +1,29 @@ +package io.openems.common.timedata; + +import java.time.ZonedDateTime; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsException; + +public interface CommonTimedataService { + + /** + * Queries the database and returns a JsonArray of the form + * + *
    +	 *	[{
    +	 *  	timestamp: "2017-03-21T08:55:20Z",
    +	 *  	channels: {
    +	 *			'thing': {
    +	 *				'channel': 'value'
    +	 *			}
    +	 *		}
    +	 * 	}]
    +	 * 
    + */ + public JsonArray queryHistoricData(ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, + int resolution, Tag... tags) throws OpenemsException; + +} diff --git a/io.openems.common/src/io/openems/common/timedata/Tag.java b/io.openems.common/src/io/openems/common/timedata/Tag.java new file mode 100644 index 00000000000..0e71ce770f8 --- /dev/null +++ b/io.openems.common/src/io/openems/common/timedata/Tag.java @@ -0,0 +1,20 @@ +package io.openems.common.timedata; + +public class Tag { + private final String name; + private final int value; + + public Tag(String name, int value) { + super(); + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public int getValue() { + return value; + } +} diff --git a/io.openems.common/src/io/openems/common/timedata/TimedataUtils.java b/io.openems.common/src/io/openems/common/timedata/TimedataUtils.java new file mode 100644 index 00000000000..d6905d9b644 --- /dev/null +++ b/io.openems.common/src/io/openems/common/timedata/TimedataUtils.java @@ -0,0 +1,67 @@ +package io.openems.common.timedata; + +import java.time.Period; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.utils.JsonUtils; +import io.openems.common.websocket.DefaultMessages; + +public class TimedataUtils { + + public static JsonObject handle(CommonTimedataService timeDataService, JsonObject jMessageId, + JsonObject jHistoricData, Tag... tags) throws OpenemsException { + String mode = JsonUtils.getAsString(jHistoricData, "mode"); + + if (mode.equals("query")) { + /* + * Query historic data + */ + int timezoneDiff = JsonUtils.getAsInt(jHistoricData, "timezone"); + ZoneId timezone = ZoneId.ofOffset("", ZoneOffset.ofTotalSeconds(timezoneDiff * -1)); + ZonedDateTime fromDate = JsonUtils.getAsZonedDateTime(jHistoricData, "fromDate", timezone); + ZonedDateTime toDate = JsonUtils.getAsZonedDateTime(jHistoricData, "toDate", timezone).plusDays(1); + JsonObject channels = JsonUtils.getAsJsonObject(jHistoricData, "channels"); + // TODO check if role is allowed to read these channels + // JsonObject kWh = JsonUtils.getAsJsonObject(jQuery, "kWh"); + int days = Period.between(fromDate.toLocalDate(), toDate.toLocalDate()).getDays(); + // TODO better calculation of sensible resolution + int resolution = 10 * 60; // 10 Minutes + if (days > 25) { + resolution = 24 * 60 * 60; // 1 Day + } else if (days > 6) { + resolution = 3 * 60 * 60; // 3 Hours + } else if (days > 2) { + resolution = 60 * 60; // 60 Minutes + } + + JsonArray jData = timeDataService.queryHistoricData(fromDate, toDate, channels, resolution, tags); + return DefaultMessages.historicDataQueryReply(jMessageId, jData); + } + + throw new OpenemsException("Undefined Timedata mode."); + } + + private final static Pattern NAME_NUMBER_PATTERN = Pattern.compile("[^0-9]+([0-9]+)$"); + + public static Integer parseNumberFromName(String name) throws OpenemsException { + try { + Matcher matcher = NAME_NUMBER_PATTERN.matcher(name); + if (matcher.find()) { + String nameNumberString = matcher.group(1); + return Integer.parseInt(nameNumberString); + } + } catch (NullPointerException e) { + /* ignore */ + } + throw new OpenemsException("Unable to parse number from name [" + name + "]"); + } + +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/package-info.java b/io.openems.common/src/io/openems/common/timedata/package-info.java similarity index 57% rename from io.openems.edge.ess.api/src/io/openems/edge/ess/power/package-info.java rename to io.openems.common/src/io/openems/common/timedata/package-info.java index 4d92f8582bb..1fe35548382 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/package-info.java +++ b/io.openems.common/src/io/openems/common/timedata/package-info.java @@ -1,2 +1,2 @@ @org.osgi.annotation.versioning.Version("1.0.0") -package io.openems.edge.ess.power; +package io.openems.common.timedata; diff --git a/io.openems.common/src/io/openems/common/utils/IntUtils.java b/io.openems.common/src/io/openems/common/utils/IntUtils.java index 526f18a62f1..a0cef50e522 100644 --- a/io.openems.common/src/io/openems/common/utils/IntUtils.java +++ b/io.openems.common/src/io/openems/common/utils/IntUtils.java @@ -16,7 +16,7 @@ public enum Round { * @param precision * @return */ - public static int roundToPrecision(int value, Round round, int precision) { + public static int roundToPrecision(float value, Round round, int precision) { switch (round) { case DOWN: return (int) (Math.floor(value / precision) * precision); diff --git a/io.openems.common/src/io/openems/common/utils/Mutex.java b/io.openems.common/src/io/openems/common/utils/Mutex.java new file mode 100644 index 00000000000..446b090e289 --- /dev/null +++ b/io.openems.common/src/io/openems/common/utils/Mutex.java @@ -0,0 +1,35 @@ +package io.openems.common.utils; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +public class Mutex { + + private final Semaphore semaphore; + + public Mutex(boolean initiallyPermitted) { + if (initiallyPermitted) { + semaphore = new Semaphore(1); + } else { + semaphore = new Semaphore(0); + } + } + + public void await() throws InterruptedException { + int permits = semaphore.drainPermits(); + if (permits == 0) { + semaphore.acquire(); + } + } + + public void awaitOrTimeout(int timeout, TimeUnit unit) throws InterruptedException { + int permits = semaphore.drainPermits(); + if (permits == 0) { + semaphore.tryAcquire(timeout, unit); + } + } + + public void release() { + semaphore.release(); + } +} diff --git a/io.openems.common/test/.gitignore b/io.openems.common/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.common/test/io/openems/common/utils/IntUtilsTest.java b/io.openems.common/test/io/openems/common/utils/IntUtilsTest.java index b256e3418a2..d4917fb8df9 100644 --- a/io.openems.common/test/io/openems/common/utils/IntUtilsTest.java +++ b/io.openems.common/test/io/openems/common/utils/IntUtilsTest.java @@ -19,6 +19,14 @@ public void testRoundToPrecision() { assertEquals(1300, IntUtils.roundToPrecision(1300, Round.DOWN, 100)); assertEquals(1200, IntUtils.roundToPrecision(1299, Round.DOWN, 100)); + + assertEquals(10000, IntUtils.roundToPrecision(1, Round.UP, 10000)); + + assertEquals(0, IntUtils.roundToPrecision(9999, Round.DOWN, 10000)); + + assertEquals(4992, IntUtils.roundToPrecision(5000, Round.DOWN, 52)); + + assertEquals(5044, IntUtils.roundToPrecision(5000, Round.UP, 52)); } } diff --git a/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java b/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java new file mode 100644 index 00000000000..cf596422af2 --- /dev/null +++ b/io.openems.common/test/io/openems/common/utils/StringUtilsTest.java @@ -0,0 +1,39 @@ +package io.openems.common.utils; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +public class StringUtilsTest { + + @Test + public void testToShortStringStringInt() { + String test = "test to short string"; + assertEquals("te...", StringUtils.toShortString(test, 5)); + + } + + @Test + public void testToShortStringJsonObjectInt() { + JsonObject j = new JsonObject(); + j.add("name", new JsonPrimitive("Testbert")); // {"name":"Testbert"} --> {"name":"T... + assertEquals("{\"name\":\"T...", StringUtils.toShortString(j, 13)); + } + + @Test + public void testCapitalizeFirstLetter() { + assertEquals("Test", StringUtils.capitalizeFirstLetter("test")); + assertEquals("TEST", StringUtils.capitalizeFirstLetter("TEST")); + assertEquals("1test", StringUtils.capitalizeFirstLetter("1test")); + } + + @Test(expected=IndexOutOfBoundsException.class) + public void testCapitalizeFirstLetterWithEmptyString() { + assertEquals("", StringUtils.capitalizeFirstLetter("")); + + } + +} diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun index 1cf12373bbd..83d1fea059d 100644 --- a/io.openems.edge.application/EdgeApp.bndrun +++ b/io.openems.edge.application/EdgeApp.bndrun @@ -1,8 +1,3 @@ -# -# RUN SPECIFICATION -# - - Bundle-Version: 1.0.0.${tstamp} Bundle-SymbolicName: io.openems.edge.application.launch JPM-Command: openems-edge @@ -21,57 +16,77 @@ JPM-Command: openems-edge osgi.identity;filter:='(osgi.identity=io.openems.edge.application)',\ osgi.identity;filter:='(osgi.identity=org.ops4j.pax.logging.pax-logging-api)',\ osgi.identity;filter:='(osgi.identity=org.ops4j.pax.logging.pax-logging-service)',\ - osgi.identity;filter:='(osgi.identity=io.openems.common)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.scheduler.fixedorder)',\ osgi.identity;filter:='(osgi.identity=org.apache.felix.webconsole)',\ osgi.identity;filter:='(osgi.identity=osgi.enroute.webconsole.xray.provider)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.meter.janitza.umg96rme)',\ + osgi.identity;filter:='(osgi.identity=io.openems.common)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.battery.soltaro)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.bridge.modbus)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.core)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.api.backend)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.api.core)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.api.websocket)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.channelthreshold)',\ osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.debug.log)',\ osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.debug.detailedlog)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.bridge.modbus)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.meter.socomec.dirisa14)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.fenecon.commercial40)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.channelthreshold)',\ osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.symmetric.fixactivepower)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.symmetric.fixreactivepower)',\ osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.symmetric.balancing)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.core)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.cluster)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.core)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.fenecon.commercial40)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.kaco.blueplanet.gridsave50)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.kostal.piko)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.streetscooter)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.evcs.keba.kecontact)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.io.kmtronic)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.meter.carlo.gavazzi.em300)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.meter.janitza.umg96rme)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.meter.socomec.dirisa14)',\ osgi.identity;filter:='(osgi.identity=io.openems.edge.scheduler.allalphabetically)',\ + osgi.identity;filter:='(osgi.identity=io.openems.edge.scheduler.fixedorder)',\ osgi.identity;filter:='(osgi.identity=io.openems.edge.simulator)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.timedata.influxdb)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.api.websocket)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.api.backend)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.io.kmtronic)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.channelthreshold)',\ - osgi.identity;filter:='(osgi.identity=io.openems.edge.evcs.keba.kecontact)',\ - bnd.identity;id='io.openems.edge.core' - --resolve: auto + osgi.identity;filter:='(osgi.identity=io.openems.edge.timedata.influxdb)' + -runbundles: \ com.google.gson;version='[2.8.2,2.8.3)',\ + com.google.guava;version='[25.1.0,25.1.1)',\ com.sun.jna;version='[4.2.2,4.2.3)',\ io.openems.common;version=snapshot,\ io.openems.edge.application;version=snapshot,\ + io.openems.edge.battery.soltaro;version=snapshot,\ io.openems.edge.bridge.modbus;version=snapshot,\ io.openems.edge.common;version=snapshot,\ - io.openems.edge.controller.api;version=snapshot,\ io.openems.edge.controller.api.backend;version=snapshot,\ + io.openems.edge.controller.api.core;version=snapshot,\ io.openems.edge.controller.api.websocket;version=snapshot,\ io.openems.edge.controller.channelthreshold;version=snapshot,\ io.openems.edge.controller.debug.detailedlog;version=snapshot,\ io.openems.edge.controller.debug.log;version=snapshot,\ io.openems.edge.controller.symmetric.balancing;version=snapshot,\ io.openems.edge.controller.symmetric.fixactivepower;version=snapshot,\ + io.openems.edge.controller.symmetric.fixreactivepower;version=snapshot,\ + io.openems.edge.core;version=snapshot,\ + io.openems.edge.ess.cluster;version=snapshot,\ + io.openems.edge.ess.core;version=snapshot,\ io.openems.edge.ess.fenecon.commercial40;version=snapshot,\ + io.openems.edge.ess.kaco.blueplanet.gridsave50;version=snapshot,\ + io.openems.edge.ess.kostal.piko;version=snapshot,\ + io.openems.edge.ess.streetscooter;version=snapshot,\ io.openems.edge.evcs.keba.kecontact;version=snapshot,\ io.openems.edge.io.kmtronic;version=snapshot,\ + io.openems.edge.meter.carlo.gavazzi.em300;version=snapshot,\ io.openems.edge.meter.janitza.umg96rme;version=snapshot,\ io.openems.edge.meter.socomec.dirisa14;version=snapshot,\ io.openems.edge.scheduler.allalphabetically;version=snapshot,\ io.openems.edge.scheduler.fixedorder;version=snapshot,\ io.openems.edge.simulator;version=snapshot,\ io.openems.edge.timedata.influxdb;version=snapshot,\ + io.openems.shared.influxdb;version=snapshot,\ io.openems.wrapper.influxdb-java;version=snapshot,\ io.openems.wrapper.j2mod;version=snapshot,\ io.openems.wrapper.jSerialComm;version=snapshot,\ - io.openems.wrapper.jts;version=snapshot,\ io.openems.wrapper.moshi;version=snapshot,\ io.openems.wrapper.retrofit2;version=snapshot,\ io.openems.wrapper.retrofit2-converter-moshi;version=snapshot,\ @@ -80,6 +95,7 @@ JPM-Command: openems-edge json;version='[20160212.0.0,20160212.0.1)',\ org.apache.commons.fileupload;version='[1.3.2,1.3.3)',\ org.apache.commons.io;version='[2.5.0,2.5.1)',\ + org.apache.commons.math3;version='[3.6.0,3.6.1)',\ org.apache.felix.configadmin;version='[1.8.8,1.8.9)',\ org.apache.felix.http.jetty;version='[3.2.0,3.2.1)',\ org.apache.felix.http.servlet-api;version='[1.1.2,1.1.3)',\ @@ -98,5 +114,4 @@ JPM-Command: openems-edge osgi.enroute.executor.simple.provider;version='[2.1.0,2.1.1)',\ osgi.enroute.web.simple.provider;version='[2.1.0,2.1.1)',\ osgi.enroute.webconsole.xray.provider;version='[2.1.0,2.1.1)',\ - io.openems.edge.core;version=snapshot,\ - com.google.guava;version='[25.1.0,25.1.1)' \ No newline at end of file + org.osgi.compendium;version='[4.1.0,4.1.1)' diff --git a/io.openems.edge.application/bnd.bnd b/io.openems.edge.application/bnd.bnd index 739fd5d026d..eb7740c0696 100644 --- a/io.openems.edge.application/bnd.bnd +++ b/io.openems.edge.application/bnd.bnd @@ -22,3 +22,4 @@ EnRoute-Application: io.openems.edge.application osgi.enroute.junit.wrapper;version=4.12 -runfw: org.eclipse.osgi;version='[3.10.100.v20150529-1857,3.10.100.v20150529-1857]' -runee: JavaSE-1.8 +-runbundles: org.apache.felix.log;version='[1.0.1,1.0.2)' \ No newline at end of file diff --git a/io.openems.edge.application/src/io/openems/edge/application/EdgeApp.java b/io.openems.edge.application/src/io/openems/edge/application/EdgeApp.java index 9af641c2221..5e1ea3b633c 100644 --- a/io.openems.edge.application/src/io/openems/edge/application/EdgeApp.java +++ b/io.openems.edge.application/src/io/openems/edge/application/EdgeApp.java @@ -46,6 +46,8 @@ void activate() { log4j.put("log4j.logger.org.apache.felix.configadmin", "INFO"); log4j.put("log4j.logger.sun.net.www.protocol.http.HttpURLConnection", "INFO"); log4j.put("log4j.logger.com.ghgande.j2mod", "INFO"); + log4j.put("log4j.logger.io.openems.edge.ess.streetscooter", "DEBUG"); + log4j.put("log4j.logger.io.openems.edge.ess.power", "INFO"); config.update(log4j); } catch (IOException | SecurityException e) { e.printStackTrace(); diff --git a/io.openems.edge.battery.api/.classpath b/io.openems.edge.battery.api/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.battery.api/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.battery.api/.gitignore b/io.openems.edge.battery.api/.gitignore new file mode 100644 index 00000000000..36573722b7e --- /dev/null +++ b/io.openems.edge.battery.api/.gitignore @@ -0,0 +1,2 @@ +/generated/ +/bin_test/ diff --git a/io.openems.edge.battery.api/bnd.bnd b/io.openems.edge.battery.api/bnd.bnd new file mode 100644 index 00000000000..7f23de14796 --- /dev/null +++ b/io.openems.edge.battery.api/bnd.bnd @@ -0,0 +1,19 @@ +Bundle-Name: OpenEMS Edge Battery Api +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.battery.api +Require-Capability: \ + compile-only + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.common;version=latest,\ + io.openems.common;version=latest + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 \ No newline at end of file diff --git a/io.openems.edge.battery.api/readme.md b/io.openems.edge.battery.api/readme.md new file mode 100644 index 00000000000..d00418c400d --- /dev/null +++ b/io.openems.edge.battery.api/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.battery.api + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java new file mode 100644 index 00000000000..9a697213bea --- /dev/null +++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Battery.java @@ -0,0 +1,170 @@ +package io.openems.edge.battery.api; + +import org.osgi.annotation.versioning.ProviderType; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.common.component.OpenemsComponent; + +@ProviderType +public interface Battery extends OpenemsComponent { + + public enum GridMode { + UNDEFINED, ON_GRID, OFF_GRID + } + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + /** + * State of Charge + * + *
      + *
    • Interface: Battery + *
    • Type: Integer + *
    • Unit: % + *
    • Range: 0..100 + *
    + */ + SOC(new Doc().type(OpenemsType.INTEGER).unit(Unit.PERCENT)), + /** + * Grid-Mode + * + *
      + *
    • Interface: Battery + *
    • Type: Integer/Enum + *
    • Range: 0=Undefined, 1=On-Grid, 2=Off-Grid + *
    + */ + GRID_MODE(new Doc().type(OpenemsType.INTEGER) // + .option(GridMode.UNDEFINED) // + .option(GridMode.ON_GRID) // + .option(GridMode.OFF_GRID) // + ), + /** + * Max capacity + * + *
      + *
    • Interface: Battery + *
    • Type: Integer + *
    • Unit: Wh + *
    + */ + MAX_CAPACITY(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT_HOURS)), + /** + * Min voltage for discharging + * + *
      + *
    • Interface: Battery + *
    • Type: Integer + *
    • Unit: V + *
    + */ + DISCHARGE_MIN_VOLTAGE(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT)), + /** + * Max current for discharging + * + *
      + *
    • Interface: Battery + *
    • Type: Integer + *
    • Unit: V + *
    + */ + DISCHARGE_MAX_CURRENT(new Doc().type(OpenemsType.INTEGER).unit(Unit.AMPERE)), + /** + * Maximal voltage for charging + * + *
      + *
    • Interface: Battery + *
    • Type: Integer + *
    • Unit: V + *
    + */ + CHARGE_MAX_VOLTAGE(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT)), + /** + * Max current for charging + * + *
      + *
    • Interface: Battery + *
    • Type: Integer + *
    • Unit: V + *
    + */ + CHARGE_MAX_CURRENT(new Doc().type(OpenemsType.INTEGER).unit(Unit.AMPERE)), + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the State of Charge in [%], range 0..100 % + * + * @return + */ + default Channel getSoc() { + return this.channel(ChannelId.SOC); + } + + /** + * Is the Battery On-Grid? + * + * @return + */ + default Channel getGridMode() { + return this.channel(ChannelId.GRID_MODE); + } + + /** + * Gets the maximum capacity + * + * @return + */ + default Channel getMaxCapacity() { + return this.channel(ChannelId.MAX_CAPACITY); + } + + /** + * Gets the min voltage for discharging + * + * @return + */ + default Channel getDischargeMinVoltage() { + return this.channel(ChannelId.DISCHARGE_MIN_VOLTAGE); + } + + /** + * Gets the max current for discharging + * + * @return + */ + default Channel getDischargeMaxCurrent() { + return this.channel(ChannelId.DISCHARGE_MAX_CURRENT); + } + + /** + * Gets the max voltage for charging + * + * @return + */ + default Channel getChargeMaxVoltage() { + return this.channel(ChannelId.CHARGE_MAX_VOLTAGE); + } + + /** + * Gets the max current for charging + * + * @return + */ + default Channel getChargeMaxCurrent() { + return this.channel(ChannelId.CHARGE_MAX_CURRENT); + } +} diff --git a/io.openems.edge.battery.api/test/.gitignore b/io.openems.edge.battery.api/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.battery.soltaro/.classpath b/io.openems.edge.battery.soltaro/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.battery.soltaro/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.battery.soltaro/.gitignore b/io.openems.edge.battery.soltaro/.gitignore new file mode 100644 index 00000000000..36573722b7e --- /dev/null +++ b/io.openems.edge.battery.soltaro/.gitignore @@ -0,0 +1,2 @@ +/generated/ +/bin_test/ diff --git a/io.openems.edge.battery.soltaro/bnd.bnd b/io.openems.edge.battery.soltaro/bnd.bnd new file mode 100644 index 00000000000..61b67e3294f --- /dev/null +++ b/io.openems.edge.battery.soltaro/bnd.bnd @@ -0,0 +1,22 @@ +Bundle-Name: OpenEMS Edge Soltaro Battery +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.battery.soltaro,\ + io.openems.edge.battery.api + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.common;version=latest,\ + io.openems.common;version=latest,\ + io.openems.edge.bridge.modbus,\ + io.openems.edge.battery.api;version=latest + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 + +-runbundles: org.apache.felix.log;version='[1.0.1,1.0.2)' \ No newline at end of file diff --git "a/io.openems.edge.battery.soltaro/doc/\345\202\250\350\203\275BMS\344\270\216PCS ModBus\351\200\232\350\256\257\345\215\217\350\256\256_\345\215\225\347\260\207EN_7.2.docx" "b/io.openems.edge.battery.soltaro/doc/\345\202\250\350\203\275BMS\344\270\216PCS ModBus\351\200\232\350\256\257\345\215\217\350\256\256_\345\215\225\347\260\207EN_7.2.docx" new file mode 100644 index 00000000000..b6308364a1c Binary files /dev/null and "b/io.openems.edge.battery.soltaro/doc/\345\202\250\350\203\275BMS\344\270\216PCS ModBus\351\200\232\350\256\257\345\215\217\350\256\256_\345\215\225\347\260\207EN_7.2.docx" differ diff --git a/io.openems.edge.battery.soltaro/readme.md b/io.openems.edge.battery.soltaro/readme.md new file mode 100644 index 00000000000..155ba30b776 --- /dev/null +++ b/io.openems.edge.battery.soltaro/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.battery.soltaro + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Config.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Config.java new file mode 100644 index 00000000000..272e51918e4 --- /dev/null +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Config.java @@ -0,0 +1,23 @@ +package io.openems.edge.battery.soltaro; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition( // + name = "BMS FENECON Soltaro", // + description = "Implements the Soltaro battery rack system.") +@interface Config { + String service_pid(); + + String id() default "bms0"; + + boolean enabled() default true; + + @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.") + String modbus_id(); + + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default ""; + + String webconsole_configurationFactory_nameHint() default "BMS FENECON Soltaro [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroRack.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroRack.java new file mode 100644 index 00000000000..3a13600eb13 --- /dev/null +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroRack.java @@ -0,0 +1,1105 @@ +package io.openems.edge.battery.soltaro; + +import java.util.Optional; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.battery.api.Battery; +import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; +import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; +import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; +import io.openems.edge.bridge.modbus.api.task.FC6WriteRegisterTask; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.IntegerWriteChannel; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Level; +import io.openems.edge.common.channel.doc.OptionsEnum; +import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.taskmanager.Priority; + +@Designate(ocd = Config.class, factory = true) +@Component( // + name = "Bms.Fenecon.Soltaro", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE // +) +public class SoltaroRack extends AbstractOpenemsModbusComponent implements Battery, OpenemsComponent, EventHandler { + + private final Logger log = LoggerFactory.getLogger(SoltaroRack.class); + + protected final static int UNIT_ID = 0x1; + protected final static int SYSTEM_ON = 1; + protected final static int SYSTEM_OFF = 0; + + private String modbusBridgeId; + + @Reference + protected ConfigurationAdmin cm; + + public SoltaroRack() { + log.info("initializing channels"); + Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); + } + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + @Activate + void activate(ComponentContext context, Config config) { + super.activate(context, config.service_pid(), config.id(), config.enabled(), UNIT_ID, this.cm, "Modbus", + config.modbus_id()); + this.modbusBridgeId = config.modbus_id(); + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + public String getModbusBridgeId() { + return modbusBridgeId; + } + + public enum ChargeIndication implements OptionsEnum { + + STANDING(0, "Standing"), DISCHARGING(1, "Discharging"), CHARGING(2, "Charging"); + + private int value; + private String option; + + private ChargeIndication(int value, String option) { + this.value = value; + this.option = option; + } + + @Override + public int getValue() { + return value; + } + + @Override + public String getOption() { + return option; + } + } + + public enum ContactorControl implements OptionsEnum { + + CUT_OFF(0, "Cut off"), CONNECTION_INITIATING(1, "Connection initiating"), ON_GRID(3, "On grid"); + + int value; + String option; + + private ContactorControl(int value, String option) { + this.value = value; + this.option = option; + } + + @Override + public int getValue() { + return value; + } + + @Override + public String getOption() { + return option; + } + } + + public enum ClusterRunState implements OptionsEnum { + + NORMAL(0, "Normal"), STOP_CHARGING(1, "Stop charging"), STOP_DISCHARGE(2, "Stop discharging"), + STANDBY(3, "Standby"); + + private int value; + private String option; + + private ClusterRunState(int value, String option) { + this.value = value; + this.option = option; + } + + @Override + public int getValue() { + return value; + } + + @Override + public String getOption() { + return option; + } + } + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + BMS_CONTACTOR_CONTROL(new Doc().options(ContactorControl.values())), // + SYSTEM_OVER_VOLTAGE_PROTECTION(new Doc().unit(Unit.MILLIVOLT)), // + SYSTEM_UNDER_VOLTAGE_PROTECTION(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_CURRENT(new Doc().unit(Unit.MILLIAMPERE)), // + CLUSTER_1_CHARGE_INDICATION(new Doc().options(ChargeIndication.values())), // + CLUSTER_1_SOH(new Doc().unit(Unit.PERCENT)), // + CLUSTER_1_MAX_CELL_VOLTAGE_ID(new Doc().unit(Unit.NONE)), // + CLUSTER_1_MAX_CELL_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_MIN_CELL_VOLTAGE_ID(new Doc().unit(Unit.NONE)), // + CLUSTER_1_MIN_CELL_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_MAX_CELL_TEMPERATURE_ID(new Doc().unit(Unit.NONE)), // + CLUSTER_1_MAX_CELL_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_MIN_CELL_TEMPERATURE_ID(new Doc().unit(Unit.NONE)), // + CLUSTER_1_MIN_CELL_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + SYSTEM_INSULATION(new Doc().unit(Unit.KILOOHM)), // + SYSTEM_ACCEPT_MAX_CHARGE_CURRENT(new Doc().unit(Unit.MILLIAMPERE)), // + SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT(new Doc().unit(Unit.MILLIAMPERE)), // + ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Discharge Temperature Low Alarm Level 2")), // + ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Discharge Temperature High Alarm Level 2")), // + ALARM_LEVEL_2_INSULATION_LOW(new Doc().level(Level.WARNING).text("Cluster1Insulation Low Alarm Level 2")), // + ALARM_LEVEL_2_CELL_CHA_TEMP_LOW( + new Doc().level(Level.WARNING).text("Cluster1 Cell Charge Temperature Low Alarm Level 2")), // + ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH( + new Doc().level(Level.WARNING).text("Cluster1 Cell Charge Temperature High Alarm Level 2")), // + ALARM_LEVEL_2_DISCHA_CURRENT_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Discharge Current High Alarm Level 2")), // + ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW( + new Doc().level(Level.WARNING).text("Cluster 1 Total Voltage Low Alarm Level 2")), // + ALARM_LEVEL_2_CELL_VOLTAGE_LOW(new Doc().level(Level.WARNING).text("Cluster 1 Cell Voltage Low Alarm Level 2")), // + ALARM_LEVEL_2_CHA_CURRENT_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Charge Current High Alarm Level 2")), // + ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Total Voltage High Alarm Level 2")), // + ALARM_LEVEL_2_CELL_VOLTAGE_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Voltage High Alarm Level 2")), // + ALARM_LEVEL_1_CELL_DISCHA_TEMP_LOW( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Discharge Temperature Low Alarm Level 1")), // + ALARM_LEVEL_1_CELL_DISCHA_TEMP_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Discharge Temperature High Alarm Level 1")), // + ALARM_LEVEL_1_TOTAL_VOLTAGE_DIFF_HIGH( + new Doc().level(Level.WARNING).text("Cluster1 Total Voltage Diff High Alarm Level 1")), // + ALARM_LEVEL_1_INSULATION_LOW(new Doc().level(Level.WARNING).text("Cluster1 Insulation Low Alarm Level1")), // + ALARM_LEVEL_1_CELL_VOLTAGE_DIFF_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Voltage Diff High Alarm Level 1")), // + ALARM_LEVEL_1_CELL_TEMP_DIFF_HIGH( + new Doc().level(Level.WARNING).text("Cluster X Cell temperature Diff High Alarm Level 1")), // + ALARM_LEVEL_1_SOC_LOW(new Doc().level(Level.WARNING).text("Cluster 1 SOC Low Alarm Level 1")), // + ALARM_LEVEL_1_CELL_CHA_TEMP_LOW( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Charge Temperature Low Alarm Level 1")), // + ALARM_LEVEL_1_CELL_CHA_TEMP_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Charge Temperature High Alarm Level 1")), // + ALARM_LEVEL_1_DISCHA_CURRENT_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Discharge Current High Alarm Level 1")), // + ALARM_LEVEL_1_TOTAL_VOLTAGE_LOW( + new Doc().level(Level.WARNING).text("Cluster 1 Total Voltage Low Alarm Level 1")), // + ALARM_LEVEL_1_CELL_VOLTAGE_LOW(new Doc().level(Level.WARNING).text("Cluster 1 Cell Voltage Low Alarm Level 1")), // + ALARM_LEVEL_1_CHA_CURRENT_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Charge Current High Alarm Level 1")), // + ALARM_LEVEL_1_TOTAL_VOLTAGE_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Total Voltage High Alarm Level 1")), // + ALARM_LEVEL_1_CELL_VOLTAGE_HIGH( + new Doc().level(Level.WARNING).text("Cluster 1 Cell Voltage High Alarm Level 1")), // + CLUSTER_RUN_STATE(new Doc().options(ClusterRunState.values())), // + FAILURE_INITIALIZATION(new Doc().level(Level.FAULT).text("Initialization failure")), // + FAILURE_EEPROM(new Doc().level(Level.FAULT).text("EEPROM fault")), // + FAILURE_INTRANET_COMMUNICATION(new Doc().level(Level.FAULT).text("Intranet communication fault")), // + FAILURE_TEMP_SAMPLING_LINE(new Doc().level(Level.FAULT).text("Temperature sampling line fault")), // + FAILURE_BALANCING_MODULE(new Doc().level(Level.FAULT).text("Balancing module fault")), // + FAILURE_TEMP_SENSOR(new Doc().level(Level.FAULT).text("Temperature sensor fault")), // + FAILURE_TEMP_SAMPLING(new Doc().level(Level.FAULT).text("Temperature sampling fault")), // + FAILURE_VOLTAGE_SAMPLING(new Doc().level(Level.FAULT).text("Voltage sampling fault")), // + FAILURE_LTC6803(new Doc().level(Level.FAULT).text("LTC6803 fault")), // + FAILURE_CONNECTOR_WIRE(new Doc().level(Level.FAULT).text("connector wire fault")), // + FAILURE_SAMPLING_WIRE(new Doc().level(Level.FAULT).text("sampling wire fault")), // + + CLUSTER_1_BATTERY_000_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_001_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_002_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_003_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_004_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_005_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_006_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_007_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_008_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_009_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_010_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_011_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_012_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_013_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_014_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_015_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_016_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_017_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_018_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_019_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_020_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_021_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_022_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_023_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_024_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_025_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_026_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_027_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_028_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_029_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_030_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_031_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_032_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_033_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_034_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_035_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_036_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_037_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_038_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_039_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_040_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_041_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_042_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_043_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_044_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_045_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_046_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_047_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_048_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_049_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_050_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_051_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_052_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_053_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_054_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_055_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_056_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_057_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_058_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_059_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_060_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_061_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_062_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_063_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_064_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_065_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_066_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_067_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_068_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_069_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_070_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_071_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_072_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_073_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_074_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_075_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_076_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_077_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_078_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_079_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_080_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_081_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_082_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_083_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_084_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_085_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_086_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_087_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_088_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_089_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_090_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_091_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_092_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_093_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_094_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_095_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_096_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_097_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_098_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_099_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_100_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_101_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_102_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_103_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_104_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_105_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_106_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_107_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_108_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_109_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_110_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_111_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_112_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_113_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_114_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_115_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_116_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_117_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_118_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_119_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_120_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_121_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_122_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_123_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_124_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_125_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_126_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_127_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_128_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_129_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_130_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_131_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_132_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_133_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_134_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_135_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_136_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_137_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_138_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_139_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_140_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_141_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_142_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_143_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_144_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_145_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_146_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_147_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_148_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_149_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_150_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_151_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_152_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_153_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_154_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_155_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_156_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_157_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_158_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_159_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_160_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_161_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_162_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_163_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_164_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_165_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_166_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_167_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_168_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_169_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_170_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_171_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_172_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_173_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_174_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_175_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_176_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_177_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_178_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_179_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_180_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_181_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_182_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_183_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_184_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_185_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_186_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_187_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_188_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_189_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_190_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_191_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_192_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_193_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_194_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_195_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_196_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_197_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_198_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_199_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_200_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_201_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_202_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_203_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_204_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_205_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_206_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_207_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_208_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_209_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_210_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_211_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_212_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_213_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_214_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_215_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_216_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_217_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_218_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_219_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_220_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_221_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_222_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_223_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_224_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_225_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_226_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_227_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_228_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_229_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_230_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_231_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_232_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_233_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_234_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_235_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_236_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_237_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_238_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + CLUSTER_1_BATTERY_239_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + + CLUSTER_1_BATTERY_00_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_01_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_02_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_03_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_04_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_05_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_06_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_07_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_08_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_09_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_10_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_11_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_12_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_13_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_14_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_15_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_16_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_17_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_18_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_19_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_20_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_21_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_22_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_23_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_24_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_25_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_26_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_27_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_28_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_29_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_30_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_31_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_32_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_33_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_34_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_35_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_36_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_37_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_38_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_39_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_40_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_41_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_42_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_43_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_44_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_45_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_46_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + CLUSTER_1_BATTERY_47_TEMPERATURE(new Doc().unit(Unit.DEZIDEGREE_CELSIUS)), // + ; + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + @Override + protected ModbusProtocol defineModbusProtocol(int unitId) { + return new ModbusProtocol(unitId, // + new FC6WriteRegisterTask(0x2010, // + m(SoltaroRack.ChannelId.BMS_CONTACTOR_CONTROL, new UnsignedWordElement(0x2010)) // + ) , // + new FC3ReadRegistersTask(0x2042, Priority.HIGH, // + m(SoltaroRack.ChannelId.SYSTEM_OVER_VOLTAGE_PROTECTION, new UnsignedWordElement(0x2042), // + ElementToChannelConverter.SCALE_FACTOR_2) // + ), // + new FC3ReadRegistersTask(0x2048, Priority.HIGH, // + m(SoltaroRack.ChannelId.SYSTEM_UNDER_VOLTAGE_PROTECTION, new UnsignedWordElement(0x2048), // + ElementToChannelConverter.SCALE_FACTOR_2) // + ), // + new FC3ReadRegistersTask(0x2100, Priority.HIGH, // + m(SoltaroRack.ChannelId.CLUSTER_1_VOLTAGE, new UnsignedWordElement(0x2100), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(SoltaroRack.ChannelId.CLUSTER_1_CURRENT, new UnsignedWordElement(0x2101), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(SoltaroRack.ChannelId.CLUSTER_1_CHARGE_INDICATION, new UnsignedWordElement(0x2102)), // + m(Battery.ChannelId.SOC, new UnsignedWordElement(0x2103)), // + m(SoltaroRack.ChannelId.CLUSTER_1_SOH, new UnsignedWordElement(0x2104)), // + m(SoltaroRack.ChannelId.CLUSTER_1_MAX_CELL_VOLTAGE_ID, new UnsignedWordElement(0x2105)), // + m(SoltaroRack.ChannelId.CLUSTER_1_MAX_CELL_VOLTAGE, new UnsignedWordElement(0x2106)), // + m(SoltaroRack.ChannelId.CLUSTER_1_MIN_CELL_VOLTAGE_ID, new UnsignedWordElement(0x2107)), // + m(SoltaroRack.ChannelId.CLUSTER_1_MIN_CELL_VOLTAGE, new UnsignedWordElement(0x2108)), // + m(SoltaroRack.ChannelId.CLUSTER_1_MAX_CELL_TEMPERATURE_ID, new UnsignedWordElement(0x2109)), // + m(SoltaroRack.ChannelId.CLUSTER_1_MAX_CELL_TEMPERATURE, new UnsignedWordElement(0x210A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_MIN_CELL_TEMPERATURE_ID, new UnsignedWordElement(0x210B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_MIN_CELL_TEMPERATURE, new UnsignedWordElement(0x210C)), // + new DummyRegisterElement(0x210D, 0x2115), // + m(SoltaroRack.ChannelId.SYSTEM_INSULATION, new UnsignedWordElement(0x2116)) // + ), // + new FC3ReadRegistersTask(0x2160, Priority.HIGH, // + m(SoltaroRack.ChannelId.SYSTEM_ACCEPT_MAX_CHARGE_CURRENT, new UnsignedWordElement(0x2160), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(SoltaroRack.ChannelId.SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT, new UnsignedWordElement(0x2161), // + ElementToChannelConverter.SCALE_FACTOR_2) // + ), // + new FC3ReadRegistersTask(0x2140, Priority.LOW, // + bm(new UnsignedWordElement(0x2140)) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_HIGH, 0) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH, 1) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_CHA_CURRENT_HIGH, 2) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_LOW, 3) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW, 4) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_DISCHA_CURRENT_HIGH, 5) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH, 6) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_CELL_CHA_TEMP_LOW, 7) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_INSULATION_LOW, 12) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH, 14) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW, 15) // + .build(), // + bm(new UnsignedWordElement(0x2141)) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CELL_VOLTAGE_HIGH, 0) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_TOTAL_VOLTAGE_HIGH, 1) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CHA_CURRENT_HIGH, 2) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CELL_VOLTAGE_LOW, 3) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_TOTAL_VOLTAGE_LOW, 4) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_DISCHA_CURRENT_HIGH, 5) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CELL_CHA_TEMP_HIGH, 6) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CELL_CHA_TEMP_LOW, 7) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_SOC_LOW, 8) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CELL_TEMP_DIFF_HIGH, 9) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CELL_VOLTAGE_DIFF_HIGH, 11) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_INSULATION_LOW, 12) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_TOTAL_VOLTAGE_DIFF_HIGH, 13) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CELL_DISCHA_TEMP_HIGH, 14) // + .m(SoltaroRack.ChannelId.ALARM_LEVEL_1_CELL_DISCHA_TEMP_LOW, 15) // + .build(), // + m(SoltaroRack.ChannelId.CLUSTER_RUN_STATE, new UnsignedWordElement(0x2142)) // + ), // + new FC3ReadRegistersTask(0x2185, Priority.LOW, // + bm(new UnsignedWordElement(0x2185)) // + .m(SoltaroRack.ChannelId.FAILURE_SAMPLING_WIRE, 0)// + .m(SoltaroRack.ChannelId.FAILURE_CONNECTOR_WIRE, 1)// + .m(SoltaroRack.ChannelId.FAILURE_LTC6803, 2)// + .m(SoltaroRack.ChannelId.FAILURE_VOLTAGE_SAMPLING, 3)// + .m(SoltaroRack.ChannelId.FAILURE_TEMP_SAMPLING, 4)// + .m(SoltaroRack.ChannelId.FAILURE_TEMP_SENSOR, 5)// + .m(SoltaroRack.ChannelId.FAILURE_BALANCING_MODULE, 8)// + .m(SoltaroRack.ChannelId.FAILURE_TEMP_SAMPLING_LINE, 9)// + .m(SoltaroRack.ChannelId.FAILURE_INTRANET_COMMUNICATION, 10)// + .m(SoltaroRack.ChannelId.FAILURE_EEPROM, 11)// + .m(SoltaroRack.ChannelId.FAILURE_INITIALIZATION, 12)// + .build() // + ), // + new FC3ReadRegistersTask(0x2800, Priority.LOW, // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_000_VOLTAGE, new UnsignedWordElement(0x2800)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_001_VOLTAGE, new UnsignedWordElement(0x2801)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_002_VOLTAGE, new UnsignedWordElement(0x2802)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_003_VOLTAGE, new UnsignedWordElement(0x2803)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_004_VOLTAGE, new UnsignedWordElement(0x2804)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_005_VOLTAGE, new UnsignedWordElement(0x2805)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_006_VOLTAGE, new UnsignedWordElement(0x2806)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_007_VOLTAGE, new UnsignedWordElement(0x2807)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_008_VOLTAGE, new UnsignedWordElement(0x2808)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_009_VOLTAGE, new UnsignedWordElement(0x2809)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_010_VOLTAGE, new UnsignedWordElement(0x280A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_011_VOLTAGE, new UnsignedWordElement(0x280B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_012_VOLTAGE, new UnsignedWordElement(0x280C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_013_VOLTAGE, new UnsignedWordElement(0x280D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_014_VOLTAGE, new UnsignedWordElement(0x280E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_015_VOLTAGE, new UnsignedWordElement(0x280F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_016_VOLTAGE, new UnsignedWordElement(0x2810)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_017_VOLTAGE, new UnsignedWordElement(0x2811)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_018_VOLTAGE, new UnsignedWordElement(0x2812)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_019_VOLTAGE, new UnsignedWordElement(0x2813)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_020_VOLTAGE, new UnsignedWordElement(0x2814)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_021_VOLTAGE, new UnsignedWordElement(0x2815)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_022_VOLTAGE, new UnsignedWordElement(0x2816)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_023_VOLTAGE, new UnsignedWordElement(0x2817)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_024_VOLTAGE, new UnsignedWordElement(0x2818)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_025_VOLTAGE, new UnsignedWordElement(0x2819)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_026_VOLTAGE, new UnsignedWordElement(0x281A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_027_VOLTAGE, new UnsignedWordElement(0x281B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_028_VOLTAGE, new UnsignedWordElement(0x281C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_029_VOLTAGE, new UnsignedWordElement(0x281D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_030_VOLTAGE, new UnsignedWordElement(0x281E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_031_VOLTAGE, new UnsignedWordElement(0x281F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_032_VOLTAGE, new UnsignedWordElement(0x2820)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_033_VOLTAGE, new UnsignedWordElement(0x2821)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_034_VOLTAGE, new UnsignedWordElement(0x2822)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_035_VOLTAGE, new UnsignedWordElement(0x2823)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_036_VOLTAGE, new UnsignedWordElement(0x2824)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_037_VOLTAGE, new UnsignedWordElement(0x2825)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_038_VOLTAGE, new UnsignedWordElement(0x2826)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_039_VOLTAGE, new UnsignedWordElement(0x2827)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_040_VOLTAGE, new UnsignedWordElement(0x2828)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_041_VOLTAGE, new UnsignedWordElement(0x2829)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_042_VOLTAGE, new UnsignedWordElement(0x282A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_043_VOLTAGE, new UnsignedWordElement(0x282B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_044_VOLTAGE, new UnsignedWordElement(0x282C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_045_VOLTAGE, new UnsignedWordElement(0x282D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_046_VOLTAGE, new UnsignedWordElement(0x282E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_047_VOLTAGE, new UnsignedWordElement(0x282F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_048_VOLTAGE, new UnsignedWordElement(0x2830)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_049_VOLTAGE, new UnsignedWordElement(0x2831)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_050_VOLTAGE, new UnsignedWordElement(0x2832)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_051_VOLTAGE, new UnsignedWordElement(0x2833)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_052_VOLTAGE, new UnsignedWordElement(0x2834)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_053_VOLTAGE, new UnsignedWordElement(0x2835)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_054_VOLTAGE, new UnsignedWordElement(0x2836)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_055_VOLTAGE, new UnsignedWordElement(0x2837)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_056_VOLTAGE, new UnsignedWordElement(0x2838)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_057_VOLTAGE, new UnsignedWordElement(0x2839)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_058_VOLTAGE, new UnsignedWordElement(0x283A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_059_VOLTAGE, new UnsignedWordElement(0x283B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_060_VOLTAGE, new UnsignedWordElement(0x283C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_061_VOLTAGE, new UnsignedWordElement(0x283D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_062_VOLTAGE, new UnsignedWordElement(0x283E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_063_VOLTAGE, new UnsignedWordElement(0x283F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_064_VOLTAGE, new UnsignedWordElement(0x2840)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_065_VOLTAGE, new UnsignedWordElement(0x2841)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_066_VOLTAGE, new UnsignedWordElement(0x2842)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_067_VOLTAGE, new UnsignedWordElement(0x2843)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_068_VOLTAGE, new UnsignedWordElement(0x2844)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_069_VOLTAGE, new UnsignedWordElement(0x2845)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_070_VOLTAGE, new UnsignedWordElement(0x2846)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_071_VOLTAGE, new UnsignedWordElement(0x2847)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_072_VOLTAGE, new UnsignedWordElement(0x2848)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_073_VOLTAGE, new UnsignedWordElement(0x2849)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_074_VOLTAGE, new UnsignedWordElement(0x284A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_075_VOLTAGE, new UnsignedWordElement(0x284B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_076_VOLTAGE, new UnsignedWordElement(0x284C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_077_VOLTAGE, new UnsignedWordElement(0x284D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_078_VOLTAGE, new UnsignedWordElement(0x284E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_079_VOLTAGE, new UnsignedWordElement(0x284F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_080_VOLTAGE, new UnsignedWordElement(0x2850)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_081_VOLTAGE, new UnsignedWordElement(0x2851)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_082_VOLTAGE, new UnsignedWordElement(0x2852)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_083_VOLTAGE, new UnsignedWordElement(0x2853)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_084_VOLTAGE, new UnsignedWordElement(0x2854)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_085_VOLTAGE, new UnsignedWordElement(0x2855)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_086_VOLTAGE, new UnsignedWordElement(0x2856)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_087_VOLTAGE, new UnsignedWordElement(0x2857)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_088_VOLTAGE, new UnsignedWordElement(0x2858)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_089_VOLTAGE, new UnsignedWordElement(0x2859)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_090_VOLTAGE, new UnsignedWordElement(0x285A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_091_VOLTAGE, new UnsignedWordElement(0x285B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_092_VOLTAGE, new UnsignedWordElement(0x285C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_093_VOLTAGE, new UnsignedWordElement(0x285D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_094_VOLTAGE, new UnsignedWordElement(0x285E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_095_VOLTAGE, new UnsignedWordElement(0x285F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_096_VOLTAGE, new UnsignedWordElement(0x2860)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_097_VOLTAGE, new UnsignedWordElement(0x2861)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_098_VOLTAGE, new UnsignedWordElement(0x2862)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_099_VOLTAGE, new UnsignedWordElement(0x2863)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_100_VOLTAGE, new UnsignedWordElement(0x2864)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_101_VOLTAGE, new UnsignedWordElement(0x2865)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_102_VOLTAGE, new UnsignedWordElement(0x2866)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_103_VOLTAGE, new UnsignedWordElement(0x2867)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_104_VOLTAGE, new UnsignedWordElement(0x2868)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_105_VOLTAGE, new UnsignedWordElement(0x2869)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_106_VOLTAGE, new UnsignedWordElement(0x286A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_107_VOLTAGE, new UnsignedWordElement(0x286B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_108_VOLTAGE, new UnsignedWordElement(0x286C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_109_VOLTAGE, new UnsignedWordElement(0x286D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_110_VOLTAGE, new UnsignedWordElement(0x286E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_111_VOLTAGE, new UnsignedWordElement(0x286F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_112_VOLTAGE, new UnsignedWordElement(0x2870)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_113_VOLTAGE, new UnsignedWordElement(0x2871)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_114_VOLTAGE, new UnsignedWordElement(0x2872)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_115_VOLTAGE, new UnsignedWordElement(0x2873)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_116_VOLTAGE, new UnsignedWordElement(0x2874)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_117_VOLTAGE, new UnsignedWordElement(0x2875)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_118_VOLTAGE, new UnsignedWordElement(0x2876)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_119_VOLTAGE, new UnsignedWordElement(0x2877)) // + + ), // + new FC3ReadRegistersTask(0x2878, Priority.LOW, // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_120_VOLTAGE, new UnsignedWordElement(0x2878)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_121_VOLTAGE, new UnsignedWordElement(0x2879)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_122_VOLTAGE, new UnsignedWordElement(0x287A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_123_VOLTAGE, new UnsignedWordElement(0x287B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_124_VOLTAGE, new UnsignedWordElement(0x287C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_125_VOLTAGE, new UnsignedWordElement(0x287D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_126_VOLTAGE, new UnsignedWordElement(0x287E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_127_VOLTAGE, new UnsignedWordElement(0x287F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_128_VOLTAGE, new UnsignedWordElement(0x2880)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_129_VOLTAGE, new UnsignedWordElement(0x2881)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_130_VOLTAGE, new UnsignedWordElement(0x2882)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_131_VOLTAGE, new UnsignedWordElement(0x2883)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_132_VOLTAGE, new UnsignedWordElement(0x2884)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_133_VOLTAGE, new UnsignedWordElement(0x2885)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_134_VOLTAGE, new UnsignedWordElement(0x2886)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_135_VOLTAGE, new UnsignedWordElement(0x2887)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_136_VOLTAGE, new UnsignedWordElement(0x2888)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_137_VOLTAGE, new UnsignedWordElement(0x2889)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_138_VOLTAGE, new UnsignedWordElement(0x288A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_139_VOLTAGE, new UnsignedWordElement(0x288B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_140_VOLTAGE, new UnsignedWordElement(0x288C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_141_VOLTAGE, new UnsignedWordElement(0x288D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_142_VOLTAGE, new UnsignedWordElement(0x288E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_143_VOLTAGE, new UnsignedWordElement(0x288F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_144_VOLTAGE, new UnsignedWordElement(0x2890)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_145_VOLTAGE, new UnsignedWordElement(0x2891)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_146_VOLTAGE, new UnsignedWordElement(0x2892)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_147_VOLTAGE, new UnsignedWordElement(0x2893)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_148_VOLTAGE, new UnsignedWordElement(0x2894)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_149_VOLTAGE, new UnsignedWordElement(0x2895)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_150_VOLTAGE, new UnsignedWordElement(0x2896)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_151_VOLTAGE, new UnsignedWordElement(0x2897)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_152_VOLTAGE, new UnsignedWordElement(0x2898)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_153_VOLTAGE, new UnsignedWordElement(0x2899)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_154_VOLTAGE, new UnsignedWordElement(0x289A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_155_VOLTAGE, new UnsignedWordElement(0x289B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_156_VOLTAGE, new UnsignedWordElement(0x289C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_157_VOLTAGE, new UnsignedWordElement(0x289D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_158_VOLTAGE, new UnsignedWordElement(0x289E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_159_VOLTAGE, new UnsignedWordElement(0x289F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_160_VOLTAGE, new UnsignedWordElement(0x28A0)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_161_VOLTAGE, new UnsignedWordElement(0x28A1)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_162_VOLTAGE, new UnsignedWordElement(0x28A2)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_163_VOLTAGE, new UnsignedWordElement(0x28A3)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_164_VOLTAGE, new UnsignedWordElement(0x28A4)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_165_VOLTAGE, new UnsignedWordElement(0x28A5)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_166_VOLTAGE, new UnsignedWordElement(0x28A6)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_167_VOLTAGE, new UnsignedWordElement(0x28A7)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_168_VOLTAGE, new UnsignedWordElement(0x28A8)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_169_VOLTAGE, new UnsignedWordElement(0x28A9)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_170_VOLTAGE, new UnsignedWordElement(0x28AA)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_171_VOLTAGE, new UnsignedWordElement(0x28AB)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_172_VOLTAGE, new UnsignedWordElement(0x28AC)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_173_VOLTAGE, new UnsignedWordElement(0x28AD)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_174_VOLTAGE, new UnsignedWordElement(0x28AE)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_175_VOLTAGE, new UnsignedWordElement(0x28AF)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_176_VOLTAGE, new UnsignedWordElement(0x28B0)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_177_VOLTAGE, new UnsignedWordElement(0x28B1)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_178_VOLTAGE, new UnsignedWordElement(0x28B2)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_179_VOLTAGE, new UnsignedWordElement(0x28B3)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_180_VOLTAGE, new UnsignedWordElement(0x28B4)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_181_VOLTAGE, new UnsignedWordElement(0x28B5)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_182_VOLTAGE, new UnsignedWordElement(0x28B6)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_183_VOLTAGE, new UnsignedWordElement(0x28B7)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_184_VOLTAGE, new UnsignedWordElement(0x28B8)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_185_VOLTAGE, new UnsignedWordElement(0x28B9)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_186_VOLTAGE, new UnsignedWordElement(0x28BA)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_187_VOLTAGE, new UnsignedWordElement(0x28BB)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_188_VOLTAGE, new UnsignedWordElement(0x28BC)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_189_VOLTAGE, new UnsignedWordElement(0x28BD)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_190_VOLTAGE, new UnsignedWordElement(0x28BE)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_191_VOLTAGE, new UnsignedWordElement(0x28BF)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_192_VOLTAGE, new UnsignedWordElement(0x28C0)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_193_VOLTAGE, new UnsignedWordElement(0x28C1)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_194_VOLTAGE, new UnsignedWordElement(0x28C2)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_195_VOLTAGE, new UnsignedWordElement(0x28C3)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_196_VOLTAGE, new UnsignedWordElement(0x28C4)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_197_VOLTAGE, new UnsignedWordElement(0x28C5)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_198_VOLTAGE, new UnsignedWordElement(0x28C6)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_199_VOLTAGE, new UnsignedWordElement(0x28C7)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_200_VOLTAGE, new UnsignedWordElement(0x28C8)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_201_VOLTAGE, new UnsignedWordElement(0x28C9)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_202_VOLTAGE, new UnsignedWordElement(0x28CA)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_203_VOLTAGE, new UnsignedWordElement(0x28CB)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_204_VOLTAGE, new UnsignedWordElement(0x28CC)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_205_VOLTAGE, new UnsignedWordElement(0x28CD)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_206_VOLTAGE, new UnsignedWordElement(0x28CE)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_207_VOLTAGE, new UnsignedWordElement(0x28CF)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_208_VOLTAGE, new UnsignedWordElement(0x28D0)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_209_VOLTAGE, new UnsignedWordElement(0x28D1)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_210_VOLTAGE, new UnsignedWordElement(0x28D2)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_211_VOLTAGE, new UnsignedWordElement(0x28D3)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_212_VOLTAGE, new UnsignedWordElement(0x28D4)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_213_VOLTAGE, new UnsignedWordElement(0x28D5)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_214_VOLTAGE, new UnsignedWordElement(0x28D6)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_215_VOLTAGE, new UnsignedWordElement(0x28D7)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_216_VOLTAGE, new UnsignedWordElement(0x28D8)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_217_VOLTAGE, new UnsignedWordElement(0x28D9)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_218_VOLTAGE, new UnsignedWordElement(0x28DA)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_219_VOLTAGE, new UnsignedWordElement(0x28DB)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_220_VOLTAGE, new UnsignedWordElement(0x28DC)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_221_VOLTAGE, new UnsignedWordElement(0x28DD)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_222_VOLTAGE, new UnsignedWordElement(0x28DE)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_223_VOLTAGE, new UnsignedWordElement(0x28DF)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_224_VOLTAGE, new UnsignedWordElement(0x28E0)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_225_VOLTAGE, new UnsignedWordElement(0x28E1)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_226_VOLTAGE, new UnsignedWordElement(0x28E2)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_227_VOLTAGE, new UnsignedWordElement(0x28E3)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_228_VOLTAGE, new UnsignedWordElement(0x28E4)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_229_VOLTAGE, new UnsignedWordElement(0x28E5)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_230_VOLTAGE, new UnsignedWordElement(0x28E6)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_231_VOLTAGE, new UnsignedWordElement(0x28E7)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_232_VOLTAGE, new UnsignedWordElement(0x28E8)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_233_VOLTAGE, new UnsignedWordElement(0x28E9)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_234_VOLTAGE, new UnsignedWordElement(0x28EA)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_235_VOLTAGE, new UnsignedWordElement(0x28EB)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_236_VOLTAGE, new UnsignedWordElement(0x28EC)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_237_VOLTAGE, new UnsignedWordElement(0x28ED)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_238_VOLTAGE, new UnsignedWordElement(0x28EE)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_239_VOLTAGE, new UnsignedWordElement(0x28EF)) // + + ), // + new FC3ReadRegistersTask(0x2C00, Priority.LOW, // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_00_TEMPERATURE, new UnsignedWordElement(0x2C00)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_01_TEMPERATURE, new UnsignedWordElement(0x2C01)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_02_TEMPERATURE, new UnsignedWordElement(0x2C02)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_03_TEMPERATURE, new UnsignedWordElement(0x2C03)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_04_TEMPERATURE, new UnsignedWordElement(0x2C04)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_05_TEMPERATURE, new UnsignedWordElement(0x2C05)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_06_TEMPERATURE, new UnsignedWordElement(0x2C06)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_07_TEMPERATURE, new UnsignedWordElement(0x2C07)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_08_TEMPERATURE, new UnsignedWordElement(0x2C08)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_09_TEMPERATURE, new UnsignedWordElement(0x2C09)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_10_TEMPERATURE, new UnsignedWordElement(0x2C0A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_11_TEMPERATURE, new UnsignedWordElement(0x2C0B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_12_TEMPERATURE, new UnsignedWordElement(0x2C0C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_13_TEMPERATURE, new UnsignedWordElement(0x2C0D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_14_TEMPERATURE, new UnsignedWordElement(0x2C0E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_15_TEMPERATURE, new UnsignedWordElement(0x2C0F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_16_TEMPERATURE, new UnsignedWordElement(0x2C10)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_17_TEMPERATURE, new UnsignedWordElement(0x2C11)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_18_TEMPERATURE, new UnsignedWordElement(0x2C12)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_19_TEMPERATURE, new UnsignedWordElement(0x2C13)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_20_TEMPERATURE, new UnsignedWordElement(0x2C14)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_21_TEMPERATURE, new UnsignedWordElement(0x2C15)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_22_TEMPERATURE, new UnsignedWordElement(0x2C16)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_23_TEMPERATURE, new UnsignedWordElement(0x2C17)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_24_TEMPERATURE, new UnsignedWordElement(0x2C18)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_25_TEMPERATURE, new UnsignedWordElement(0x2C19)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_26_TEMPERATURE, new UnsignedWordElement(0x2C1A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_27_TEMPERATURE, new UnsignedWordElement(0x2C1B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_28_TEMPERATURE, new UnsignedWordElement(0x2C1C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_29_TEMPERATURE, new UnsignedWordElement(0x2C1D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_30_TEMPERATURE, new UnsignedWordElement(0x2C1E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_31_TEMPERATURE, new UnsignedWordElement(0x2C1F)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_32_TEMPERATURE, new UnsignedWordElement(0x2C20)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_33_TEMPERATURE, new UnsignedWordElement(0x2C21)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_34_TEMPERATURE, new UnsignedWordElement(0x2C22)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_35_TEMPERATURE, new UnsignedWordElement(0x2C23)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_36_TEMPERATURE, new UnsignedWordElement(0x2C24)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_37_TEMPERATURE, new UnsignedWordElement(0x2C25)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_38_TEMPERATURE, new UnsignedWordElement(0x2C26)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_39_TEMPERATURE, new UnsignedWordElement(0x2C27)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_40_TEMPERATURE, new UnsignedWordElement(0x2C28)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_41_TEMPERATURE, new UnsignedWordElement(0x2C29)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_42_TEMPERATURE, new UnsignedWordElement(0x2C2A)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_43_TEMPERATURE, new UnsignedWordElement(0x2C2B)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_44_TEMPERATURE, new UnsignedWordElement(0x2C2C)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_45_TEMPERATURE, new UnsignedWordElement(0x2C2D)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_46_TEMPERATURE, new UnsignedWordElement(0x2C2E)), // + m(SoltaroRack.ChannelId.CLUSTER_1_BATTERY_47_TEMPERATURE, new UnsignedWordElement(0x2C2F)) // + )// + ); // + } + + @Override + public String debugLog() { + return "SoC:" + this.getSoc().value().asString(); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + switch (event.getTopic()) { + + case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE: + checkSystemState(); + break; + } + } + + private void checkSystemState() { + IntegerReadChannel contactorControlChannel = this.channel(ChannelId.BMS_CONTACTOR_CONTROL); + + Optional> ccOpt = contactorControlChannel.value().asEnumOptional(); + if (!ccOpt.isPresent()) { + return; + } + ContactorControl cc = (ContactorControl) ccOpt.get(); + + if (cc == ContactorControl.CONNECTION_INITIATING) { + // do nothing and wait until system is in normal operating mode + return; + } + if (cc == ContactorControl.CUT_OFF) { + switchSystemOn(); + return; + } + + if (cc == ContactorControl.ON_GRID) { + if (checkForFault()) { + handleFaults(); + } else { + doNormalProcessing(); + } + } + } + + private void switchSystemOn() { + IntegerWriteChannel contactorControlChannel = this.channel(ChannelId.BMS_CONTACTOR_CONTROL); + try { + contactorControlChannel.setNextWriteValue(SYSTEM_ON); + } catch (OpenemsException e) { + log.error(e.getMessage()); + } + } + + private void doNormalProcessing() { + // Try to react on possible errors + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_HIGH)) { + handleCellVoltageHigh(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH)) { + handleTotalVoltageHigh(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_CHA_CURRENT_HIGH)) { + handleChargeCurrentHigh(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_CELL_VOLTAGE_LOW)) { + handleCellVoltageLow(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW)) { + handleTotalVoltageLow(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_DISCHA_CURRENT_HIGH)) { + handleDischargeCurrentHigh(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH)) { + handleCellChargeTemperatureHigh(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_CELL_CHA_TEMP_LOW)) { + handleCellChargeTemperatureLow(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_INSULATION_LOW)) { + handleInsulationLow(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH)) { + handleCellDischargeTemperatureHigh(); + } + if (isStateValueInChannelSet(ChannelId.ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW)) { + handleCellDischargeTemperatureLow(); + } + } + + private void handleFaults() { + Optional state = getState().getNextValue().asOptional(); + if (!state.isPresent()) { + return; + } + switch (state.get()) { + case 0: // SAMPLING_WIRE + case 1:// CONNECTOR_WIRE + case 2:// LTC6803 + case 3:// VOLTAGE_SAMPLING + case 4:// TEMP_SAMPLING + case 5:// TEMP_SENSOR + case 8:// BALANCING_MODULE + case 9:// TEMP_SAMPLING_LINE + case 10:// INTRANET_COMMUNICATION + case 11:// EEPROM + case 12:// INITIALIZATION + // Turn off the system + IntegerReadChannel contactorControlChannel = this.channel(ChannelId.BMS_CONTACTOR_CONTROL); + contactorControlChannel.setNextValue(SYSTEM_OFF); + break; + } + } + + private boolean checkForFault() { + Optional state = getState().getNextValue().asOptional(); + return (state.isPresent() && state.get() != 0); + } + + private boolean isStateValueInChannelSet(ChannelId channelId) { + StateChannel channel = this.channel(channelId); + Optional valueOpt = channel.value().asOptional(); + return valueOpt.isPresent() && valueOpt.get(); + } + + private void handleCellDischargeTemperatureLow() { + } + + private void handleCellDischargeTemperatureHigh() { + } + + private void handleInsulationLow() { + } + + private void handleCellChargeTemperatureLow() { + } + + private void handleCellChargeTemperatureHigh() { + } + + private void handleDischargeCurrentHigh() { + } + + private void handleTotalVoltageLow() { + } + + private void handleCellVoltageLow() { + } + + private void handleChargeCurrentHigh() { + } + + private void handleTotalVoltageHigh() { + } + + private void handleCellVoltageHigh() { + } + + @Override + public Channel getDischargeMinVoltage() { + return this.channel(ChannelId.SYSTEM_UNDER_VOLTAGE_PROTECTION); + } + + @Override + public Channel getDischargeMaxCurrent() { + return this.channel(ChannelId.SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT); + } + + @Override + public Channel getChargeMaxVoltage() { + return this.channel(ChannelId.SYSTEM_OVER_VOLTAGE_PROTECTION); + } + + @Override + public Channel getChargeMaxCurrent() { + return this.channel(ChannelId.SYSTEM_ACCEPT_MAX_CHARGE_CURRENT); + } +} diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Utils.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Utils.java new file mode 100644 index 00000000000..e5dc36b5604 --- /dev/null +++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/Utils.java @@ -0,0 +1,397 @@ +package io.openems.edge.battery.soltaro; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.battery.api.Battery; +import io.openems.edge.common.channel.AbstractReadChannel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.IntegerWriteChannel; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.component.OpenemsComponent; + +public class Utils { + public static Stream> initializeChannels(SoltaroRack s) { + // Define the channels. Using streams + switch enables Eclipse IDE to tell us if + // we are missing an Enum value. + return Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(s, channelId); + } + return null; + }), Arrays.stream(Battery.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case MAX_CAPACITY: + case GRID_MODE: + case CHARGE_MAX_CURRENT: + case CHARGE_MAX_VOLTAGE: + case DISCHARGE_MAX_CURRENT: + case DISCHARGE_MIN_VOLTAGE: + return new IntegerReadChannel(s, channelId); + } + return null; + }), Arrays.stream(SoltaroRack.ChannelId.values()).map(channelId -> { + switch (channelId) { + case BMS_CONTACTOR_CONTROL: + return new IntegerWriteChannel(s, channelId); + + case ALARM_LEVEL_1_CELL_CHA_TEMP_HIGH: + case ALARM_LEVEL_1_CELL_CHA_TEMP_LOW: + case ALARM_LEVEL_1_CELL_DISCHA_TEMP_HIGH: + case ALARM_LEVEL_1_CELL_DISCHA_TEMP_LOW: + case ALARM_LEVEL_1_CELL_TEMP_DIFF_HIGH: + case ALARM_LEVEL_1_CELL_VOLTAGE_DIFF_HIGH: + case ALARM_LEVEL_1_CELL_VOLTAGE_HIGH: + case ALARM_LEVEL_1_CELL_VOLTAGE_LOW: + case ALARM_LEVEL_1_CHA_CURRENT_HIGH: + case ALARM_LEVEL_1_DISCHA_CURRENT_HIGH: + case ALARM_LEVEL_1_INSULATION_LOW: + case ALARM_LEVEL_1_SOC_LOW: + case ALARM_LEVEL_1_TOTAL_VOLTAGE_DIFF_HIGH: + case ALARM_LEVEL_1_TOTAL_VOLTAGE_HIGH: + case ALARM_LEVEL_1_TOTAL_VOLTAGE_LOW: + case ALARM_LEVEL_2_CELL_CHA_TEMP_HIGH: + case ALARM_LEVEL_2_CELL_CHA_TEMP_LOW: + case ALARM_LEVEL_2_CELL_DISCHA_TEMP_HIGH: + case ALARM_LEVEL_2_CELL_DISCHA_TEMP_LOW: + case ALARM_LEVEL_2_CELL_VOLTAGE_HIGH: + case ALARM_LEVEL_2_CELL_VOLTAGE_LOW: + case ALARM_LEVEL_2_CHA_CURRENT_HIGH: + case ALARM_LEVEL_2_DISCHA_CURRENT_HIGH: + case ALARM_LEVEL_2_INSULATION_LOW: + case ALARM_LEVEL_2_TOTAL_VOLTAGE_HIGH: + case ALARM_LEVEL_2_TOTAL_VOLTAGE_LOW: + + case FAILURE_BALANCING_MODULE: + case FAILURE_CONNECTOR_WIRE: + case FAILURE_EEPROM: + case FAILURE_INITIALIZATION: + case FAILURE_INTRANET_COMMUNICATION: + case FAILURE_LTC6803: + case FAILURE_SAMPLING_WIRE: + case FAILURE_TEMP_SAMPLING: + case FAILURE_TEMP_SAMPLING_LINE: + case FAILURE_TEMP_SENSOR: + case FAILURE_VOLTAGE_SAMPLING: + return new StateChannel(s, channelId); + case CLUSTER_1_BATTERY_000_VOLTAGE: + case CLUSTER_1_BATTERY_001_VOLTAGE: + case CLUSTER_1_BATTERY_002_VOLTAGE: + case CLUSTER_1_BATTERY_003_VOLTAGE: + case CLUSTER_1_BATTERY_004_VOLTAGE: + case CLUSTER_1_BATTERY_005_VOLTAGE: + case CLUSTER_1_BATTERY_006_VOLTAGE: + case CLUSTER_1_BATTERY_007_VOLTAGE: + case CLUSTER_1_BATTERY_008_VOLTAGE: + case CLUSTER_1_BATTERY_009_VOLTAGE: + case CLUSTER_1_BATTERY_010_VOLTAGE: + case CLUSTER_1_BATTERY_011_VOLTAGE: + case CLUSTER_1_BATTERY_012_VOLTAGE: + case CLUSTER_1_BATTERY_013_VOLTAGE: + case CLUSTER_1_BATTERY_014_VOLTAGE: + case CLUSTER_1_BATTERY_015_VOLTAGE: + case CLUSTER_1_BATTERY_016_VOLTAGE: + case CLUSTER_1_BATTERY_017_VOLTAGE: + case CLUSTER_1_BATTERY_018_VOLTAGE: + case CLUSTER_1_BATTERY_019_VOLTAGE: + case CLUSTER_1_BATTERY_020_VOLTAGE: + case CLUSTER_1_BATTERY_021_VOLTAGE: + case CLUSTER_1_BATTERY_022_VOLTAGE: + case CLUSTER_1_BATTERY_023_VOLTAGE: + case CLUSTER_1_BATTERY_024_VOLTAGE: + case CLUSTER_1_BATTERY_025_VOLTAGE: + case CLUSTER_1_BATTERY_026_VOLTAGE: + case CLUSTER_1_BATTERY_027_VOLTAGE: + case CLUSTER_1_BATTERY_028_VOLTAGE: + case CLUSTER_1_BATTERY_029_VOLTAGE: + case CLUSTER_1_BATTERY_030_VOLTAGE: + case CLUSTER_1_BATTERY_031_VOLTAGE: + case CLUSTER_1_BATTERY_032_VOLTAGE: + case CLUSTER_1_BATTERY_033_VOLTAGE: + case CLUSTER_1_BATTERY_034_VOLTAGE: + case CLUSTER_1_BATTERY_035_VOLTAGE: + case CLUSTER_1_BATTERY_036_VOLTAGE: + case CLUSTER_1_BATTERY_037_VOLTAGE: + case CLUSTER_1_BATTERY_038_VOLTAGE: + case CLUSTER_1_BATTERY_039_VOLTAGE: + case CLUSTER_1_BATTERY_040_VOLTAGE: + case CLUSTER_1_BATTERY_041_VOLTAGE: + case CLUSTER_1_BATTERY_042_VOLTAGE: + case CLUSTER_1_BATTERY_043_VOLTAGE: + case CLUSTER_1_BATTERY_044_VOLTAGE: + case CLUSTER_1_BATTERY_045_VOLTAGE: + case CLUSTER_1_BATTERY_046_VOLTAGE: + case CLUSTER_1_BATTERY_047_VOLTAGE: + case CLUSTER_1_BATTERY_048_VOLTAGE: + case CLUSTER_1_BATTERY_049_VOLTAGE: + case CLUSTER_1_BATTERY_050_VOLTAGE: + case CLUSTER_1_BATTERY_051_VOLTAGE: + case CLUSTER_1_BATTERY_052_VOLTAGE: + case CLUSTER_1_BATTERY_053_VOLTAGE: + case CLUSTER_1_BATTERY_054_VOLTAGE: + case CLUSTER_1_BATTERY_055_VOLTAGE: + case CLUSTER_1_BATTERY_056_VOLTAGE: + case CLUSTER_1_BATTERY_057_VOLTAGE: + case CLUSTER_1_BATTERY_058_VOLTAGE: + case CLUSTER_1_BATTERY_059_VOLTAGE: + case CLUSTER_1_BATTERY_060_VOLTAGE: + case CLUSTER_1_BATTERY_061_VOLTAGE: + case CLUSTER_1_BATTERY_062_VOLTAGE: + case CLUSTER_1_BATTERY_063_VOLTAGE: + case CLUSTER_1_BATTERY_064_VOLTAGE: + case CLUSTER_1_BATTERY_065_VOLTAGE: + case CLUSTER_1_BATTERY_066_VOLTAGE: + case CLUSTER_1_BATTERY_067_VOLTAGE: + case CLUSTER_1_BATTERY_068_VOLTAGE: + case CLUSTER_1_BATTERY_069_VOLTAGE: + case CLUSTER_1_BATTERY_070_VOLTAGE: + case CLUSTER_1_BATTERY_071_VOLTAGE: + case CLUSTER_1_BATTERY_072_VOLTAGE: + case CLUSTER_1_BATTERY_073_VOLTAGE: + case CLUSTER_1_BATTERY_074_VOLTAGE: + case CLUSTER_1_BATTERY_075_VOLTAGE: + case CLUSTER_1_BATTERY_076_VOLTAGE: + case CLUSTER_1_BATTERY_077_VOLTAGE: + case CLUSTER_1_BATTERY_078_VOLTAGE: + case CLUSTER_1_BATTERY_079_VOLTAGE: + case CLUSTER_1_BATTERY_080_VOLTAGE: + case CLUSTER_1_BATTERY_081_VOLTAGE: + case CLUSTER_1_BATTERY_082_VOLTAGE: + case CLUSTER_1_BATTERY_083_VOLTAGE: + case CLUSTER_1_BATTERY_084_VOLTAGE: + case CLUSTER_1_BATTERY_085_VOLTAGE: + case CLUSTER_1_BATTERY_086_VOLTAGE: + case CLUSTER_1_BATTERY_087_VOLTAGE: + case CLUSTER_1_BATTERY_088_VOLTAGE: + case CLUSTER_1_BATTERY_089_VOLTAGE: + case CLUSTER_1_BATTERY_090_VOLTAGE: + case CLUSTER_1_BATTERY_091_VOLTAGE: + case CLUSTER_1_BATTERY_092_VOLTAGE: + case CLUSTER_1_BATTERY_093_VOLTAGE: + case CLUSTER_1_BATTERY_094_VOLTAGE: + case CLUSTER_1_BATTERY_095_VOLTAGE: + case CLUSTER_1_BATTERY_096_VOLTAGE: + case CLUSTER_1_BATTERY_097_VOLTAGE: + case CLUSTER_1_BATTERY_098_VOLTAGE: + case CLUSTER_1_BATTERY_099_VOLTAGE: + case CLUSTER_1_BATTERY_100_VOLTAGE: + case CLUSTER_1_BATTERY_101_VOLTAGE: + case CLUSTER_1_BATTERY_102_VOLTAGE: + case CLUSTER_1_BATTERY_103_VOLTAGE: + case CLUSTER_1_BATTERY_104_VOLTAGE: + case CLUSTER_1_BATTERY_105_VOLTAGE: + case CLUSTER_1_BATTERY_106_VOLTAGE: + case CLUSTER_1_BATTERY_107_VOLTAGE: + case CLUSTER_1_BATTERY_108_VOLTAGE: + case CLUSTER_1_BATTERY_109_VOLTAGE: + case CLUSTER_1_BATTERY_110_VOLTAGE: + case CLUSTER_1_BATTERY_111_VOLTAGE: + case CLUSTER_1_BATTERY_112_VOLTAGE: + case CLUSTER_1_BATTERY_113_VOLTAGE: + case CLUSTER_1_BATTERY_114_VOLTAGE: + case CLUSTER_1_BATTERY_115_VOLTAGE: + case CLUSTER_1_BATTERY_116_VOLTAGE: + case CLUSTER_1_BATTERY_117_VOLTAGE: + case CLUSTER_1_BATTERY_118_VOLTAGE: + case CLUSTER_1_BATTERY_119_VOLTAGE: + case CLUSTER_1_BATTERY_120_VOLTAGE: + case CLUSTER_1_BATTERY_121_VOLTAGE: + case CLUSTER_1_BATTERY_122_VOLTAGE: + case CLUSTER_1_BATTERY_123_VOLTAGE: + case CLUSTER_1_BATTERY_124_VOLTAGE: + case CLUSTER_1_BATTERY_125_VOLTAGE: + case CLUSTER_1_BATTERY_126_VOLTAGE: + case CLUSTER_1_BATTERY_127_VOLTAGE: + case CLUSTER_1_BATTERY_128_VOLTAGE: + case CLUSTER_1_BATTERY_129_VOLTAGE: + case CLUSTER_1_BATTERY_130_VOLTAGE: + case CLUSTER_1_BATTERY_131_VOLTAGE: + case CLUSTER_1_BATTERY_132_VOLTAGE: + case CLUSTER_1_BATTERY_133_VOLTAGE: + case CLUSTER_1_BATTERY_134_VOLTAGE: + case CLUSTER_1_BATTERY_135_VOLTAGE: + case CLUSTER_1_BATTERY_136_VOLTAGE: + case CLUSTER_1_BATTERY_137_VOLTAGE: + case CLUSTER_1_BATTERY_138_VOLTAGE: + case CLUSTER_1_BATTERY_139_VOLTAGE: + case CLUSTER_1_BATTERY_140_VOLTAGE: + case CLUSTER_1_BATTERY_141_VOLTAGE: + case CLUSTER_1_BATTERY_142_VOLTAGE: + case CLUSTER_1_BATTERY_143_VOLTAGE: + case CLUSTER_1_BATTERY_144_VOLTAGE: + case CLUSTER_1_BATTERY_145_VOLTAGE: + case CLUSTER_1_BATTERY_146_VOLTAGE: + case CLUSTER_1_BATTERY_147_VOLTAGE: + case CLUSTER_1_BATTERY_148_VOLTAGE: + case CLUSTER_1_BATTERY_149_VOLTAGE: + case CLUSTER_1_BATTERY_150_VOLTAGE: + case CLUSTER_1_BATTERY_151_VOLTAGE: + case CLUSTER_1_BATTERY_152_VOLTAGE: + case CLUSTER_1_BATTERY_153_VOLTAGE: + case CLUSTER_1_BATTERY_154_VOLTAGE: + case CLUSTER_1_BATTERY_155_VOLTAGE: + case CLUSTER_1_BATTERY_156_VOLTAGE: + case CLUSTER_1_BATTERY_157_VOLTAGE: + case CLUSTER_1_BATTERY_158_VOLTAGE: + case CLUSTER_1_BATTERY_159_VOLTAGE: + case CLUSTER_1_BATTERY_160_VOLTAGE: + case CLUSTER_1_BATTERY_161_VOLTAGE: + case CLUSTER_1_BATTERY_162_VOLTAGE: + case CLUSTER_1_BATTERY_163_VOLTAGE: + case CLUSTER_1_BATTERY_164_VOLTAGE: + case CLUSTER_1_BATTERY_165_VOLTAGE: + case CLUSTER_1_BATTERY_166_VOLTAGE: + case CLUSTER_1_BATTERY_167_VOLTAGE: + case CLUSTER_1_BATTERY_168_VOLTAGE: + case CLUSTER_1_BATTERY_169_VOLTAGE: + case CLUSTER_1_BATTERY_170_VOLTAGE: + case CLUSTER_1_BATTERY_171_VOLTAGE: + case CLUSTER_1_BATTERY_172_VOLTAGE: + case CLUSTER_1_BATTERY_173_VOLTAGE: + case CLUSTER_1_BATTERY_174_VOLTAGE: + case CLUSTER_1_BATTERY_175_VOLTAGE: + case CLUSTER_1_BATTERY_176_VOLTAGE: + case CLUSTER_1_BATTERY_177_VOLTAGE: + case CLUSTER_1_BATTERY_178_VOLTAGE: + case CLUSTER_1_BATTERY_179_VOLTAGE: + case CLUSTER_1_BATTERY_180_VOLTAGE: + case CLUSTER_1_BATTERY_181_VOLTAGE: + case CLUSTER_1_BATTERY_182_VOLTAGE: + case CLUSTER_1_BATTERY_183_VOLTAGE: + case CLUSTER_1_BATTERY_184_VOLTAGE: + case CLUSTER_1_BATTERY_185_VOLTAGE: + case CLUSTER_1_BATTERY_186_VOLTAGE: + case CLUSTER_1_BATTERY_187_VOLTAGE: + case CLUSTER_1_BATTERY_188_VOLTAGE: + case CLUSTER_1_BATTERY_189_VOLTAGE: + case CLUSTER_1_BATTERY_190_VOLTAGE: + case CLUSTER_1_BATTERY_191_VOLTAGE: + case CLUSTER_1_BATTERY_192_VOLTAGE: + case CLUSTER_1_BATTERY_193_VOLTAGE: + case CLUSTER_1_BATTERY_194_VOLTAGE: + case CLUSTER_1_BATTERY_195_VOLTAGE: + case CLUSTER_1_BATTERY_196_VOLTAGE: + case CLUSTER_1_BATTERY_197_VOLTAGE: + case CLUSTER_1_BATTERY_198_VOLTAGE: + case CLUSTER_1_BATTERY_199_VOLTAGE: + case CLUSTER_1_BATTERY_200_VOLTAGE: + case CLUSTER_1_BATTERY_201_VOLTAGE: + case CLUSTER_1_BATTERY_202_VOLTAGE: + case CLUSTER_1_BATTERY_203_VOLTAGE: + case CLUSTER_1_BATTERY_204_VOLTAGE: + case CLUSTER_1_BATTERY_205_VOLTAGE: + case CLUSTER_1_BATTERY_206_VOLTAGE: + case CLUSTER_1_BATTERY_207_VOLTAGE: + case CLUSTER_1_BATTERY_208_VOLTAGE: + case CLUSTER_1_BATTERY_209_VOLTAGE: + case CLUSTER_1_BATTERY_210_VOLTAGE: + case CLUSTER_1_BATTERY_211_VOLTAGE: + case CLUSTER_1_BATTERY_212_VOLTAGE: + case CLUSTER_1_BATTERY_213_VOLTAGE: + case CLUSTER_1_BATTERY_214_VOLTAGE: + case CLUSTER_1_BATTERY_215_VOLTAGE: + case CLUSTER_1_BATTERY_216_VOLTAGE: + case CLUSTER_1_BATTERY_217_VOLTAGE: + case CLUSTER_1_BATTERY_218_VOLTAGE: + case CLUSTER_1_BATTERY_219_VOLTAGE: + case CLUSTER_1_BATTERY_220_VOLTAGE: + case CLUSTER_1_BATTERY_221_VOLTAGE: + case CLUSTER_1_BATTERY_222_VOLTAGE: + case CLUSTER_1_BATTERY_223_VOLTAGE: + case CLUSTER_1_BATTERY_224_VOLTAGE: + case CLUSTER_1_BATTERY_225_VOLTAGE: + case CLUSTER_1_BATTERY_226_VOLTAGE: + case CLUSTER_1_BATTERY_227_VOLTAGE: + case CLUSTER_1_BATTERY_228_VOLTAGE: + case CLUSTER_1_BATTERY_229_VOLTAGE: + case CLUSTER_1_BATTERY_230_VOLTAGE: + case CLUSTER_1_BATTERY_231_VOLTAGE: + case CLUSTER_1_BATTERY_232_VOLTAGE: + case CLUSTER_1_BATTERY_233_VOLTAGE: + case CLUSTER_1_BATTERY_234_VOLTAGE: + case CLUSTER_1_BATTERY_235_VOLTAGE: + case CLUSTER_1_BATTERY_236_VOLTAGE: + case CLUSTER_1_BATTERY_237_VOLTAGE: + case CLUSTER_1_BATTERY_238_VOLTAGE: + case CLUSTER_1_BATTERY_239_VOLTAGE: + + case CLUSTER_1_BATTERY_00_TEMPERATURE: + case CLUSTER_1_BATTERY_01_TEMPERATURE: + case CLUSTER_1_BATTERY_02_TEMPERATURE: + case CLUSTER_1_BATTERY_03_TEMPERATURE: + case CLUSTER_1_BATTERY_04_TEMPERATURE: + case CLUSTER_1_BATTERY_05_TEMPERATURE: + case CLUSTER_1_BATTERY_06_TEMPERATURE: + case CLUSTER_1_BATTERY_07_TEMPERATURE: + case CLUSTER_1_BATTERY_08_TEMPERATURE: + case CLUSTER_1_BATTERY_09_TEMPERATURE: + case CLUSTER_1_BATTERY_10_TEMPERATURE: + case CLUSTER_1_BATTERY_11_TEMPERATURE: + case CLUSTER_1_BATTERY_12_TEMPERATURE: + case CLUSTER_1_BATTERY_13_TEMPERATURE: + case CLUSTER_1_BATTERY_14_TEMPERATURE: + case CLUSTER_1_BATTERY_15_TEMPERATURE: + case CLUSTER_1_BATTERY_16_TEMPERATURE: + case CLUSTER_1_BATTERY_17_TEMPERATURE: + case CLUSTER_1_BATTERY_18_TEMPERATURE: + case CLUSTER_1_BATTERY_19_TEMPERATURE: + case CLUSTER_1_BATTERY_20_TEMPERATURE: + case CLUSTER_1_BATTERY_21_TEMPERATURE: + case CLUSTER_1_BATTERY_22_TEMPERATURE: + case CLUSTER_1_BATTERY_23_TEMPERATURE: + case CLUSTER_1_BATTERY_24_TEMPERATURE: + case CLUSTER_1_BATTERY_25_TEMPERATURE: + case CLUSTER_1_BATTERY_26_TEMPERATURE: + case CLUSTER_1_BATTERY_27_TEMPERATURE: + case CLUSTER_1_BATTERY_28_TEMPERATURE: + case CLUSTER_1_BATTERY_29_TEMPERATURE: + case CLUSTER_1_BATTERY_30_TEMPERATURE: + case CLUSTER_1_BATTERY_31_TEMPERATURE: + case CLUSTER_1_BATTERY_32_TEMPERATURE: + case CLUSTER_1_BATTERY_33_TEMPERATURE: + case CLUSTER_1_BATTERY_34_TEMPERATURE: + case CLUSTER_1_BATTERY_35_TEMPERATURE: + case CLUSTER_1_BATTERY_36_TEMPERATURE: + case CLUSTER_1_BATTERY_37_TEMPERATURE: + case CLUSTER_1_BATTERY_38_TEMPERATURE: + case CLUSTER_1_BATTERY_39_TEMPERATURE: + case CLUSTER_1_BATTERY_40_TEMPERATURE: + case CLUSTER_1_BATTERY_41_TEMPERATURE: + case CLUSTER_1_BATTERY_42_TEMPERATURE: + case CLUSTER_1_BATTERY_43_TEMPERATURE: + case CLUSTER_1_BATTERY_44_TEMPERATURE: + case CLUSTER_1_BATTERY_45_TEMPERATURE: + case CLUSTER_1_BATTERY_46_TEMPERATURE: + case CLUSTER_1_BATTERY_47_TEMPERATURE: + + case CLUSTER_1_VOLTAGE: + case CLUSTER_1_CURRENT: + case CLUSTER_1_CHARGE_INDICATION: + case CLUSTER_1_SOH: + case CLUSTER_RUN_STATE: + case SYSTEM_INSULATION: + + case SYSTEM_ACCEPT_MAX_CHARGE_CURRENT: + case SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT: + case SYSTEM_OVER_VOLTAGE_PROTECTION: + case SYSTEM_UNDER_VOLTAGE_PROTECTION: + + case CLUSTER_1_MIN_CELL_TEMPERATURE: + case CLUSTER_1_MAX_CELL_TEMPERATURE: + case CLUSTER_1_MAX_CELL_TEMPERATURE_ID: + case CLUSTER_1_MAX_CELL_VOLTAGE: + case CLUSTER_1_MAX_CELL_VOLTAGE_ID: + case CLUSTER_1_MIN_CELL_TEMPERATURE_ID: + case CLUSTER_1_MIN_CELL_VOLTAGE: + case CLUSTER_1_MIN_CELL_VOLTAGE_ID: + return new IntegerReadChannel(s, channelId); + } + return null; + }) // + ).flatMap(channel -> channel); + } +} diff --git a/io.openems.edge.battery.soltaro/test/.gitignore b/io.openems.edge.battery.soltaro/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/AbstractModbusBridge.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/AbstractModbusBridge.java index 4b7cda4664a..7aa3e5c09b4 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/AbstractModbusBridge.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/AbstractModbusBridge.java @@ -23,11 +23,11 @@ import io.openems.edge.bridge.modbus.api.ModbusProtocol; import io.openems.edge.bridge.modbus.api.task.ReadTask; import io.openems.edge.bridge.modbus.api.task.WriteTask; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.common.worker.AbstractWorker; +import io.openems.edge.common.worker.AbstractCycleWorker; /** * Abstract service for connecting to, querying and writing to a Modbus device @@ -62,7 +62,7 @@ public AbstractModbusBridge() { Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(this, channelId); + return new StateCollectorChannel(this, channelId); } return null; })).flatMap(channel -> channel).forEach(channel -> this.addChannel(channel)); @@ -71,6 +71,7 @@ public AbstractModbusBridge() { /** * Remember defective devices (Unit IDs)? */ + @SuppressWarnings("unused") private final Set defectiveUnitIds = new ConcurrentSkipListSet(); /** @@ -111,7 +112,8 @@ public void removeProtocol(String sourceId) { this.protocols.removeAll(sourceId); } - private class ModbusWorker extends AbstractWorker { + private class ModbusWorker extends AbstractCycleWorker { + @Override public void activate(String name) { super.activate(name); @@ -145,7 +147,7 @@ protected void forever() { }); } /* - * Execute next read task + * Execute next read abstractTask */ try { readTask.executeQuery(AbstractModbusBridge.this); @@ -160,7 +162,7 @@ protected void forever() { * Returns the 'nextReadTasks' list. * * This checks if a device is listed as defective and - if it is - adds only one - * task with this unitId to the queue + * abstractTask with this unitId to the queue */ private List getNextReadTasks() { List result = new ArrayList<>(); @@ -168,16 +170,19 @@ private List getNextReadTasks() { // get the next read tasks from the protocol List nextReadTasks = protocol.getNextReadTasks(); // check if the unitId is defective - int unitId = protocol.getUnitId(); - if (nextReadTasks.size() > 0 && defectiveUnitIds.contains(unitId)) { - // it is defective. Add only one read task. - // This avoids filling the queue with requests that cannot be fulfilled anyway - // because the unitId is not reachable - result.add(nextReadTasks.get(0)); - } else { - // add all tasks to the next tasks - result.addAll(nextReadTasks); - } + // int unitId = protocol.getUnitId(); + // FIXME: if we do the following in here, we will eventually miss the + // ONCE-priority tasks + // if (nextReadTasks.size() > 0 && defectiveUnitIds.contains(unitId)) { + // // it is defective. Add only one read abstractTask. + // // This avoids filling the queue with requests that cannot be fulfilled + // anyway + // // because the unitId is not reachable + // result.add(nextReadTasks.get(0)); + // } else { + // add all tasks to the next tasks + result.addAll(nextReadTasks); + // } }); return result; } @@ -189,12 +194,6 @@ private List getNextWriteTasks() { }); return result; } - - @Override - protected int getCycleTime() { - // TODO calculate cycle time to optimize handling of read and write tasks - return 1000; - } } @Override @@ -202,6 +201,7 @@ public void handleEvent(Event event) { switch (event.getTopic()) { case EdgeEventConstants.TOPIC_CYCLE_EXECUTE_WRITE: this.forceWrite.set(true); + this.worker.triggerNextCycle(); break; } } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcp.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcp.java index b6d71f8bfa0..bfd339159dc 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcp.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/BridgeModbusTcp.java @@ -42,9 +42,9 @@ public class BridgeModbusTcp extends AbstractModbusBridge implements BridgeModbu private InetAddress ipAddress = null; @Activate - void activate(ComponentContext context, ConfigTcp config) throws UnknownHostException { + protected void activate(ComponentContext context, ConfigTcp config) throws UnknownHostException { super.activate(context, config.service_pid(), config.id(), config.enabled()); - this.ipAddress = InetAddress.getByName(config.ip()); + this.setIpAddress(InetAddress.getByName(config.ip())); } @Deactivate @@ -74,7 +74,7 @@ private synchronized TCPMasterConnection getModbusConnection() throws OpenemsExc /* * create new connection */ - TCPMasterConnection connection = new TCPMasterConnection(this.ipAddress); + TCPMasterConnection connection = new TCPMasterConnection(this.getIpAddress()); connection.setPort(Modbus.DEFAULT_PORT); this._connection = connection; } @@ -83,10 +83,18 @@ private synchronized TCPMasterConnection getModbusConnection() throws OpenemsExc this._connection.connect(); } catch (Exception e) { throw new OpenemsException( - "Connection to [" + this.ipAddress.getHostAddress() + "] failed: " + e.getMessage(), e); + "Connection to [" + this.getIpAddress().getHostAddress() + "] failed: " + e.getMessage(), e); } this._connection.getModbusTransport().setTimeout(AbstractModbusBridge.DEFAULT_TIMEOUT); } return this._connection; } + + public InetAddress getIpAddress() { + return ipAddress; + } + + public void setIpAddress(InetAddress ipAddress) { + this.ipAddress = ipAddress; + } } \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ElementToChannelConverter.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ElementToChannelConverter.java index 316e1f0b85f..6a4e9f886c0 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ElementToChannelConverter.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ElementToChannelConverter.java @@ -19,6 +19,13 @@ public class ElementToChannelConverter { // channel -> element value -> value); + /** + * Applies a scale factor of -1. + * + * @see ElementToChannelScaleFactorConverter + */ + public final static ElementToChannelConverter SCALE_FACTOR_MINUS_1 = new ElementToChannelScaleFactorConverter(-1); + /** * Applies a scale factor of 1. * diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusProtocol.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusProtocol.java index 59a6cea6169..5f99171e686 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusProtocol.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusProtocol.java @@ -1,19 +1,16 @@ package io.openems.edge.bridge.modbus.api; -import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.ArrayListMultimap; - import io.openems.edge.bridge.modbus.api.element.ModbusElement; -import io.openems.edge.bridge.modbus.api.task.Priority; +import io.openems.edge.bridge.modbus.api.task.AbstractTask; import io.openems.edge.bridge.modbus.api.task.ReadTask; import io.openems.edge.bridge.modbus.api.task.Task; import io.openems.edge.bridge.modbus.api.task.WriteTask; +import io.openems.edge.common.taskmanager.TaskManager; public class ModbusProtocol { @@ -25,19 +22,14 @@ public class ModbusProtocol { private final int unitId; /** - * All ReadTasks by their Priority - */ - private final ArrayListMultimap readTasks = ArrayListMultimap.create(); - - /** - * Next queue of ReadTasks + * TaskManager for ReadTasks */ - private final ArrayListMultimap nextReadTasks = ArrayListMultimap.create(); + private final TaskManager readTaskManager = new TaskManager<>(); /** - * All WriteTasks + * TaskManager for WriteTasks */ - private final List writeTasks = new ArrayList<>(); + private final TaskManager writeTaskManager = new TaskManager<>(); public ModbusProtocol(int unitId, Task... tasks) { this.unitId = unitId; @@ -50,88 +42,49 @@ public int getUnitId() { return unitId; } - public void addTask(Task task) { - // add the unitId to the task + public synchronized void addTask(Task task) { + // add the unitId to the abstractTask task.setUnitId(this.unitId); - // check task for plausibility + // check abstractTask for plausibility this.checkTask(task); /* * fill writeTasks */ if (task instanceof WriteTask) { - WriteTask writeTask = (WriteTask) task; - this.writeTasks.add(writeTask); + this.writeTaskManager.addTask((WriteTask) task); } /* - * fill readTasks + * fill readTaskManager */ if (task instanceof ReadTask) { - ReadTask readTask = (ReadTask) task; - this.readTasks.put(task.getPriority(), readTask); + this.readTaskManager.addTask((ReadTask) task); } } /** - * Returns the next list of ReadTasks that should be executed within one cycle + * Returns the next list of WriteTasks that should be executed within one cycle * * @return */ - public List getNextReadTasks() { - List result = new ArrayList<>(this.readTasks.get(Priority.HIGH).size() + 1); - this.readTasks.keySet().forEach(priority -> { - /* - * Evaluates, how many tasks should be taken per priority for the result - */ - int take = 0; // how many tasks should be taken? - switch (priority) { - case HIGH: - take = -1; // take all tasks - break; - case LOW: - take = 1; // take one task - break; - } - /* - * Apply the 'take' value - */ - if (take == 0) { - // add none - } else if (take < 0) { - // take all read tasks - result.addAll(this.readTasks.get(priority)); - } else { - synchronized (this.nextReadTasks) { - if (this.nextReadTasks.get(priority).size() == 0) { - // refill the queue - this.nextReadTasks.putAll(priority, this.readTasks.get(priority)); - } - // take the given number of tasks; using nextReadTasks as a buffer queue. - Iterator iter = this.nextReadTasks.get(priority).iterator(); - for (int i = 0; i < take && iter.hasNext(); i++) { - result.add(iter.next()); - iter.remove(); - } - } - } - }); - return result; + public List getNextWriteTasks() { + return this.writeTaskManager.getNextReadTasks(); } - + /** - * Returns the next list of WriteTasks that should be executed within one cycle + * Returns the next list of ReadTasks that should be executed within one cycle * * @return */ - public List getNextWriteTasks() { - return this.writeTasks; + public List getNextReadTasks() { + return this.readTaskManager.getNextReadTasks(); } /** - * Checks a {@link Task} for plausibility + * Checks a {@link AbstractTask} for plausibility * * @param task */ - private void checkTask(Task task) { + private synchronized void checkTask(Task task) { int address = task.getStartAddress(); for (ModbusElement element : task.getElements()) { if (element.getStartAddress() != address) { diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractDoubleWordElement.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractDoubleWordElement.java index 509ba258a68..a85c99a17f3 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractDoubleWordElement.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractDoubleWordElement.java @@ -3,6 +3,9 @@ import java.nio.ByteBuffer; import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.ghgande.j2mod.modbus.procimg.InputRegister; import com.ghgande.j2mod.modbus.procimg.Register; import com.ghgande.j2mod.modbus.procimg.SimpleRegister; @@ -12,6 +15,8 @@ public abstract class AbstractDoubleWordElement extends AbstractModbusRegisterElement { + private final Logger log = LoggerFactory.getLogger(AbstractDoubleWordElement.class); + protected WordOrder wordOrder = WordOrder.MSWLSW; public AbstractDoubleWordElement(OpenemsType type, int startAddress) { @@ -51,6 +56,9 @@ protected final void _setInputRegisters(InputRegister... registers) { @Override public final void _setNextWriteValue(Optional valueOpt) throws OpenemsException { + if (this.isDebug()) { + log.info("Element [" + this + "] set next write value to [" + valueOpt.orElse(null) + "]."); + } if (valueOpt.isPresent()) { ByteBuffer buff = ByteBuffer.allocate(4).order(this.getByteOrder()); buff = this.toByteBuffer(buff, valueOpt.get()); diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractModbusElement.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractModbusElement.java index 96fad93ccd3..c3a5f3c6420 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractModbusElement.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractModbusElement.java @@ -8,7 +8,7 @@ import org.slf4j.LoggerFactory; import io.openems.common.types.OpenemsType; -import io.openems.edge.bridge.modbus.api.task.Task; +import io.openems.edge.bridge.modbus.api.task.AbstractTask; public abstract class AbstractModbusElement implements ModbusElement { @@ -18,7 +18,7 @@ public abstract class AbstractModbusElement implements ModbusElement { private final int startAddress; private final boolean isIgnored; - protected Task task = null; + protected AbstractTask abstractTask = null; public AbstractModbusElement(OpenemsType type, int startAddress) { this(type, startAddress, false); @@ -59,12 +59,12 @@ public boolean isIgnored() { } @Override - public void setModbusTask(Task task) { - this.task = task; + public void setModbusTask(AbstractTask abstractTask) { + this.abstractTask = abstractTask; } - public Task getModbusTask() { - return task; + public AbstractTask getModbusTask() { + return abstractTask; } protected void setValue(T value) { diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractWordElement.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractWordElement.java index b230f56bc5c..288e1c59d02 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractWordElement.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/AbstractWordElement.java @@ -4,6 +4,9 @@ import java.nio.ByteOrder; import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.ghgande.j2mod.modbus.procimg.InputRegister; import com.ghgande.j2mod.modbus.procimg.Register; import com.ghgande.j2mod.modbus.procimg.SimpleRegister; @@ -15,6 +18,8 @@ public abstract class AbstractWordElement extends AbstractModbusRegisterEleme private final static ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.BIG_ENDIAN; + private final Logger log = LoggerFactory.getLogger(AbstractWordElement.class); + protected ByteOrder byteOrder = DEFAULT_BYTE_ORDER; public AbstractWordElement(OpenemsType type, int startAddress) { @@ -46,6 +51,9 @@ protected final void _setInputRegisters(InputRegister... registers) { @Override public final void _setNextWriteValue(Optional valueOpt) throws OpenemsException { + if (this.isDebug()) { + log.info("Element [" + this + "] set next write value to [" + valueOpt.orElse(null) + "]."); + } if (valueOpt.isPresent()) { ByteBuffer buff = ByteBuffer.allocate(2).order(this.getByteOrder()); buff = this.toByteBuffer(buff, valueOpt.get()); diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/CoilElement.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/CoilElement.java index 6d99dfd118e..61219ccbb82 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/CoilElement.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/CoilElement.java @@ -29,11 +29,14 @@ public int getLength() { @Override public void _setNextWriteValue(Optional valueOpt) throws OpenemsException { + if (this.isDebug()) { + log.info("Element [" + this + "] set next write value to [" + valueOpt.orElse(null) + "]."); + } this.nextWriteValue = valueOpt; } @Override - public void setInputCoil(boolean coil) throws OpenemsException { + public void setInputCoil(Boolean coil) throws OpenemsException { if (this.isDebug()) { log.info("Element [" + this + "] set input coil to [" + coil + "]"); } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/ModbusCoilElement.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/ModbusCoilElement.java index 48b23360a59..77bdf6a95b0 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/ModbusCoilElement.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/ModbusCoilElement.java @@ -14,7 +14,7 @@ public interface ModbusCoilElement extends ModbusElement { * @param coil * @throws OpenemsException */ - public void setInputCoil(boolean coil) throws OpenemsException; + public void setInputCoil(Boolean coil) throws OpenemsException; /** * Sets a value that should be written to the Modbus device diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/ModbusElement.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/ModbusElement.java index f4275bba28d..5d9b677472a 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/ModbusElement.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/element/ModbusElement.java @@ -5,7 +5,7 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.types.OpenemsType; import io.openems.edge.bridge.modbus.api.task.ReadTask; -import io.openems.edge.bridge.modbus.api.task.Task; +import io.openems.edge.bridge.modbus.api.task.AbstractTask; /** * A ModbusElement represents one or more registers or coils in a @@ -29,12 +29,12 @@ public interface ModbusElement { public abstract int getLength(); /** - * Set the {@link Task}, where this Element belongs to. This is called during - * {@link Task}.add() + * Set the {@link AbstractTask}, where this Element belongs to. This is called during + * {@link AbstractTask}.add() * * @param readTask */ - public void setModbusTask(Task task); + public void setModbusTask(AbstractTask abstractTask); /** * Whether this Element should be ignored (= DummyElement) diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadDigitalInputsTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadDigitalInputsTask.java new file mode 100644 index 00000000000..e750c3dc878 --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadDigitalInputsTask.java @@ -0,0 +1,50 @@ +package io.openems.edge.bridge.modbus.api.task; + +import com.ghgande.j2mod.modbus.msg.ModbusResponse; +import com.ghgande.j2mod.modbus.util.BitVector; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; +import io.openems.edge.bridge.modbus.api.element.ModbusCoilElement; +import io.openems.edge.bridge.modbus.api.element.ModbusElement; +import io.openems.edge.common.taskmanager.Priority; + +public abstract class AbstractReadDigitalInputsTask extends AbstractReadTask { + + public AbstractReadDigitalInputsTask(int startAddress, Priority priority, AbstractModbusElement... elements) { + super(startAddress, priority, elements); + } + + @Override + protected boolean isCorrectElementInstance(ModbusElement modbusElement) { + return modbusElement instanceof ModbusCoilElement; + } + + @Override + protected String getRequiredElementName() { + return "ModbusCoilElement"; + } + + @Override + protected void doElementSetInput(ModbusElement modbusElement, int position, Boolean[] response) throws OpenemsException { + ((ModbusCoilElement) modbusElement).setInputCoil( (Boolean) response[position]); + } + + @Override + protected int increasePosition(int position, ModbusElement modbusElement) { + return position + 1; + } + + @Override + protected Boolean[] handleResponse(ModbusResponse response) throws OpenemsException { + try { + return (Utils.toBooleanArray(getBitVector(response))); + } catch (ClassCastException e) { + throw new OpenemsException("Unexpected Modbus response. Expected [" + getExpectedInputClassname() + "], got [" + + response.getClass().getSimpleName() + "]"); + } + } + + protected abstract String getExpectedInputClassname(); + protected abstract BitVector getBitVector(ModbusResponse response) throws OpenemsException; +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadInputRegistersTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadInputRegistersTask.java new file mode 100644 index 00000000000..3c459153a49 --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadInputRegistersTask.java @@ -0,0 +1,39 @@ +package io.openems.edge.bridge.modbus.api.task; + +import java.util.Arrays; + +import com.ghgande.j2mod.modbus.procimg.InputRegister; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; +import io.openems.edge.bridge.modbus.api.element.ModbusElement; +import io.openems.edge.bridge.modbus.api.element.ModbusRegisterElement; +import io.openems.edge.common.taskmanager.Priority; + +public abstract class AbstractReadInputRegistersTask extends AbstractReadTask { + + public AbstractReadInputRegistersTask(int startAddress, Priority priority, AbstractModbusElement... elements) { + super(startAddress, priority, elements); + } + + @Override + protected boolean isCorrectElementInstance(ModbusElement modbusElement) { + return modbusElement instanceof ModbusRegisterElement; + } + + @Override + protected void doElementSetInput(ModbusElement modbusElement, int position, InputRegister[] response) throws OpenemsException { + ((ModbusRegisterElement) modbusElement).setInputRegisters( (InputRegister[]) + Arrays.copyOfRange(response, position, position + modbusElement.getLength())); + } + + @Override + protected String getRequiredElementName() { + return "ModbusRegisterElement"; + } + + @Override + protected int increasePosition(int position, ModbusElement modbusElement) { + return position + modbusElement.getLength(); + } +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadTask.java new file mode 100644 index 00000000000..65b9b165f4f --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractReadTask.java @@ -0,0 +1,99 @@ +package io.openems.edge.bridge.modbus.api.task; + +import com.ghgande.j2mod.modbus.ModbusException; +import com.ghgande.j2mod.modbus.msg.ModbusRequest; +import com.ghgande.j2mod.modbus.msg.ModbusResponse; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.AbstractModbusBridge; +import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; +import io.openems.edge.bridge.modbus.api.element.ModbusElement; +import io.openems.edge.common.taskmanager.Priority; + +/** + * An abstract Modbus 'AbstractTask' is holding references to one or more Modbus + * {@link AbstractModbusElement} which have register addresses in the same + * range. + * + * @author stefan.feilmeier + */ +public abstract class AbstractReadTask extends AbstractTask implements ReadTask{ + + private final Priority priority; + + public AbstractReadTask(int startAddress, Priority priority, AbstractModbusElement... elements) { + super(startAddress, elements); + this.priority = priority; + } + + public void executeQuery(AbstractModbusBridge bridge) throws OpenemsException { + T[] response; + try { + /* + * First try + */ + response = this.readElements(bridge); + } catch (OpenemsException | ModbusException e) { + /* + * Second try: with new connection + */ + bridge.closeModbusConnection(); + try { + response = this.readElements(bridge); + } catch (ModbusException e2) { + throw new OpenemsException("Transaction failed: " + e.getMessage(), e2); + } + } + + // Verify response length + if (response.length < getLength()) { + throw new OpenemsException("Received message is too short. Expected [" + getLength() + "], got [" + response.length + "]"); + } + + fillElements(response); + } + + protected T[] readElements(AbstractModbusBridge bridge) throws OpenemsException, ModbusException { + ModbusRequest request = getRequest(); + ModbusResponse response = Utils.getResponse(request, getUnitId(), bridge); + return handleResponse(response); + } + + protected void fillElements(T[] response) { + int position = 0; + for (ModbusElement modbusElement : this.getElements()) { + if (!(isCorrectElementInstance(modbusElement))) { + doErrorLog(modbusElement); + } else { + try { + if (!modbusElement.isIgnored()) { + doElementSetInput(modbusElement, position, response); + } + } catch (OpenemsException e) { + doWarnLog(e); + } + } + position = increasePosition(position, modbusElement); + } + } + + public Priority getPriority() { + return priority; + } + + protected abstract int increasePosition(int position, ModbusElement modbusElement); + protected abstract void doElementSetInput(ModbusElement modbusElement, int position, T[] response) throws OpenemsException; + protected abstract String getRequiredElementName(); + protected abstract boolean isCorrectElementInstance(ModbusElement modbusElement); + protected abstract ModbusRequest getRequest(); + protected abstract T[] handleResponse(ModbusResponse response) throws OpenemsException; + + private void doWarnLog(OpenemsException e) { + log.warn("Unable to fill modbus element. UnitId [" + this.getUnitId() + "] Address [" + getStartAddress() + + "] Length [" + getLength() + "]: " + e.getMessage()); + } + + private void doErrorLog(ModbusElement modbusElement) { + log.error("A " + getRequiredElementName() + " is required for a " + getActiondescription() + "Task! Element [" + modbusElement + "]"); + } +} diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractTask.java new file mode 100644 index 00000000000..0bcdb90ea76 --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/AbstractTask.java @@ -0,0 +1,74 @@ +package io.openems.edge.bridge.modbus.api.task; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; +import io.openems.edge.bridge.modbus.api.element.ModbusElement; + +/** + * An abstract Modbus 'AbstractTask' is holding references to one or more Modbus + * {@link AbstractModbusElement} which have register addresses in the same + * range. + * + * @author stefan.feilmeier + */ +public abstract class AbstractTask implements Task { + + private final int length; + private final int startAddress; + protected final Logger log; + + private ModbusElement[] elements; + private int unitId; // this is always set by ModbusProtocol.addTask() + + public AbstractTask(int startAddress, AbstractModbusElement... elements) { + log = LoggerFactory.getLogger(getClass()); + this.startAddress = startAddress; + this.elements = elements; + for (AbstractModbusElement element : elements) { + element.setModbusTask(this); + } + int length = 0; + for (AbstractModbusElement element : elements) { + length += element.getLength(); + } + this.length = length; + } + + public ModbusElement[] getElements() { + return elements; + } + + public int getLength() { + return length; + } + + public int getStartAddress() { + return startAddress; + } + + public void setUnitId(int unitId) { + this.unitId = unitId; + } + + public int getUnitId() { + return unitId; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(getActiondescription()); + sb.append(" ["); + sb.append(this.getStartAddress()); + sb.append("/0x"); + sb.append(Integer.toHexString(this.getStartAddress())); + sb.append(";length="); + sb.append(this.getLength()); + sb.append("]"); + return sb.toString(); + } + + protected abstract String getActiondescription(); +} diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC16WriteRegistersTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC16WriteRegistersTask.java index 73dfe9a255a..464e4ed188d 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC16WriteRegistersTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC16WriteRegistersTask.java @@ -4,11 +4,7 @@ import java.util.List; import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.io.ModbusTransaction; import com.ghgande.j2mod.modbus.msg.ModbusResponse; import com.ghgande.j2mod.modbus.msg.WriteMultipleRegistersRequest; import com.ghgande.j2mod.modbus.msg.WriteMultipleRegistersResponse; @@ -21,15 +17,13 @@ import io.openems.edge.bridge.modbus.api.element.ModbusRegisterElement; /** - * Implements a Write Holding Registers task, using Modbus function code 16 + * Implements a Write Holding Registers abstractTask, using Modbus function code 16 * (http://www.simplymodbus.ca/FC16.htm) */ -public class FC16WriteRegistersTask extends Task implements WriteTask { - - private final Logger log = LoggerFactory.getLogger(FC16WriteRegistersTask.class); +public class FC16WriteRegistersTask extends AbstractTask implements WriteTask { public FC16WriteRegistersTask(int startAddress, AbstractModbusElement... elements) { - super(startAddress, Priority.HIGH /* Write Tasks always have HIGH priority */, elements); + super(startAddress, elements); } private class CombinedWriteRegisters { @@ -95,12 +89,10 @@ public void executeWrite(AbstractModbusBridge bridge) throws OpenemsException { private void writeMultipleRegisters(AbstractModbusBridge bridge, int unitId, int startAddress, Register[] registers) throws ModbusException, OpenemsException { - ModbusTransaction transaction = bridge.getNewModbusTransaction(); - WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(startAddress, registers); - request.setUnitID(unitId); - transaction.setRequest(request); - transaction.execute(); - ModbusResponse response = transaction.getResponse(); + + WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(startAddress, registers); + ModbusResponse response = Utils.getResponse(request, unitId, bridge); + if (!(response instanceof WriteMultipleRegistersResponse)) { throw new OpenemsException("Unexpected Modbus response. Expected [WriteMultipleRegistersResponse], got [" + response.getClass().getSimpleName() + "]"); @@ -140,8 +132,7 @@ private List mergeWriteRegisters() { } @Override - public String toString() { - return "FC16 Write Registers [" + this.getStartAddress() + "/0x" + Integer.toHexString(this.getStartAddress()) - + ";length=" + this.getLength() + "]"; + protected String getActiondescription() { + return "FC16 Write Registers"; } } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC1ReadCoilsTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC1ReadCoilsTask.java index e565cc404dd..f65405d075f 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC1ReadCoilsTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC1ReadCoilsTask.java @@ -1,117 +1,42 @@ package io.openems.edge.bridge.modbus.api.task; -import java.util.BitSet; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.io.ModbusTransaction; +import com.ghgande.j2mod.modbus.msg.ModbusRequest; import com.ghgande.j2mod.modbus.msg.ModbusResponse; import com.ghgande.j2mod.modbus.msg.ReadCoilsRequest; import com.ghgande.j2mod.modbus.msg.ReadCoilsResponse; +import com.ghgande.j2mod.modbus.util.BitVector; -import io.openems.common.exceptions.OpenemsException; -import io.openems.edge.bridge.modbus.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; -import io.openems.edge.bridge.modbus.api.element.ModbusCoilElement; -import io.openems.edge.bridge.modbus.api.element.ModbusElement; +import io.openems.edge.common.taskmanager.Priority; /** - * Implements a Read Coils task, implementing Modbus function code 1 + * Implements a Read Coils abstractTask, implementing Modbus function code 1 * (http://www.simplymodbus.ca/FC01.htm) */ -public class FC1ReadCoilsTask extends Task implements ReadTask { - - private final Logger log = LoggerFactory.getLogger(FC1ReadCoilsTask.class); +public class FC1ReadCoilsTask extends AbstractReadDigitalInputsTask implements ReadTask { public FC1ReadCoilsTask(int startAddress, Priority priority, AbstractModbusElement... elements) { super(startAddress, priority, elements); } - public void executeQuery(AbstractModbusBridge bridge) throws OpenemsException { - // Query this Task - int startAddress = this.getStartAddress(); - int length = this.getLength(); - boolean[] response; - try { - /* - * First try - */ - response = this.readCoils(bridge, this.getUnitId(), startAddress, length); - } catch (OpenemsException | ModbusException e) { - /* - * Second try: with new connection - */ - bridge.closeModbusConnection(); - try { - response = this.readCoils(bridge, this.getUnitId(), startAddress, length); - } catch (ModbusException e2) { - throw new OpenemsException("Transaction failed: " + e.getMessage(), e2); - } - } - - // Verify response length - if (response.length < length) { - throw new OpenemsException( - "Received message is too short. Expected [" + length + "], got [" + response.length + "]"); - } - - // Fill elements - int position = 0; - for (ModbusElement modbusElement : this.getElements()) { - if (!(modbusElement instanceof ModbusCoilElement)) { - log.error("A ModbusCoilElement is required for a FC1ReadCoilsTask! Element [" + modbusElement + "]"); - } else { - // continue with correctly casted ModbusCoilElement - ModbusCoilElement element = (ModbusCoilElement) modbusElement; - try { - if (element.isIgnored()) { - // ignore dummy - } else { - element.setInputCoil(response[position]); - } - } catch (OpenemsException e) { - log.warn("Unable to fill modbus element. UnitId [" + this.getUnitId() + "] Address [" + startAddress - + "] Length [" + length + "]: " + e.getMessage()); - } - } - position++; - } + @Override + protected BitVector getBitVector(ModbusResponse response) { + ReadCoilsResponse coilsResponse = (ReadCoilsResponse) response; + return coilsResponse.getCoils(); } - private boolean[] readCoils(AbstractModbusBridge bridge, int unitId, int startAddress, int length) - throws OpenemsException, ModbusException { - ModbusTransaction transaction = bridge.getNewModbusTransaction(); - ReadCoilsRequest request = new ReadCoilsRequest(startAddress, length); - request.setUnitID(unitId); - transaction.setRequest(request); - transaction.execute(); - ModbusResponse response = transaction.getResponse(); - if (response instanceof ReadCoilsResponse) { - ReadCoilsResponse coilsResponse = (ReadCoilsResponse) response; - return toBooleanArray(coilsResponse.getCoils().getBytes()); - } else { - throw new OpenemsException("Unexpected Modbus response. Expected [ReadCoilsResponse], got [" - + response.getClass().getSimpleName() + "]"); - } + @Override + protected String getExpectedInputClassname() { + return "ReadCoilsResponse"; } @Override - public String toString() { - return "FC1 Read Coils [" + this.getStartAddress() + "/0x" + Integer.toHexString(this.getStartAddress()) - + ";length=" + this.getLength() + "]"; + protected ModbusRequest getRequest() { + return new ReadCoilsRequest(getStartAddress(), getLength()); } - /* - * Static Methods - */ - static boolean[] toBooleanArray(byte[] bytes) { - BitSet bits = BitSet.valueOf(bytes); - boolean[] bools = new boolean[bytes.length * 8]; - for (int i = bits.nextSetBit(0); i != -1; i = bits.nextSetBit(i + 1)) { - bools[i] = true; - } - return bools; + @Override + protected String getActiondescription() { + return "FC1 Read Coils"; } } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC2ReadInputsTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC2ReadInputsTask.java new file mode 100644 index 00000000000..b35e0089479 --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC2ReadInputsTask.java @@ -0,0 +1,42 @@ +package io.openems.edge.bridge.modbus.api.task; + +import com.ghgande.j2mod.modbus.msg.ModbusRequest; +import com.ghgande.j2mod.modbus.msg.ModbusResponse; +import com.ghgande.j2mod.modbus.msg.ReadInputDiscretesRequest; +import com.ghgande.j2mod.modbus.msg.ReadInputDiscretesResponse; +import com.ghgande.j2mod.modbus.util.BitVector; + +import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; +import io.openems.edge.common.taskmanager.Priority; + +/** + * Implements a Read Inputs abstractTask, implementing Modbus function code 2 + * (http://www.simplymodbus.ca/FC02.htm) + */ +public class FC2ReadInputsTask extends AbstractReadDigitalInputsTask implements ReadTask { + + public FC2ReadInputsTask(int startAddress, Priority priority, AbstractModbusElement... elements) { + super(startAddress, priority, elements); + } + + @Override + protected BitVector getBitVector(ModbusResponse response) { + ReadInputDiscretesResponse readInputDiscretesResponse = (ReadInputDiscretesResponse) response; + return readInputDiscretesResponse.getDiscretes(); + } + + @Override + protected String getActiondescription() { + return "FC2 Read Coils"; + } + + @Override + protected String getExpectedInputClassname() { + return "ReadInputDiscretesResponse"; + } + + @Override + protected ModbusRequest getRequest() { + return new ReadInputDiscretesRequest(getStartAddress(), getLength()); + } +} diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC3ReadRegistersTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC3ReadRegistersTask.java index b964e5554c3..3ce1eb99ed0 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC3ReadRegistersTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC3ReadRegistersTask.java @@ -1,96 +1,32 @@ package io.openems.edge.bridge.modbus.api.task; -import java.util.Arrays; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.io.ModbusTransaction; +import com.ghgande.j2mod.modbus.msg.ModbusRequest; import com.ghgande.j2mod.modbus.msg.ModbusResponse; import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersRequest; import com.ghgande.j2mod.modbus.msg.ReadMultipleRegistersResponse; -import com.ghgande.j2mod.modbus.procimg.Register; +import com.ghgande.j2mod.modbus.procimg.InputRegister; import io.openems.common.exceptions.OpenemsException; -import io.openems.edge.bridge.modbus.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; -import io.openems.edge.bridge.modbus.api.element.ModbusElement; -import io.openems.edge.bridge.modbus.api.element.ModbusRegisterElement; +import io.openems.edge.common.taskmanager.Priority; /** - * Implements a Read Holding Register task, implementing Modbus function code 3 + * Implements a Read Holding Register abstractTask, implementing Modbus function code 3 * (http://www.simplymodbus.ca/FC03.htm) */ -public class FC3ReadRegistersTask extends Task implements ReadTask { - - private final Logger log = LoggerFactory.getLogger(FC3ReadRegistersTask.class); +public class FC3ReadRegistersTask extends AbstractReadInputRegistersTask implements ReadTask { public FC3ReadRegistersTask(int startAddress, Priority priority, AbstractModbusElement... elements) { super(startAddress, priority, elements); } - public void executeQuery(AbstractModbusBridge bridge) throws OpenemsException { - // Query this Task - int startAddress = this.getStartAddress(); - int length = this.getLength(); - Register[] response; - try { - /* - * First try - */ - response = this.readRegisters(bridge, this.getUnitId(), startAddress, length); - } catch (OpenemsException | ModbusException e) { - /* - * Second try: with new connection - */ - bridge.closeModbusConnection(); - try { - response = this.readRegisters(bridge, this.getUnitId(), startAddress, length); - } catch (ModbusException e2) { - throw new OpenemsException("Transaction failed: " + e.getMessage(), e2); - } - } - - // Verify response length - if (response.length < length) { - throw new OpenemsException( - "Received message is too short. Expected [" + length + "], got [" + response.length + "]"); - } - - // Fill elements - int position = 0; - for (ModbusElement modbusElement : this.getElements()) { - if (!(modbusElement instanceof ModbusRegisterElement)) { - log.error("A ModbusRegisterElement is required for a FC3ReadHoldingRegisterTask! Element [" - + modbusElement + "]"); - } else { - // continue with correctly casted ModbusRegisterElement - ModbusRegisterElement element = (ModbusRegisterElement) modbusElement; - try { - if (element.isIgnored()) { - // ignore dummy - } else { - element.setInputRegisters( - Arrays.copyOfRange(response, position, position + element.getLength())); - } - } catch (OpenemsException e) { - log.warn("Unable to fill modbus element. UnitId [" + this.getUnitId() + "] Address [" + startAddress - + "] Length [" + length + "]: " + e.getMessage()); - } - } - position += modbusElement.getLength(); - } + @Override + protected ModbusRequest getRequest() { + return new ReadMultipleRegistersRequest(getStartAddress(), getLength()); } - private Register[] readRegisters(AbstractModbusBridge bridge, int unitId, int startAddress, int length) - throws OpenemsException, ModbusException { - ModbusTransaction transaction = bridge.getNewModbusTransaction(); - ReadMultipleRegistersRequest request = new ReadMultipleRegistersRequest(startAddress, length); - request.setUnitID(unitId); - transaction.setRequest(request); - transaction.execute(); - ModbusResponse response = transaction.getResponse(); + @Override + protected InputRegister[] handleResponse(ModbusResponse response) throws OpenemsException { if (response instanceof ReadMultipleRegistersResponse) { ReadMultipleRegistersResponse registersResponse = (ReadMultipleRegistersResponse) response; return registersResponse.getRegisters(); @@ -101,8 +37,7 @@ private Register[] readRegisters(AbstractModbusBridge bridge, int unitId, int st } @Override - public String toString() { - return "FC3 Read Registers [" + this.getStartAddress() + "/0x" + Integer.toHexString(this.getStartAddress()) - + ";length=" + this.getLength() + "]"; + protected String getActiondescription() { + return "FC3 ReadHoldingRegister"; } } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC4ReadInputRegistersTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC4ReadInputRegistersTask.java new file mode 100644 index 00000000000..68be165e425 --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC4ReadInputRegistersTask.java @@ -0,0 +1,43 @@ +package io.openems.edge.bridge.modbus.api.task; + +import com.ghgande.j2mod.modbus.msg.ModbusRequest; +import com.ghgande.j2mod.modbus.msg.ModbusResponse; +import com.ghgande.j2mod.modbus.msg.ReadInputRegistersRequest; +import com.ghgande.j2mod.modbus.msg.ReadInputRegistersResponse; +import com.ghgande.j2mod.modbus.procimg.InputRegister; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; +import io.openems.edge.common.taskmanager.Priority; + +/** + * Implements a Read Input Register abstractTask, implementing Modbus function code 4 + * (http://www.simplymodbus.ca/FC04.htm) + */ +public class FC4ReadInputRegistersTask extends AbstractReadInputRegistersTask implements ReadTask { + + public FC4ReadInputRegistersTask(int startAddress, Priority priority, AbstractModbusElement... elements) { + super(startAddress, priority, elements); + } + + @Override + protected String getActiondescription() { + return "FC4 ReadHoldingRegister"; + } + + @Override + protected ModbusRequest getRequest() { + return new ReadInputRegistersRequest(getStartAddress(), getLength()); + } + + @Override + protected InputRegister[] handleResponse(ModbusResponse response) throws OpenemsException { + if (response instanceof ReadInputRegistersResponse) { + ReadInputRegistersResponse registersResponse = (ReadInputRegistersResponse) response; + return registersResponse.getRegisters(); + } else { + throw new OpenemsException("Unexpected Modbus response. Expected [ReadInputRegistersResponse], got [" + + response.getClass().getSimpleName() + "]"); + } + } +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC5WriteCoilTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC5WriteCoilTask.java index c9ef0bcab8c..8b8f7c28b7c 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC5WriteCoilTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC5WriteCoilTask.java @@ -2,11 +2,7 @@ import java.util.Optional; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.ghgande.j2mod.modbus.ModbusException; -import com.ghgande.j2mod.modbus.io.ModbusTransaction; import com.ghgande.j2mod.modbus.msg.ModbusResponse; import com.ghgande.j2mod.modbus.msg.WriteCoilRequest; import com.ghgande.j2mod.modbus.msg.WriteCoilResponse; @@ -18,15 +14,13 @@ import io.openems.edge.bridge.modbus.api.element.ModbusElement; /** - * Implements a Write Single Coil task, using Modbus function code 5 + * Implements a Write Single Coil abstractTask, using Modbus function code 5 * (http://www.simplymodbus.ca/FC05.htm) */ -public class FC5WriteCoilTask extends Task implements WriteTask { - - private final Logger log = LoggerFactory.getLogger(FC5WriteCoilTask.class); +public class FC5WriteCoilTask extends AbstractTask implements WriteTask { public FC5WriteCoilTask(int startAddress, AbstractModbusElement element) { - super(startAddress, Priority.HIGH /* Write Tasks always have HIGH priority */, element); + super(startAddress, element); } @Override @@ -60,12 +54,10 @@ public void executeWrite(AbstractModbusBridge bridge) throws OpenemsException { private void writeCoil(AbstractModbusBridge bridge, int unitId, int startAddress, boolean value) throws OpenemsException, ModbusException { - ModbusTransaction transaction = bridge.getNewModbusTransaction(); - WriteCoilRequest request = new WriteCoilRequest(startAddress, value); - request.setUnitID(this.getUnitId()); - transaction.setRequest(request); - transaction.execute(); - ModbusResponse response = transaction.getResponse(); + + WriteCoilRequest request = new WriteCoilRequest(startAddress, value); + ModbusResponse response = Utils.getResponse(request, unitId, bridge); + if (!(response instanceof WriteCoilResponse)) { throw new OpenemsException("Unexpected Modbus response. Expected [WriteCoilResponse], got [" + response.getClass().getSimpleName() + "]"); @@ -73,7 +65,7 @@ private void writeCoil(AbstractModbusBridge bridge, int unitId, int startAddress } @Override - public String toString() { - return "FC5 Write Coil [" + this.getStartAddress() + "/0x" + Integer.toHexString(this.getStartAddress()) + "]"; + protected String getActiondescription() { + return "FC5 Write Coil "; } } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC6WriteRegisterTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC6WriteRegisterTask.java new file mode 100644 index 00000000000..2e08ff43afa --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/FC6WriteRegisterTask.java @@ -0,0 +1,77 @@ +package io.openems.edge.bridge.modbus.api.task; + +import java.util.Optional; + +import com.ghgande.j2mod.modbus.ModbusException; +import com.ghgande.j2mod.modbus.msg.ModbusResponse; +import com.ghgande.j2mod.modbus.msg.WriteSingleRegisterRequest; +import com.ghgande.j2mod.modbus.msg.WriteSingleRegisterResponse; +import com.ghgande.j2mod.modbus.procimg.Register; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.AbstractModbusBridge; +import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; +import io.openems.edge.bridge.modbus.api.element.AbstractWordElement; +import io.openems.edge.bridge.modbus.api.element.ModbusElement; + +public class FC6WriteRegisterTask extends AbstractTask implements WriteTask { + + public FC6WriteRegisterTask(int startAddress, AbstractModbusElement element) { + super(startAddress, new AbstractModbusElement[] { element }); + } + + @Override + public void executeWrite(AbstractModbusBridge bridge) throws OpenemsException { + ModbusElement element = this.getElements()[0]; + + if (element instanceof AbstractWordElement) { + + Optional valueOpt = ((AbstractWordElement) element).getNextWriteValue(); + if (valueOpt.isPresent()) { + Register[] registers = valueOpt.get(); + + if (registers.length == 1 && registers[0] != null) { + // found value -> write + try { + /* + * First try + */ + + this.writeSingleRegister(bridge, this.getUnitId(), this.getStartAddress(), registers[0]); + } catch (OpenemsException | ModbusException e) { + /* + * Second try: with new connection + */ + bridge.closeModbusConnection(); + try { + this.writeSingleRegister(bridge, this.getUnitId(), this.getStartAddress(), registers[0]); + } catch (ModbusException e2) { + throw new OpenemsException("Transaction failed: " + e.getMessage(), e2); + } + } + } else { + log.warn("Expecting exactly one register. Got [" + registers.length + "]"); + } + } + } else { + log.warn("Unable to execute Write for ModbusElement [" + element + "]: No AbstractWordElement!"); + } + } + + @Override + protected String getActiondescription() { + return "FC6 Write Register"; + } + + private void writeSingleRegister(AbstractModbusBridge bridge, int unitId, int startAddress, Register register) + throws ModbusException, OpenemsException { + + WriteSingleRegisterRequest request = new WriteSingleRegisterRequest(startAddress, register); + ModbusResponse response = Utils.getResponse(request, unitId, bridge); + + if (!(response instanceof WriteSingleRegisterResponse)) { + throw new OpenemsException("Unexpected Modbus response. Expected [WriteSingleRegisterResponse], got [" + + response.getClass().getSimpleName() + "]"); + } + } +} diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Priority.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Priority.java deleted file mode 100644 index e09d015f5bc..00000000000 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Priority.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.openems.edge.bridge.modbus.api.task; - -public enum Priority { - LOW, HIGH; -} diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/ReadTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/ReadTask.java index b7380612ffd..94e0f44539d 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/ReadTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/ReadTask.java @@ -5,7 +5,7 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.AbstractModbusBridge; import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; -import io.openems.edge.bridge.modbus.api.element.ModbusElement; +import io.openems.edge.common.taskmanager.ManagedTask; /** * A Modbus 'ReadTask' is holding references to one or more Modbus @@ -15,43 +15,14 @@ * * @author stefan.feilmeier */ -public interface ReadTask { +public interface ReadTask extends Task, ManagedTask { /** - * Sets the modbus unit id - * - * @param unitId - */ - public void setUnitId(int unitId); - - /** - * Gets the ModbusElements - * - * @return - */ - public ModbusElement[] getElements(); - - /** - * Gets the start modbus register address - * - * @return - */ - public int getStartAddress(); - - /** - * Gets the Priority of this ReadTask. The higher the priority, the more often - * the task is executed. (HIGH = execute in every cycle). - * - * @return - */ - public Priority getPriority(); - - /** - * Sends a query for this Task to the Modbus device + * Sends a query for this AbstractTask to the Modbus device * * @param bridge * @param unitId * @throws ModbusException */ - public abstract void executeQuery(AbstractModbusBridge bridge) throws OpenemsException; + public abstract void executeQuery(AbstractModbusBridge bridge) throws OpenemsException; } diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Task.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Task.java index 7380be0a1cc..2aba3102597 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Task.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Task.java @@ -1,62 +1,28 @@ package io.openems.edge.bridge.modbus.api.task; -import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement; import io.openems.edge.bridge.modbus.api.element.ModbusElement; -/** - * An abstract Modbus 'Task' is holding references to one or more Modbus - * {@link AbstractModbusElement} which have register addresses in the same - * range. - * - * @author stefan.feilmeier - */ -public abstract class Task { - - private final int length; - private final int startAddress; - private final Priority priority; - - private ModbusElement[] elements; - private int unitId; // this is always set by ModbusProtocol.addTask() - - public Task(int startAddress, Priority priority, AbstractModbusElement... elements) { - this.startAddress = startAddress; - this.priority = priority; - this.elements = elements; - for (AbstractModbusElement element : elements) { - element.setModbusTask(this); - } - int length = 0; - for (AbstractModbusElement element : elements) { - length += element.getLength(); - } - this.length = length; - } - - public ModbusElement[] getElements() { - return elements; - } - - public int getLength() { - return length; - } - - public int getStartAddress() { - return startAddress; - } - - public Priority getPriority() { - return priority; - } - - public void setUnitId(int unitId) { - this.unitId = unitId; - } - - public int getUnitId() { - return unitId; - } - - @Override - public abstract String toString(); -} +public interface Task { + + /** + * Sets the modbus unit id + * + * @param unitId + */ + void setUnitId(int unitId); + + /** + * Gets the ModbusElements + * + * @return + */ + ModbusElement[] getElements(); + + /** + * Gets the start modbus register address + * + * @return + */ + int getStartAddress(); + +} \ No newline at end of file diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Utils.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Utils.java new file mode 100644 index 00000000000..567d7c58949 --- /dev/null +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/Utils.java @@ -0,0 +1,64 @@ +package io.openems.edge.bridge.modbus.api.task; + +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import com.ghgande.j2mod.modbus.ModbusException; +import com.ghgande.j2mod.modbus.io.ModbusTransaction; +import com.ghgande.j2mod.modbus.msg.ModbusRequest; +import com.ghgande.j2mod.modbus.msg.ModbusResponse; +import com.ghgande.j2mod.modbus.procimg.InputRegister; +import com.ghgande.j2mod.modbus.util.BitVector; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.bridge.modbus.AbstractModbusBridge; + +public class Utils { + + public static Boolean[] toBooleanArray(BitVector v) { + Boolean[] bools = new Boolean[v.size()]; + for (int i = 0; i < v.size(); i++) { + bools[i] = v.getBit(i); + } + return bools; + } + + public static Boolean[] toBooleanArray(byte[] bytes) { + Boolean[] bools = new Boolean[bytes.length * 8]; + for (int i = 0; i < bytes.length * 8; i++) { + int byteIndex = i / 8; + bools[i] = (bytes[byteIndex] & (byte) (128 / Math.pow(2, i % 8))) != 0; + } + return bools; + } + + public static ModbusResponse getResponse(ModbusRequest request, int unitId, AbstractModbusBridge bridge) + throws OpenemsException, ModbusException { + request.setUnitID(unitId); + ModbusTransaction transaction = bridge.getNewModbusTransaction(); + transaction.setRequest(request); + transaction.execute(); + ModbusResponse response = transaction.getResponse(); + return response; + } + + public static String toBitString(InputRegister[] registers) { + return Arrays.stream(registers).map(register -> { + byte[] bs = register.toBytes(); + + return String.format("%8s", // + Integer.toBinaryString(bs[0] & 0xFF)).replace(' ', '0') // + + " " // + + String.format("%8s", // + Integer.toBinaryString(bs[1] & 0xFF)).replace(' ', '0'); + }).collect(Collectors.joining(" ")); + } + + public static String toBitString(byte[] bs) { + return IntStream.range(0, bs.length).map(idx -> bs[idx]).mapToObj(b -> { + return String.format("%8s", // + Integer.toBinaryString((byte) b & 0xFF)).replace(' ', '0'); + }).collect(Collectors.joining(" ")); + } +} diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/WriteTask.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/WriteTask.java index 0c03602b59c..e89ff9b1c40 100644 --- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/WriteTask.java +++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/task/WriteTask.java @@ -4,37 +4,26 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.edge.bridge.modbus.AbstractModbusBridge; -import io.openems.edge.bridge.modbus.api.element.ModbusElement; +import io.openems.edge.common.taskmanager.ManagedTask; +import io.openems.edge.common.taskmanager.Priority; -public interface WriteTask { +public interface WriteTask extends Task, ManagedTask { /** - * Sets the modbus unit id + * Executes writing for this AbstractTask to the Modbus device * + * @param bridge * @param unitId + * @throws ModbusException */ - public void setUnitId(int unitId); - - /** - * Gets the ModbusElements - * - * @return - */ - public ModbusElement[] getElements(); - + public abstract void executeWrite(AbstractModbusBridge bridge) throws OpenemsException; + /** - * Gets the start modbus register address + * Priority for WriteTasks is by default always HIGH. * * @return */ - public int getStartAddress(); - - /** - * Executes writing for this Task to the Modbus device - * - * @param bridge - * @param unitId - * @throws ModbusException - */ - public abstract void executeWrite(AbstractModbusBridge bridge) throws OpenemsException; + public default Priority getPriority() { + return Priority.HIGH; + } } diff --git a/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/task/UtilsTest.java b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/task/UtilsTest.java new file mode 100644 index 00000000000..48b26fdea4f --- /dev/null +++ b/io.openems.edge.bridge.modbus/test/io/openems/edge/bridge/modbus/api/task/UtilsTest.java @@ -0,0 +1,36 @@ +package io.openems.edge.bridge.modbus.api.task; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class UtilsTest { + + @Test + public void testToBooleanArray() { + + byte[] bs = new byte[] { + (byte)0xAA, (byte) 0xAA + }; + + Boolean[] bools = Utils.toBooleanArray(bs); + + assertEquals(true, bools[0]); + assertEquals(false, bools[1]); + assertEquals(true, bools[2]); + assertEquals(false, bools[3]); + assertEquals(true, bools[4]); + assertEquals(false, bools[5]); + assertEquals(true, bools[6]); + assertEquals(false, bools[7]); + assertEquals(true, bools[8]); + assertEquals(false, bools[9]); + assertEquals(true, bools[10]); + assertEquals(false, bools[11]); + assertEquals(true, bools[12]); + assertEquals(false, bools[13]); + assertEquals(true, bools[14]); + assertEquals(false, bools[15]); + } + +} diff --git a/io.openems.edge.common/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.common/.settings/org.eclipse.core.resources.prefs index 94d597eefd5..2ef91b7ec43 100644 --- a/io.openems.edge.common/.settings/org.eclipse.core.resources.prefs +++ b/io.openems.edge.common/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,5 @@ eclipse.preferences.version=1 +encoding//src/io/openems/edge/common/channel/doc/Unit.java=UTF-8 encoding//src/io/openems/edge/common/channel/doc/package-info.java=UTF-8 encoding//src/io/openems/edge/common/channel/merger/package-info.java=UTF-8 encoding//src/io/openems/edge/common/channel/package-info.java=UTF-8 diff --git a/io.openems.edge.common/bnd.bnd b/io.openems.edge.common/bnd.bnd index e3f7b2b74c5..b4915c9ede2 100644 --- a/io.openems.edge.common/bnd.bnd +++ b/io.openems.edge.common/bnd.bnd @@ -13,7 +13,8 @@ Export-Package: \ io.openems.edge.common.channel.value,\ io.openems.edge.api.user,\ io.openems.edge.common.user,\ - io.openems.edge.common.type + io.openems.edge.common.type,\ + io.openems.edge.common.taskmanager -includeresource: {readme.md} diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/AbstractReadChannel.java b/io.openems.edge.common/src/io/openems/edge/common/channel/AbstractReadChannel.java index 90fcbb5e1c9..6b6238989e0 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/AbstractReadChannel.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/AbstractReadChannel.java @@ -1,6 +1,7 @@ package io.openems.edge.common.channel; import java.util.List; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; @@ -18,11 +19,13 @@ public abstract class AbstractReadChannel implements Channel { private final Logger log = LoggerFactory.getLogger(AbstractReadChannel.class); + protected final OpenemsComponent parent; + private final ChannelId channelId; - private final OpenemsComponent component; private final OpenemsType type; private final List>> onUpdateCallbacks = new CopyOnWriteArrayList<>(); private final List>> onSetNextValueCallbacks = new CopyOnWriteArrayList<>(); + private final List>> onChangeCallbacks = new CopyOnWriteArrayList<>(); private volatile Value nextValue = null; // TODO add timeout for nextValue validity private volatile Value activeValue = null; @@ -31,11 +34,11 @@ public AbstractReadChannel(OpenemsType type, OpenemsComponent component, Channel this(type, component, channelId, null); } - public AbstractReadChannel(OpenemsType type, OpenemsComponent component, ChannelId channelId, T initialValue) { + public AbstractReadChannel(OpenemsType type, OpenemsComponent parent, ChannelId channelId, T initialValue) { this.nextValue = new Value(this, null); this.activeValue = new Value(this, null); this.type = type; - this.component = component; + this.parent = parent; this.channelId = channelId; // validate Type if (channelId.doc().getType().isPresent()) { @@ -66,18 +69,22 @@ public ChannelId channelId() { @Override public OpenemsComponent getComponent() { - return component; + return parent; } @Override public void nextProcessImage() { + boolean valueHasChanged = !Objects.equals(this.activeValue, this.nextValue); this.activeValue = this.nextValue; this.onUpdateCallbacks.forEach(callback -> callback.accept(this.activeValue)); + if (valueHasChanged) { + this.onChangeCallbacks.forEach(callback -> callback.accept(this.activeValue)); + } } @Override public ChannelAddress address() { - return new ChannelAddress(this.component.id(), this.channelId().id()); + return new ChannelAddress(this.parent.id(), this.channelId().id()); } @Override @@ -120,10 +127,16 @@ public void onUpdate(Consumer> callback) { this.onUpdateCallbacks.add(callback); } + @Override public void onSetNextValue(Consumer> callback) { this.onSetNextValueCallbacks.add(callback); } + @Override + public void onChange(Consumer> callback) { + this.onChangeCallbacks.add(callback); + } + /* * This is to help WriteChannels implement the WriteChannel interface. * 'onSetNextWriteCallbacks' is not final by purpose, because it might be called diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/Channel.java b/io.openems.edge.common/src/io/openems/edge/common/channel/Channel.java index f84944399f0..66aa5bec5a3 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/Channel.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/Channel.java @@ -24,8 +24,8 @@ *
  • a {@link OpenemsType} which needs to map to the generic parameter . * (via {@link Channel#getType()}) *
  • an (active) {@link Value}. (via {@link Channel#value()}) - *
  • callback methods to listen on value changes. (see - * {@link Channel#onUpdate()} and {@link Channel#onSetNextValue()}) + *
  • callback methods to listen on value updates and changes. (see + * {@link Channel#onChange()}, {@link Channel#onUpdate()} and {@link Channel#onSetNextValue()}) * * * Channels implement a 'Process Image' pattern. They provide an 'active' value @@ -127,8 +127,14 @@ public default void setNextValue(Object value) { Value value(); /** - * Add an onUpdate callback. It is called, after a new ActiveValue was set via + * Add an onUpdate callback. It is called, after the active value was updated by * nextProcessImage(). */ public void onUpdate(Consumer> callback); + + /** + * Add an onChange callback. It is called, after a new, different active value was set by + * nextProcessImage(). + */ + public void onChange(Consumer> callback); } diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/FloatReadChannel.java b/io.openems.edge.common/src/io/openems/edge/common/channel/FloatReadChannel.java new file mode 100644 index 00000000000..6dd0eefce25 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/FloatReadChannel.java @@ -0,0 +1,17 @@ +package io.openems.edge.common.channel; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.doc.ChannelId; +import io.openems.edge.common.component.OpenemsComponent; + +public class FloatReadChannel extends AbstractReadChannel { + + public FloatReadChannel(OpenemsComponent component, ChannelId channelId) { + super(OpenemsType.FLOAT, component, channelId); + } + + public FloatReadChannel(OpenemsComponent component, ChannelId channelId, Float initialValue) { + super(OpenemsType.FLOAT, component, channelId, initialValue); + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/StateChannel.java b/io.openems.edge.common/src/io/openems/edge/common/channel/StateChannel.java index a7fd3c7e4fb..7502329631a 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/StateChannel.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/StateChannel.java @@ -1,41 +1,17 @@ package io.openems.edge.common.channel; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - import io.openems.common.types.OpenemsType; import io.openems.edge.common.channel.doc.ChannelId; import io.openems.edge.common.component.OpenemsComponent; -public class StateChannel extends AbstractReadChannel { - - public enum States { - OK(0), WARNING(1), FAULT(2); - - private final int value; - - private States(int value) { - this.value = value; - } - - public int getValue() { - return value; - } - } - - private final Map> channels = Collections - .synchronizedMap(new HashMap<>()); +/** + * Represents a single state. Changes to the value are reported to the + * {@link StateCollectorChannel} "State" of the OpenEMS Component. + */ +public class StateChannel extends AbstractReadChannel { public StateChannel(OpenemsComponent component, ChannelId channelId) { - super(OpenemsType.INTEGER, component, channelId); + super(OpenemsType.BOOLEAN, component, channelId); } - protected void addChannel(Channel channel) { - if (channel == null) { - throw new NullPointerException( - "Trying to add 'null' Channel. Hint: Check for missing handling of Enum value."); - } - this.channels.put(channel.channelId(), channel); - } } diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/StateCollectorChannel.java b/io.openems.edge.common/src/io/openems/edge/common/channel/StateCollectorChannel.java new file mode 100644 index 00000000000..800b9c00601 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/StateCollectorChannel.java @@ -0,0 +1,84 @@ +package io.openems.edge.common.channel; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.doc.ChannelId; +import io.openems.edge.common.channel.doc.Level; +import io.openems.edge.common.component.OpenemsComponent; + +/** + * Collects the values of all {@link StateChannel}s. This class is used for the + * "State" Channel of every OpenEMS Component. + */ +public class StateCollectorChannel extends AbstractReadChannel { + + /** + * Holds all Channels that are connected to and collected by this StateCollectorChannel + */ + private final Map> channels = Collections + .synchronizedMap(new HashMap<>()); + + /** + * Holds Channels that have an active (true) value. + */ + private final Multimap activeStates = HashMultimap.create(); + + public StateCollectorChannel(OpenemsComponent parent, ChannelId channelId) { + super(OpenemsType.INTEGER, parent, channelId); + } + + public void addChannel(StateChannel channel) { + this.channels.put(channel.channelId(), channel); + + channel.onChange(value -> { + /* + * update activeStates + */ + Level channelLevel = channel.channelDoc().getLevel(); + if (value.orElse(false)) { + // Value is true -> add to activeStates + this.activeStates.put(channelLevel, channel.channelId()); + } else { + // Value is false or unknown -> remove from activeStates + this.activeStates.remove(channelLevel, channel.channelId()); + } + + /* + * Set my own next value according to activeStates. + * + * Higher value of Level beats lower value. + */ + int nextValue = 0; + for (Level level : Level.values()) { + if (this.activeStates.get(level).size() > 0) { + nextValue = Math.max(nextValue, level.getValue()); + } + } + this.setNextValue(nextValue); + }); + } + + public String listStates() { + StringBuilder result = new StringBuilder(); + for (Level level : Level.values()) { + Collection channelIds = this.activeStates.get(level); + if (channelIds.size() > 0) { + if(result.length() > 0) { + result.append("| "); + } + result.append(level.name() + ": "); + for(ChannelId channelId : channelIds) { + result.append(this.parent.channel(channelId).channelDoc().getText() + ","); + } + } + } + return result.toString(); + } +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Doc.java b/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Doc.java index 97b74fd4d35..e9f9713d2a2 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Doc.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Doc.java @@ -18,7 +18,7 @@ * * Possible meta information: *
      - *
    • read-only/writable flag {@link Doc#isWritable()} + *
    • read-only/writable flag {@link Doc#setWritable()} *
    • expected OpenemsType via {@link Doc#getType()} *
    • descriptive text via {@link Doc#getText()} *
    • a Unit via {@link Doc#getUnit()} @@ -43,7 +43,7 @@ public class Doc { * * @return */ - public Doc isWritable() { + public Doc setWritable() { this.isWritable = true; return this; } @@ -94,7 +94,7 @@ public Doc text(String text) { return this; } - String getText() { + public String getText() { return this.text; } @@ -123,8 +123,12 @@ public Unit getUnit() { */ private BiMap options = HashBiMap.create(); + public boolean hasOptions() { + return this.options.size() > 0; + } + public Doc option(int value, Enum option) { - this.options.put(value, option.name()); + this.options.put(value, option); return this; } @@ -132,8 +136,15 @@ public Doc option(Enum option) { this.options.put(option.ordinal(), option); // this.options.put(option.ordinal(), option.name()); return this; - } + } + public Doc options(Enum[] options) { + for(Enum option : options) { + this.option(((OptionsEnum)option).getValue(), option); + } + return this; + } + public Doc option(int value, String option) { this.options.put(value, option); return this; diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Level.java b/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Level.java index 05e22752e0f..8108667e5cc 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Level.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Level.java @@ -1,8 +1,18 @@ package io.openems.edge.common.channel.doc; -/* +/** * Severity/visibility Level */ public enum Level { - INFO, WARNING, FAULT + INFO(1), WARNING(2), FAULT(3); + + private final int value; + + private Level(int value) { + this.value = value; + } + + public int getValue() { + return value; + } } \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/doc/OptionsEnum.java b/io.openems.edge.common/src/io/openems/edge/common/channel/doc/OptionsEnum.java new file mode 100644 index 00000000000..1d4d058b10f --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/doc/OptionsEnum.java @@ -0,0 +1,8 @@ +package io.openems.edge.common.channel.doc; + +public interface OptionsEnum { + + int getValue(); + + String getOption(); +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Unit.java b/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Unit.java index b911e0435f7..12780e0a4c0 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Unit.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/doc/Unit.java @@ -31,12 +31,12 @@ public enum Unit { /** * Unit of Active Power [mW] */ - MILLIWATT("W", WATT, -3), - /* + MILLIWATT("mW", WATT, -3), + /** * Unit of Reactive Power [var] */ VOLT_AMPERE_REACTIVE("var"), - /* + /** * Unit of Apparent Power [VA] */ VOLT_AMPERE("VA"), @@ -53,7 +53,7 @@ public enum Unit { * Unit of Voltage [mV] */ MILLIVOLT("mV", VOLT, -3), - + /* * Current */ @@ -75,6 +75,10 @@ public enum Unit { * Unit of Energy [Wh] */ WATT_HOURS("Wh"), + /** + * Unit of Energy [kWh] + */ + KILOWATT_HOURS("kWh", WATT_HOURS, 3), /* * Frequency @@ -92,10 +96,15 @@ public enum Unit { /* * Temperature */ + + /** + * Unit of Temperature [�C] + */ + DEGREE_CELSIUS("�C"), /** - * Unit of Temperature [C] + * Unit of Temperature [d�C] */ - DEGREE_CELCIUS("C"), + DEZIDEGREE_CELSIUS("d�C", DEGREE_CELSIUS, -1), /* * Time @@ -103,7 +112,21 @@ public enum Unit { /** * Unit of Time in Seconds [s] */ - SECONDS("sec"); + SECONDS("sec"), + + /* + * Resistance + */ + + /** + * Unit of Resistance [Ohm] + */ + OHM("Ohm"), + + /** + * Unit of Resistance [kOhm] + */ + KILOOHM("kOhm", OHM, 3); private final Unit baseUnit; private final int scaleFactor; @@ -136,7 +159,8 @@ public String format(Object value, OpenemsType type) { case NONE: return value.toString(); case AMPERE: - case DEGREE_CELCIUS: + case DEGREE_CELSIUS: + case DEZIDEGREE_CELSIUS: case HERTZ: case MILLIAMPERE: case MILLIHERTZ: @@ -147,6 +171,8 @@ public String format(Object value, OpenemsType type) { case VOLT_AMPERE_REACTIVE: case WATT: case WATT_HOURS: + case OHM: + case KILOOHM: case SECONDS: return value + " " + this.symbol; case ON_OFF: diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/internal/AverageInteger.java b/io.openems.edge.common/src/io/openems/edge/common/channel/merger/AverageInteger.java similarity index 50% rename from io.openems.edge.core/src/io/openems/edge/core/sum/internal/AverageInteger.java rename to io.openems.edge.common/src/io/openems/edge/common/channel/merger/AverageInteger.java index 1f5b7586217..236a7f4ab0b 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/internal/AverageInteger.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/merger/AverageInteger.java @@ -1,16 +1,19 @@ -package io.openems.edge.core.sum.internal; +package io.openems.edge.common.channel.merger; import java.util.NoSuchElementException; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.core.sum.Sum; -import io.openems.edge.core.sum.Sum.ChannelId; public class AverageInteger extends ChannelsFunction { - public AverageInteger(Sum parent, ChannelId targetChannelId, - io.openems.edge.common.channel.doc.ChannelId sourceChannelId) { - super(parent, targetChannelId, sourceChannelId); +// public AverageInteger(Sum parent, ChannelId targetChannelId, +// io.openems.edge.common.channel.doc.ChannelId sourceChannelId) { +// super(parent, targetChannelId, sourceChannelId); +// } + + public AverageInteger(OpenemsComponent parent, io.openems.edge.common.channel.doc.ChannelId target, + io.openems.edge.common.channel.doc.ChannelId source) { + super(parent, target, source); } protected double calculate() throws NoSuchElementException { diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/internal/ChannelsFunction.java b/io.openems.edge.common/src/io/openems/edge/common/channel/merger/ChannelsFunction.java similarity index 81% rename from io.openems.edge.core/src/io/openems/edge/core/sum/internal/ChannelsFunction.java rename to io.openems.edge.common/src/io/openems/edge/common/channel/merger/ChannelsFunction.java index 90520b9b224..9dd37ddeec0 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/internal/ChannelsFunction.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/merger/ChannelsFunction.java @@ -1,4 +1,4 @@ -package io.openems.edge.core.sum.internal; +package io.openems.edge.common.channel.merger; import java.util.Map; import java.util.NoSuchElementException; @@ -12,7 +12,6 @@ import io.openems.edge.common.channel.doc.ChannelId; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.core.sum.Sum; public abstract class ChannelsFunction { @@ -24,8 +23,7 @@ public abstract class ChannelsFunction { protected final Map> valueMap = new ConcurrentHashMap<>(); - public ChannelsFunction(Sum parent, io.openems.edge.core.sum.Sum.ChannelId targetChannelId, - ChannelId sourceChannelId) { + public ChannelsFunction(OpenemsComponent parent, ChannelId targetChannelId, ChannelId sourceChannelId) { this.targetChannel = parent.channel(targetChannelId); this.sourceChannelId = sourceChannelId; } @@ -36,11 +34,7 @@ public void addComponent(C component) { } final Consumer> handler = value -> { this.valueMap.put(component.id(), value); - try { - this.targetChannel.setNextValue(this.calculate()); - } catch (NoSuchElementException e) { - this.targetChannel.setNextValue(null); - } + this.recalculateValue(); }; Channel channel = component.channel(this.sourceChannelId); handler.accept(channel.getNextValue()); // handle current value @@ -53,6 +47,7 @@ public void removeComponent(OpenemsComponent component) { "Remove Component [" + component.id() + "] of type [" + component.getClass().getSimpleName() + "]"); } this.valueMap.remove(component.id()); + this.recalculateValue(); } public ChannelsFunction debug() { @@ -60,5 +55,13 @@ public ChannelsFunction debug() { return this; } + private void recalculateValue() { + try { + this.targetChannel.setNextValue(this.calculate()); + } catch (NoSuchElementException e) { + this.targetChannel.setNextValue(null); + } + } + protected abstract double calculate() throws NoSuchElementException; } diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/internal/SumInteger.java b/io.openems.edge.common/src/io/openems/edge/common/channel/merger/SumInteger.java similarity index 64% rename from io.openems.edge.core/src/io/openems/edge/core/sum/internal/SumInteger.java rename to io.openems.edge.common/src/io/openems/edge/common/channel/merger/SumInteger.java index 91a4aa4d93e..30d01ccf551 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/internal/SumInteger.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/merger/SumInteger.java @@ -1,15 +1,13 @@ -package io.openems.edge.core.sum.internal; +package io.openems.edge.common.channel.merger; import java.util.NoSuchElementException; +import io.openems.edge.common.channel.doc.ChannelId; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.core.sum.Sum; -import io.openems.edge.core.sum.Sum.ChannelId; public class SumInteger extends ChannelsFunction { - public SumInteger(Sum parent, ChannelId targetChannelId, - io.openems.edge.common.channel.doc.ChannelId sourceChannelId) { + public SumInteger(OpenemsComponent parent, ChannelId targetChannelId, ChannelId sourceChannelId) { super(parent, targetChannelId, sourceChannelId); } diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/value/Value.java b/io.openems.edge.common/src/io/openems/edge/common/channel/value/Value.java index 230b6f0f0ed..19b5f0d118f 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/channel/value/Value.java +++ b/io.openems.edge.common/src/io/openems/edge/common/channel/value/Value.java @@ -127,6 +127,20 @@ public Enum asEnum() throws InvalidValueException { int intValue = TypeUtils.getAsType(OpenemsType.INTEGER, value); return this.parent.channelDoc().getOptionEnum(intValue); } + + + /** + * Gets the value as an Optional enum + * + * @return + */ + public Optional> asEnumOptional() { + try { + return Optional.ofNullable(asEnum()); + } catch (Exception e) { // if there is null in asEnum a NullPointerException is thrown + return Optional.empty(); + } + } /** * Gets the value in JSON format diff --git a/io.openems.edge.common/src/io/openems/edge/common/component/AbstractOpenemsComponent.java b/io.openems.edge.common/src/io/openems/edge/common/component/AbstractOpenemsComponent.java index 3575aa04d74..7b1ed2427a5 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/component/AbstractOpenemsComponent.java +++ b/io.openems.edge.common/src/io/openems/edge/common/component/AbstractOpenemsComponent.java @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.StateChannel; /** * This is the default implementation of the {@link OpenemsComponent} interface. @@ -105,7 +106,14 @@ protected void addChannel(Channel channel) { throw new NullPointerException( "Trying to add 'null' Channel. Hint: Check for missing handling of Enum value."); } + // Add Channel to channels list this.channels.put(channel.channelId().id(), channel); + /* + * Handle StateChannels + */ + if (channel instanceof StateChannel) { + this.getState().addChannel((StateChannel) channel); + } } @Override diff --git a/io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java b/io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java index 83665055fb7..eb9bdb44832 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java +++ b/io.openems.edge.common/src/io/openems/edge/common/component/OpenemsComponent.java @@ -9,9 +9,10 @@ import org.osgi.service.component.ComponentContext; import io.openems.edge.common.channel.Channel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.common.channel.doc.Level; /** * This is the base interface for and should be implemented by every service @@ -116,11 +117,12 @@ default > T channel(io.openems.edge.common.channel.doc.Chan Collection> channels(); public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { - // Running State of the component + // Running State of the component. Keep values in sync with 'Level' enum! STATE(new Doc().unit(Unit.NONE) // .option(0, "Ok") // - .option(1, "Warning") // - .option(2, "Fault")); + .option(1, Level.INFO) // + .option(2, Level.WARNING) // + .option(3, Level.FAULT)); private final Doc doc; @@ -134,8 +136,8 @@ public Doc doc() { } } - default StateChannel getState() { - return this._getChannelAs(ChannelId.STATE, StateChannel.class); + default StateCollectorChannel getState() { + return this._getChannelAs(ChannelId.STATE, StateCollectorChannel.class); } @SuppressWarnings("unchecked") @@ -173,22 +175,18 @@ public default String debugLog() { * Generates a 'target' filter on the 'Controllers' member so, that the target * component 'id' is in 'controllerIds'. * - * @param cm - * a ConfigurationAdmin instance. Get one using + * @param cm a ConfigurationAdmin instance. Get one using * - *
      -	 *            @Reference
      -	 *            ConfigurationAdmin cm;
      -	 *            
      + *
      +	 *               @Reference
      +	 *               ConfigurationAdmin cm;
      +	 *               
      * - * @param pid - * PID of the calling component (use 'config.service_pid()' or - * '(String)prop.get(Constants.SERVICE_PID)' - * @param member - * Name of the Method or Field with the Reference annotation, e.g. - * 'Controllers' for 'addControllers()' method - * @param ids - * Component IDs to be filtered for + * @param pid PID of the calling component (use 'config.service_pid()' or + * '(String)prop.get(Constants.SERVICE_PID)' + * @param member Name of the Method or Field with the Reference annotation, e.g. + * 'Controllers' for 'addControllers()' method + * @param ids Component IDs to be filtered for * * @return true if the filter was updated. You may use it to abort the * activate() method. @@ -198,7 +196,12 @@ public static boolean updateReferenceFilter(ConfigurationAdmin cm, String pid, S /* * generate required target filter */ - StringBuilder targetBuilder = new StringBuilder("(&(enabled=true)(|"); + // target component must be enabled + StringBuilder targetBuilder = new StringBuilder("(&(enabled=true)"); + // target component must not be the same as the calling component + targetBuilder.append("(!(service.pid=" + pid + "))"); + // add filter for given Component-IDs + targetBuilder.append("(|"); for (String id : ids) { targetBuilder.append("(id=" + id + ")"); } @@ -235,21 +238,17 @@ public static boolean updateReferenceFilter(ConfigurationAdmin cm, String pid, S * updateConfigurationProperty(cm, servicePid, "propertyName", "propertyValue"); * * - * @param cm - * a ConfigurationAdmin instance. Get one using + * @param cm a ConfigurationAdmin instance. Get one using * - *
      -	 *            @Reference
      -	 *            ConfigurationAdmin cm;
      -	 *            
      + *
      +	 *                 @Reference
      +	 *                 ConfigurationAdmin cm;
      +	 *                 
      * - * @param pid - * PID of the calling component (use 'config.service_pid()' or - * '(String)prop.get(Constants.SERVICE_PID)' - * @param property - * Name of the configuration property - * @param value - * New configuration value + * @param pid PID of the calling component (use 'config.service_pid()' or + * '(String)prop.get(Constants.SERVICE_PID)' + * @param property Name of the configuration property + * @param value New configuration value */ public static void updateConfigurationProperty(ConfigurationAdmin cm, String pid, String property, int value) { Configuration c; diff --git a/io.openems.edge.common/src/io/openems/edge/common/taskmanager/ManagedTask.java b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/ManagedTask.java new file mode 100644 index 00000000000..4ea478fe4a0 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/ManagedTask.java @@ -0,0 +1,7 @@ +package io.openems.edge.common.taskmanager; + +public interface ManagedTask { + + public Priority getPriority(); + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/taskmanager/Priority.java b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/Priority.java new file mode 100644 index 00000000000..04f6e5a7b8d --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/Priority.java @@ -0,0 +1,5 @@ +package io.openems.edge.common.taskmanager; + +public enum Priority { + HIGH, LOW, ONCE +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/taskmanager/Task.java b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/Task.java new file mode 100644 index 00000000000..b6979aeca25 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/Task.java @@ -0,0 +1,15 @@ +package io.openems.edge.common.taskmanager; + +public class Task { + + private final Priority priority; + + public Task(Priority priority) { + this.priority = priority; + } + + public Priority getPriority() { + return this.priority; + } + +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/taskmanager/TaskManager.java b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/TaskManager.java new file mode 100644 index 00000000000..cb730d32568 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/TaskManager.java @@ -0,0 +1,68 @@ +package io.openems.edge.common.taskmanager; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class TaskManager { + + private final List prioHighTasks = new ArrayList<>(); + private final List prioLowTasks = new ArrayList<>(); + private final List prioOnceTasks = new ArrayList<>(); + + private final Queue nextLowTasks = new LinkedList<>(); + private final Queue nextOnceTasks = new LinkedList<>(); + + @SafeVarargs + public TaskManager(T... tasks) { + for (T task : tasks) { + this.addTask(task); + } + } + + public void addTask(T task) { + switch (task.getPriority()) { + case HIGH: + this.prioHighTasks.add(task); + break; + case LOW: + this.prioLowTasks.add(task); + break; + case ONCE: + this.prioOnceTasks.add(task); + // Fill the 'nextOnceTasks'. This happens only once. + this.nextOnceTasks.add(task); + break; + } + } + + public synchronized List getNextReadTasks() { + List result = new ArrayList<>(); + /* + * Handle HIGH + */ + result.addAll(this.prioHighTasks); + + /* + * Handle LOW + */ + if (nextLowTasks.isEmpty()) { + // Refill the 'nextLowTasks'. This happens every time the list is empty. + this.nextLowTasks.addAll(prioLowTasks); + } + T task = nextLowTasks.poll(); + if (task != null) { + result.add(task); + } + + /* + * Handle ONCE + */ + task = nextOnceTasks.poll(); + if (task != null) { + result.add(task); + } + return result; + } +} \ No newline at end of file diff --git a/io.openems.edge.common/src/io/openems/edge/common/taskmanager/TasksManager.java b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/TasksManager.java new file mode 100644 index 00000000000..21f7b93c3c6 --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/TasksManager.java @@ -0,0 +1,64 @@ +package io.openems.edge.common.taskmanager; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class TasksManager { + + private final List prioHighTasks = new ArrayList<>(); + private final List prioLowTasks = new ArrayList<>(); + private final List prioOnceTasks = new ArrayList<>(); + + private final Queue nextLowTasks = new LinkedList<>(); + private final Queue nextOnceTasks = new LinkedList<>(); + + @SafeVarargs + public TasksManager(T... tasks) { + for (T task : tasks) { + switch (task.getPriority()) { + case HIGH: + this.prioHighTasks.add(task); + break; + case LOW: + this.prioLowTasks.add(task); + break; + case ONCE: + this.prioOnceTasks.add(task); + break; + } + } + // Fill the 'nextOnceTasks'. This happens only once. + this.nextOnceTasks.addAll(prioOnceTasks); + } + + public synchronized List getNextReadTasks() { + List result = new ArrayList<>(); + /* + * Handle HIGH + */ + result.addAll(this.prioHighTasks); + + /* + * Handle LOW + */ + if (nextLowTasks.isEmpty()) { + // Refill the 'nextLowTasks'. This happens every time the list is empty. + this.nextLowTasks.addAll(prioLowTasks); + } + T task = nextLowTasks.poll(); + if (task != null) { + result.add(task); + } + + /* + * Handle ONCE + */ + task = nextOnceTasks.poll(); + if (task != null) { + result.add(task); + } + return result; + } +} \ No newline at end of file diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/package-info.java b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/package-info.java similarity index 52% rename from io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/package-info.java rename to io.openems.edge.common/src/io/openems/edge/common/taskmanager/package-info.java index 6d50d2c8634..3f51222bd8b 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/package-info.java +++ b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/package-info.java @@ -1,2 +1,2 @@ @org.osgi.annotation.versioning.Version("1.0.0") -package io.openems.edge.ess.power.symmetric; +package io.openems.edge.common.taskmanager; diff --git a/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractCycleWorker.java b/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractCycleWorker.java new file mode 100644 index 00000000000..71c097ac68b --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractCycleWorker.java @@ -0,0 +1,32 @@ +package io.openems.edge.common.worker; + +/** + * A helper worker for tasks that need to be executed synchronized with the + * Cycle. Be sure to call 'triggerNextCycle()' once per Cycle (using an OSGi + * EventHandler). + */ +public abstract class AbstractCycleWorker extends AbstractWorker { + + @Override + public void activate(String name) { + super.activate(name); + } + + @Override + public void deactivate() { + super.deactivate(); + } + + @Override + protected final int getCycleTime() { + return -1; + } + + @Override + public void triggerNextCycle() { + super.triggerNextCycle(); + } + + @Override + protected abstract void forever(); +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractImmediateWorker.java b/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractImmediateWorker.java new file mode 100644 index 00000000000..661289e181c --- /dev/null +++ b/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractImmediateWorker.java @@ -0,0 +1,31 @@ +package io.openems.edge.common.worker; + +/** + * A helper worker for tasks that need to be executed forever without any + * interruption or sleep. + */ +public abstract class AbstractImmediateWorker extends AbstractWorker { + + @Override + public void activate(String name) { + super.activate(name); + } + + @Override + public void deactivate() { + super.deactivate(); + } + + @Override + protected final int getCycleTime() { + return 0; + } + + @Override + public void triggerNextCycle() { + super.triggerNextCycle(); + } + + @Override + protected abstract void forever(); +} diff --git a/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractWorker.java b/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractWorker.java index 29ef16e7ce6..099b7e4c3a7 100644 --- a/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractWorker.java +++ b/io.openems.edge.common/src/io/openems/edge/common/worker/AbstractWorker.java @@ -5,19 +5,22 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import io.openems.common.utils.Mutex; + public abstract class AbstractWorker { private final Logger log = LoggerFactory.getLogger(AbstractWorker.class); private final AtomicBoolean isForceRun = new AtomicBoolean(false); private final AtomicBoolean isStopped = new AtomicBoolean(false); - + private final Mutex cycleMutex = new Mutex(true); + /** * Initializes the worker and starts the worker thread * * @param name */ - protected void activate(String name) { + public void activate(String name) { if (name != null) { this.worker.setName(name); this.worker.start(); @@ -27,7 +30,7 @@ protected void activate(String name) { /** * Stops the worker thread */ - protected void deactivate() { + public void deactivate() { this.isStopped.set(true); } @@ -38,13 +41,18 @@ protected void deactivate() { /** * Gets the cycleTime of this worker in [ms]. + *
        + *
      • > 0 sets the minimum execution time of one Cycle + *
      • = 0 never wait between two consecutive executions of forever() + *
      • < 0 causes the Cycle to sleep forever until 'triggerNextRun()' is called + *
      * * @return */ protected abstract int getCycleTime(); /** - * Causes the Worker to interrupt sleeping and start again the run() method + * Causes the Worker to interrupt sleeping and start again the forever() method * immediately */ public void triggerForceRun() { @@ -52,6 +60,13 @@ public void triggerForceRun() { this.worker.interrupt(); } } + + /** + * Allows the next execution of the forever() method. + */ + public void triggerNextCycle() { + this.cycleMutex.release(); + } private final Thread worker = new Thread() { public void run() { @@ -67,9 +82,16 @@ public void run() { * Wait for next cycle */ try { - long sleep = getCycleTime() - (System.currentTimeMillis() - cycleStart); - if (sleep > 0) { - Thread.sleep(sleep); + int cycleTime = getCycleTime(); + if (cycleTime == 0) { + // no wait + } else if (cycleTime > 0) { + long sleep = cycleTime - (System.currentTimeMillis() - cycleStart); + if (sleep > 0) { + Thread.sleep(sleep); + } + } else { + cycleMutex.await(); } } catch (InterruptedException e) { if (isForceRun.get()) { @@ -103,8 +125,7 @@ public void run() { * ForceRun-Flag. It is not making sense anyway, because something is wrong with * the setup if we landed here. * - * @param duration - * in seconds + * @param duration in seconds */ private long onWorkerExceptionSleep(long duration) { if (duration < 60) { diff --git a/io.openems.edge.common/test/io/openems/edge/common/taskmanager/TasksManagerTest.java b/io.openems.edge.common/test/io/openems/edge/common/taskmanager/TasksManagerTest.java new file mode 100644 index 00000000000..79dd4c8f000 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/taskmanager/TasksManagerTest.java @@ -0,0 +1,74 @@ +package io.openems.edge.common.taskmanager; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.common.taskmanager.TaskManager; + +public class TasksManagerTest { + + private class Task implements ManagedTask { + + private final Priority priority; + + public Task(Priority priority) { + this.priority = priority; + } + + @Override + public Priority getPriority() { + return this.priority; + } + + } + + @Test + public void testNextReadTasks() { + ManagedTask o1 = new Task(Priority.ONCE); + ManagedTask o2 = new Task(Priority.ONCE); + ManagedTask l1 = new Task(Priority.LOW); + ManagedTask l2 = new Task(Priority.LOW); + ManagedTask l3 = new Task(Priority.LOW); + ManagedTask h1 = new Task(Priority.HIGH); + ManagedTask h2 = new Task(Priority.HIGH); + ManagedTask h3 = new Task(Priority.HIGH); + + TaskManager m = new TaskManager(o1, o2, l1, l2, l3, h1, h2, h3); + + List t1 = m.getNextReadTasks(); + assertEquals(5, t1.size()); + assertTrue(t1.contains(h1)); + assertTrue(t1.contains(h2)); + assertTrue(t1.contains(h3)); + assertTrue(t1.contains(o1)); + assertTrue(t1.contains(l1)); + + List t2 = m.getNextReadTasks(); + assertEquals(5, t2.size()); + assertTrue(t2.contains(h1)); + assertTrue(t2.contains(h2)); + assertTrue(t2.contains(h3)); + assertTrue(t2.contains(o2)); + assertTrue(t2.contains(l2)); + + List t3 = m.getNextReadTasks(); + assertEquals(4, t3.size()); + assertTrue(t3.contains(h1)); + assertTrue(t3.contains(h2)); + assertTrue(t3.contains(h3)); + assertTrue(t3.contains(l3)); + + List t4 = m.getNextReadTasks(); + assertEquals(4, t4.size()); + assertTrue(t4.contains(h1)); + assertTrue(t4.contains(h2)); + assertTrue(t4.contains(h3)); + assertTrue(t4.contains(l1)); + + } + +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractCycleWorkerTest.java b/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractCycleWorkerTest.java new file mode 100644 index 00000000000..13d43ca7bf2 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractCycleWorkerTest.java @@ -0,0 +1,38 @@ +package io.openems.edge.common.worker; + +import static org.junit.Assert.*; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +public class AbstractCycleWorkerTest { + + @Test + public void testCycle() throws InterruptedException { + + final AtomicInteger counter = new AtomicInteger(0); + + AbstractCycleWorker worker = new AbstractCycleWorker() { + + @Override + protected void forever() { + counter.incrementAndGet(); + } + }; + + worker.activate("test"); + + Thread.sleep(100); + + worker.triggerNextCycle(); + + Thread.sleep(100); + + worker.triggerNextCycle(); + + assertEquals(3, counter.get()); + + worker.deactivate(); + } +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractImmediateWorkerTest.java b/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractImmediateWorkerTest.java new file mode 100644 index 00000000000..ad70ebf3426 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractImmediateWorkerTest.java @@ -0,0 +1,37 @@ +package io.openems.edge.common.worker; + +import static org.junit.Assert.*; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +public class AbstractImmediateWorkerTest { + + @Test + public void testImmediate() throws InterruptedException { + + final AtomicInteger counter = new AtomicInteger(0); + + AbstractImmediateWorker worker = new AbstractImmediateWorker() { + + @Override + protected void forever() { + counter.incrementAndGet(); + try { + Thread.sleep(10); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + } + }; + + worker.activate("test"); + + Thread.sleep(101); + + assertTrue(counter.get() > 9); + + worker.deactivate(); + } +} diff --git a/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractWorkerTest.java b/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractWorkerTest.java new file mode 100644 index 00000000000..bd683dfeca1 --- /dev/null +++ b/io.openems.edge.common/test/io/openems/edge/common/worker/AbstractWorkerTest.java @@ -0,0 +1,105 @@ +package io.openems.edge.common.worker; + +import static org.junit.Assert.*; + +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Test; + +public class AbstractWorkerTest { + + @Test + public void testDefinedCycleTime() throws InterruptedException { + + final AtomicInteger counter = new AtomicInteger(0); + + AbstractWorker worker = new AbstractWorker() { + + @Override + protected int getCycleTime() { + return 100; + } + + @Override + protected void forever() { + counter.incrementAndGet(); + } + }; + + worker.activate("test"); + + Thread.sleep(450); + + assertEquals(5, counter.get()); + + worker.deactivate(); + } + + @Test + public void testTriggerForceRun() throws InterruptedException { + + final AtomicInteger counter = new AtomicInteger(0); + + AbstractWorker worker = new AbstractWorker() { + + @Override + protected int getCycleTime() { + return 0; + } + + @Override + protected void forever() { + counter.incrementAndGet(); + } + }; + + worker.activate("test"); + + Thread.sleep(100); + + worker.triggerForceRun(); + + Thread.sleep(100); + + worker.triggerForceRun(); + + Thread.sleep(100); + + assertEquals(3, counter.get()); + + worker.deactivate(); + } + + @Test + public void testCombined() throws InterruptedException { + + final AtomicInteger counter = new AtomicInteger(0); + + AbstractWorker worker = new AbstractWorker() { + + @Override + protected int getCycleTime() { + return 100; + } + + @Override + protected void forever() { + counter.incrementAndGet(); + } + }; + + worker.activate("test"); + + Thread.sleep(120); + + worker.triggerForceRun(); + + Thread.sleep(20); + + assertEquals(3, counter.get()); + + worker.deactivate(); + } + + +} diff --git a/io.openems.edge.controller.api.backend/bnd.bnd b/io.openems.edge.controller.api.backend/bnd.bnd index 9fc75ee2bc5..3b5576cb219 100644 --- a/io.openems.edge.controller.api.backend/bnd.bnd +++ b/io.openems.edge.controller.api.backend/bnd.bnd @@ -3,8 +3,7 @@ Bundle-Vendor: FENECON GmbH Bundle-License: https://opensource.org/licenses/EPL-2.0 Bundle-Version: 1.0.0.${tstamp} Private-Package: \ - io.openems.edge.controller.api.backend,\ - io.openems.edge.controller.api.apicontrollerutils + io.openems.edge.controller.api.backend -includeresource: {readme.md} @@ -17,7 +16,8 @@ Private-Package: \ com.google.guava,\ io.openems.edge.timedata.api;version=latest,\ io.openems.common;version=latest,\ - org.ops4j.pax.logging.pax-logging-api + org.ops4j.pax.logging.pax-logging-api,\ + io.openems.edge.controller.api.core;version=latest -testpath: \ osgi.enroute.junit.wrapper;version=4.12, \ diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApi.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApi.java index c2ead3a3485..a417b3fdd8d 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApi.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApi.java @@ -29,8 +29,8 @@ import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.controller.api.Controller; -import io.openems.edge.controller.api.apicontrollerutils.ApiController; -import io.openems.edge.controller.api.apicontrollerutils.ApiWorker; +import io.openems.edge.controller.api.core.ApiController; +import io.openems.edge.controller.api.core.ApiWorker; import io.openems.edge.timedata.api.Timedata; @Designate(ocd = Config.class, factory = true) diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/MyWebSocketClient.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/MyWebSocketClient.java index 50c11e8e2aa..3a3d0637f97 100644 --- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/MyWebSocketClient.java +++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/MyWebSocketClient.java @@ -24,8 +24,8 @@ import io.openems.common.exceptions.OpenemsException; import io.openems.common.websocket.WebSocketUtils; -import io.openems.edge.controller.api.apicontrollerutils.ApiController; -import io.openems.edge.controller.api.apicontrollerutils.EdgeWebsocketHandler; +import io.openems.edge.controller.api.core.ApiController; +import io.openems.edge.controller.api.core.EdgeWebsocketHandler; /** * Local implementation of WebSocketClient to catch events diff --git a/io.openems.edge.controller.api.backend/test/.gitignore b/io.openems.edge.controller.api.backend/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.api.core/.classpath b/io.openems.edge.controller.api.core/.classpath new file mode 100644 index 00000000000..26009f42341 --- /dev/null +++ b/io.openems.edge.controller.api.core/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.controller.api.core/.gitignore b/io.openems.edge.controller.api.core/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.controller.api.core/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.controller.api.core/bnd.bnd b/io.openems.edge.controller.api.core/bnd.bnd new file mode 100644 index 00000000000..bc73065ad41 --- /dev/null +++ b/io.openems.edge.controller.api.core/bnd.bnd @@ -0,0 +1,22 @@ +Bundle-Name: OpenEMS Edge Controller API Core +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.controller.api.core + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.timedata.api;version=latest,\ + io.openems.edge.controller.api;version=latest,\ + io.openems.common;version=latest,\ + io.openems.wrapper.websocket;version=latest,\ + com.google.gson,\ + io.openems.edge.common;version=latest,\ + org.ops4j.pax.logging.pax-logging-api + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 diff --git a/io.openems.edge.controller.api.core/debug.bndrun b/io.openems.edge.controller.api.core/debug.bndrun new file mode 100644 index 00000000000..03edeaabc4d --- /dev/null +++ b/io.openems.edge.controller.api.core/debug.bndrun @@ -0,0 +1,13 @@ +# +# io.openems.edge.controller.api.core DEBUG LAUNCH SPECFICATION +# + +-include: ~io.openems.edge.controller.api.core.bndrun + +-runrequires.debug: \ + ${debug-bundles} + +-runtrace: true + +-runbundles: \ + ${error;Resolve first} diff --git a/io.openems.edge.controller.api.core/io.openems.edge.controller.api.core.bndrun b/io.openems.edge.controller.api.core/io.openems.edge.controller.api.core.bndrun new file mode 100644 index 00000000000..0a603646236 --- /dev/null +++ b/io.openems.edge.controller.api.core/io.openems.edge.controller.api.core.bndrun @@ -0,0 +1,14 @@ +# +# io.openems.edge.controller.api.core LAUNCH SPECIFICATION +# + + +Bundle-Version: 1.0.0.${tstamp} +Bundle-SymbolicName: io.openems.edge.controller.api.core.launch +JPM-Command: provider + + +-runrequires: \ + osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.api.core.provider)' + +-runbundles: ${error;You must first resolve this bndrun file before you can run it} diff --git a/io.openems.edge.controller.api.core/readme.md b/io.openems.edge.controller.api.core/readme.md new file mode 100644 index 00000000000..65102017054 --- /dev/null +++ b/io.openems.edge.controller.api.core/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.controller.api.core Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/ApiController.java b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/ApiController.java similarity index 87% rename from io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/ApiController.java rename to io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/ApiController.java index 0140af98f1a..30c4327e2f9 100644 --- a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/ApiController.java +++ b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/ApiController.java @@ -1,4 +1,4 @@ -package io.openems.edge.controller.api.apicontrollerutils; +package io.openems.edge.controller.api.core; import java.util.List; diff --git a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/ApiWorker.java b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/ApiWorker.java similarity index 98% rename from io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/ApiWorker.java rename to io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/ApiWorker.java index 7eb892c08bd..9290e58bd9a 100644 --- a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/ApiWorker.java +++ b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/ApiWorker.java @@ -1,4 +1,4 @@ -package io.openems.edge.controller.api.apicontrollerutils; +package io.openems.edge.controller.api.core; import java.util.HashMap; import java.util.Map; diff --git a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/EdgeCurrentDataWorker.java b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/EdgeCurrentDataWorker.java similarity index 97% rename from io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/EdgeCurrentDataWorker.java rename to io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/EdgeCurrentDataWorker.java index d3f1f8e1fdd..5113b304ffa 100644 --- a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/EdgeCurrentDataWorker.java +++ b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/EdgeCurrentDataWorker.java @@ -1,4 +1,4 @@ -package io.openems.edge.controller.api.apicontrollerutils; +package io.openems.edge.controller.api.core; import org.java_websocket.WebSocket; diff --git a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/EdgeWebsocketHandler.java b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/EdgeWebsocketHandler.java similarity index 98% rename from io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/EdgeWebsocketHandler.java rename to io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/EdgeWebsocketHandler.java index 39f975cba82..bcc298ee602 100644 --- a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/EdgeWebsocketHandler.java +++ b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/EdgeWebsocketHandler.java @@ -1,4 +1,4 @@ -package io.openems.edge.controller.api.apicontrollerutils; +package io.openems.edge.controller.api.core; import java.io.IOException; import java.util.HashMap; @@ -12,12 +12,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.gson.JsonArray; import com.google.gson.JsonObject; import io.openems.common.exceptions.AccessDeniedException; import io.openems.common.exceptions.OpenemsException; import io.openems.common.session.Role; +import io.openems.common.timedata.TimedataUtils; import io.openems.common.utils.JsonUtils; import io.openems.common.websocket.DefaultMessages; import io.openems.common.websocket.LogBehaviour; @@ -173,8 +173,8 @@ private void historicData(JsonObject jMessageId, JsonObject jHistoricData) { return; } try { - JsonArray jData = timedataService.queryHistoricData(jHistoricData); - WebSocketUtils.send(this.websocket, DefaultMessages.historicDataQueryReply(jMessageId, jData)); + JsonObject j = TimedataUtils.handle(timedataService, jMessageId, jHistoricData); + WebSocketUtils.send(this.websocket, j); } catch (OpenemsException e) { WebSocketUtils.sendNotificationOrLogError(this.websocket, jMessageId, LogBehaviour.WRITE_TO_LOG, Notification.UNABLE_TO_QUERY_HISTORIC_DATA, e.getMessage()); diff --git a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/Utils.java b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/Utils.java similarity index 98% rename from io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/Utils.java rename to io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/Utils.java index 268dbc573c3..c9d58ebf2cf 100644 --- a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/Utils.java +++ b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/Utils.java @@ -1,4 +1,4 @@ -package io.openems.edge.controller.api.apicontrollerutils; +package io.openems.edge.controller.api.core; import java.util.Arrays; import java.util.Collections; diff --git a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/WriteObject.java b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/WriteObject.java similarity index 97% rename from io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/WriteObject.java rename to io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/WriteObject.java index 7d61c1c80b6..c5c88dcea60 100644 --- a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/WriteObject.java +++ b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/WriteObject.java @@ -1,4 +1,4 @@ -package io.openems.edge.controller.api.apicontrollerutils; +package io.openems.edge.controller.api.core; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; diff --git a/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/package-info.java b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/package-info.java new file mode 100644 index 00000000000..37e94c2a412 --- /dev/null +++ b/io.openems.edge.controller.api.core/src/io/openems/edge/controller/api/core/package-info.java @@ -0,0 +1,2 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +package io.openems.edge.controller.api.core; diff --git a/io.openems.edge.controller.api.core/test/.gitignore b/io.openems.edge.controller.api.core/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.api.websocket/bnd.bnd b/io.openems.edge.controller.api.websocket/bnd.bnd index 71eb58bcf51..7844fe0e7ac 100644 --- a/io.openems.edge.controller.api.websocket/bnd.bnd +++ b/io.openems.edge.controller.api.websocket/bnd.bnd @@ -16,7 +16,8 @@ Private-Package: \ io.openems.wrapper.websocket;version=latest,\ com.google.gson,\ io.openems.edge.timedata.api;version=latest,\ - org.ops4j.pax.logging.pax-logging-api + org.ops4j.pax.logging.pax-logging-api,\ + io.openems.edge.controller.api.core;version=latest -testpath: \ osgi.enroute.junit.wrapper;version=4.12, \ diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/UiEdgeWebsocketHandler.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/UiEdgeWebsocketHandler.java index 659da1a109e..c780ae27d71 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/UiEdgeWebsocketHandler.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/UiEdgeWebsocketHandler.java @@ -7,8 +7,8 @@ import io.openems.common.session.Role; import io.openems.edge.common.user.User; -import io.openems.edge.controller.api.apicontrollerutils.ApiController; -import io.openems.edge.controller.api.apicontrollerutils.EdgeWebsocketHandler; +import io.openems.edge.controller.api.core.ApiController; +import io.openems.edge.controller.api.core.EdgeWebsocketHandler; public class UiEdgeWebsocketHandler extends EdgeWebsocketHandler { diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketApi.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketApi.java index 33890bda25a..f1b6d142a19 100644 --- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketApi.java +++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketApi.java @@ -24,8 +24,8 @@ import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.user.UserService; import io.openems.edge.controller.api.Controller; -import io.openems.edge.controller.api.apicontrollerutils.ApiController; -import io.openems.edge.controller.api.apicontrollerutils.ApiWorker; +import io.openems.edge.controller.api.core.ApiController; +import io.openems.edge.controller.api.core.ApiWorker; import io.openems.edge.timedata.api.Timedata; @Designate(ocd = Config.class, factory = true) diff --git a/io.openems.edge.controller.api.websocket/test/.gitignore b/io.openems.edge.controller.api.websocket/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.api/bnd.bnd b/io.openems.edge.controller.api/bnd.bnd index e3f5c220888..8a0e17623b9 100644 --- a/io.openems.edge.controller.api/bnd.bnd +++ b/io.openems.edge.controller.api/bnd.bnd @@ -3,21 +3,16 @@ Bundle-Vendor: FENECON GmbH Bundle-License: https://opensource.org/licenses/EPL-2.0 Bundle-Version: 1.0.0.${tstamp} Export-Package: \ - io.openems.edge.controller.api,\ - io.openems.edge.controller.api.apicontrollerutils -#Require-Capability: \ -# compile-only + io.openems.edge.controller.api +Require-Capability: \ + compile-only -includeresource: {readme.md} -buildpath: \ osgi.enroute.base.api;version=2.1,\ - com.google.gson,\ io.openems.common;version=latest,\ - io.openems.edge.common;version=latest,\ - io.openems.edge.timedata.api;version=latest,\ - io.openems.wrapper.websocket;version=latest,\ - org.ops4j.pax.logging.pax-logging-api + io.openems.edge.common;version=latest -testpath: \ osgi.enroute.junit.wrapper;version=4.12, \ diff --git a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/package-info.java b/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/package-info.java deleted file mode 100644 index fd971201b32..00000000000 --- a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/apicontrollerutils/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -@org.osgi.annotation.versioning.Version("1.0.0") -package io.openems.edge.controller.api.apicontrollerutils; diff --git a/io.openems.edge.controller.channelthreshold/test/.gitignore b/io.openems.edge.controller.channelthreshold/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.debug.detailedlog/src/io/openems/edge/controller/debug/detailedlog/DebugDetailedLog.java b/io.openems.edge.controller.debug.detailedlog/src/io/openems/edge/controller/debug/detailedlog/DebugDetailedLog.java index c5e9a827731..288190fc777 100644 --- a/io.openems.edge.controller.debug.detailedlog/src/io/openems/edge/controller/debug/detailedlog/DebugDetailedLog.java +++ b/io.openems.edge.controller.debug.detailedlog/src/io/openems/edge/controller/debug/detailedlog/DebugDetailedLog.java @@ -26,6 +26,8 @@ import com.google.common.collect.Multimap; import io.openems.common.types.ChannelAddress; +import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.controller.api.Controller; @@ -106,8 +108,30 @@ public void run() { .sorted((c1, c2) -> c1.channelId().name().compareTo(c2.channelId().name())) // .forEach(channel -> { String unit = channel.channelDoc().getUnit().getSymbol(); - String line = String.format("%-" + WIDTH_FIRST + "s : %15s %s", channel.channelId().id(), - channel.value().asStringWithoutUnit(), unit); + /* + * create descriptive text + */ + String description = ""; + if (channel.channelDoc().hasOptions()) { + description += channel.value().asOptionString(); + } + if (channel instanceof StateChannel && ((StateChannel) channel).value().orElse(false) == true) { + if(!description.isEmpty()) { + description += "; "; + } + description += ((StateChannel) channel).channelDoc().getText(); + } + if (channel instanceof StateCollectorChannel + && ((StateCollectorChannel) channel).value().orElse(0) != 0) { + if(!description.isEmpty()) { + description += "; "; + } + description += ((StateCollectorChannel) channel).listStates(); + } + // Build complete line + String line = String.format("%-" + WIDTH_FIRST + "s : %15s %-3s %s", channel.channelId().id(), + channel.value().asStringWithoutUnit(), unit, + description.isEmpty() ? "" : "(" + description + ")"); // Print the line only if is not equal to the last printed line if ((!this.lastPrinted.containsKey(channel.address())) || !(this.lastPrinted.get(channel.address()).equals(line))) { diff --git a/io.openems.edge.controller.debug.detailedlog/test/.gitignore b/io.openems.edge.controller.debug.detailedlog/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/DebugLog.java b/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/DebugLog.java index ad861bb691c..5faf25f80d4 100644 --- a/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/DebugLog.java +++ b/io.openems.edge.controller.debug.log/src/io/openems/edge/controller/debuglog/DebugLog.java @@ -63,13 +63,16 @@ public void run() { * Asks each component for its debugLog()-ChannelIds. Prints an aggregated log * of those channelIds and their current values. */ - this._components.stream().forEach(component -> { - String debugLog = component.debugLog(); - if (debugLog != null) { - b.append(component.id()); - b.append("[" + debugLog + "] "); - } - }); + this._components.stream() // + .filter(c -> c.isEnabled()) // enabled components only + .sorted((c1, c2) -> c1.id().compareTo(c2.id())) // sorted by Component-ID + .forEachOrdered(component -> { + String debugLog = component.debugLog(); + if (debugLog != null) { + b.append(component.id()); + b.append("[" + debugLog + "] "); + } + }); logInfo(this.log, b.toString()); } } diff --git a/io.openems.edge.controller.symmetric.balancing/src/io/openems/edge/controller/symmetric/balancing/Balancing.java b/io.openems.edge.controller.symmetric.balancing/src/io/openems/edge/controller/symmetric/balancing/Balancing.java index f243f57c7dc..11a63c87079 100644 --- a/io.openems.edge.controller.symmetric.balancing/src/io/openems/edge/controller/symmetric/balancing/Balancing.java +++ b/io.openems.edge.controller.symmetric.balancing/src/io/openems/edge/controller/symmetric/balancing/Balancing.java @@ -1,5 +1,6 @@ package io.openems.edge.controller.symmetric.balancing; +import org.apache.commons.math3.optim.linear.Relationship; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -18,12 +19,14 @@ import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.controller.api.Controller; -import io.openems.edge.ess.api.Ess; -import io.openems.edge.ess.power.PowerException; -import io.openems.edge.ess.power.symmetric.PEqualLimitation; -import io.openems.edge.ess.power.symmetric.SymmetricPower; -import io.openems.edge.ess.symmetric.api.SymmetricEss; -import io.openems.edge.meter.symmetric.api.SymmetricMeter; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.power.api.PowerException; +import io.openems.edge.ess.power.api.Pwr; +import io.openems.edge.meter.api.SymmetricMeter; @Designate(ocd = Config.class, factory = true) @Component(name = "Controller.Symmetric.Balancing", immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE) @@ -48,7 +51,7 @@ void activate(ComponentContext context, Config config) { } @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) - private SymmetricEss ess; + private ManagedSymmetricEss ess; @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) private SymmetricMeter meter; @@ -70,15 +73,13 @@ private int calculateRequiredPower() throws InvalidValueException, NullPointerEx @Override public void run() { - // TODO improvement: calculate required power with SoC in mind. On high SoC - // prefer feeding-to-grid a little bit (<100 W) than buying; on low SoC inverse int requiredPower; try { /* * Check that we are On-Grid */ Enum gridMode = this.ess.getGridMode().value().asEnum(); - if (gridMode != Ess.GridMode.ON_GRID) { + if (gridMode != SymmetricEss.GridMode.ON_GRID) { return; } @@ -88,17 +89,18 @@ public void run() { requiredPower = this.calculateRequiredPower(); } catch (InvalidValueException | NullPointerException e) { - logError(this.log, e.getMessage()); + logError(this.log, + "Error while calculating required power. " + e.getClass().getSimpleName() + ": " + e.getMessage()); return; } - SymmetricPower power = ess.getPower(); + Power power = ess.getPower(); if (requiredPower > 0) { /* * Discharge */ // fit into max possible discharge power - int maxDischargePower = power.getMaxP().orElse(0); + int maxDischargePower = power.getMaxActivePower(); if (requiredPower > maxDischargePower) { requiredPower = maxDischargePower; } @@ -108,7 +110,7 @@ public void run() { * Charge */ // fit into max possible discharge power - int maxChargePower = power.getMinP().orElse(0); + int maxChargePower = power.getMinActivePower(); if (requiredPower < maxChargePower) { requiredPower = maxChargePower; } @@ -118,7 +120,9 @@ public void run() { * set result */ try { - power.applyLimitation(new PEqualLimitation(power).setP(requiredPower)); + this.ess.addPowerConstraintAndValidate(ConstraintType.CYCLE, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, + requiredPower); + this.ess.addPowerConstraintAndValidate(ConstraintType.CYCLE, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, 0); } catch (PowerException e) { logError(this.log, "Unable to set Power: " + e.getMessage()); } diff --git a/io.openems.edge.controller.symmetric.balancing/test/.gitignore b/io.openems.edge.controller.symmetric.balancing/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.symmetric.fixactivepower/src/io/openems/edge/controller/symmetric/fixactivepower/SymmetricFixActivePower.java b/io.openems.edge.controller.symmetric.fixactivepower/src/io/openems/edge/controller/symmetric/fixactivepower/SymmetricFixActivePower.java index b8070153136..7e137b7d21b 100644 --- a/io.openems.edge.controller.symmetric.fixactivepower/src/io/openems/edge/controller/symmetric/fixactivepower/SymmetricFixActivePower.java +++ b/io.openems.edge.controller.symmetric.fixactivepower/src/io/openems/edge/controller/symmetric/fixactivepower/SymmetricFixActivePower.java @@ -1,5 +1,6 @@ package io.openems.edge.controller.symmetric.fixactivepower; +import org.apache.commons.math3.optim.linear.Relationship; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -14,13 +15,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.openems.common.exceptions.OpenemsException; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.controller.api.Controller; -import io.openems.edge.ess.power.symmetric.PEqualLimitation; -import io.openems.edge.ess.power.symmetric.SymmetricPower; -import io.openems.edge.ess.symmetric.api.SymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.PowerException; +import io.openems.edge.ess.power.api.Pwr; @Designate(ocd = Config.class, factory = true) @Component(name = "Controller.Symmetric.FixActivePower", immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE) @@ -50,7 +52,7 @@ void activate(ComponentContext context, Config config) { } @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) - private SymmetricEss ess; + private ManagedSymmetricEss ess; @Deactivate protected void deactivate() { @@ -60,9 +62,9 @@ protected void deactivate() { @Override public void run() { try { - SymmetricPower power = ess.getPower(); - power.applyLimitation(new PEqualLimitation(power).setP(this.power)); - } catch (OpenemsException e) { + this.ess.addPowerConstraintAndValidate(ConstraintType.CYCLE, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, + this.power); + } catch (PowerException e) { logError(log, e.getMessage()); } } diff --git a/io.openems.edge.controller.symmetric.fixactivepower/test/.gitignore b/io.openems.edge.controller.symmetric.fixactivepower/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/.classpath b/io.openems.edge.controller.symmetric.fixreactivepower/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.controller.symmetric.fixreactivepower/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.bridge.modbus.impl/.gitignore b/io.openems.edge.controller.symmetric.fixreactivepower/.gitignore similarity index 62% rename from io.openems.bridge.modbus.impl/.gitignore rename to io.openems.edge.controller.symmetric.fixreactivepower/.gitignore index 57b341172a1..90dde36e4ac 100644 --- a/io.openems.bridge.modbus.impl/.gitignore +++ b/io.openems.edge.controller.symmetric.fixreactivepower/.gitignore @@ -1,2 +1,3 @@ /bin/ +/bin_test/ /generated/ diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/bnd.bnd b/io.openems.edge.controller.symmetric.fixreactivepower/bnd.bnd new file mode 100644 index 00000000000..8119b6204fb --- /dev/null +++ b/io.openems.edge.controller.symmetric.fixreactivepower/bnd.bnd @@ -0,0 +1,20 @@ +Bundle-Name: OpenEMS Edge Controller Symmetric Fix-ReactivePower +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: io.openems.edge.controller.api + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.controller.api;version=latest,\ + io.openems.edge.ess.api;version=latest,\ + io.openems.edge.common;version=latest,\ + io.openems.common;version=latest + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 + +Private-Package: io.openems.edge.controller.symmetric.fixreactivepower \ No newline at end of file diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/debug.bndrun b/io.openems.edge.controller.symmetric.fixreactivepower/debug.bndrun new file mode 100644 index 00000000000..5466801674b --- /dev/null +++ b/io.openems.edge.controller.symmetric.fixreactivepower/debug.bndrun @@ -0,0 +1,13 @@ +# +# io.openems.edge.controller.symmetric.fixvalue DEBUG LAUNCH SPECFICATION +# + +-include: ~io.openems.edge.controller.symmetric.fixvalue.bndrun + +-runrequires.debug: \ + ${debug-bundles} + +-runtrace: true + +-runbundles: \ + ${error;Resolve first} diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/io.openems.edge.controller.symmetric.fixactivepower.bndrun b/io.openems.edge.controller.symmetric.fixreactivepower/io.openems.edge.controller.symmetric.fixactivepower.bndrun new file mode 100644 index 00000000000..a17062f2519 --- /dev/null +++ b/io.openems.edge.controller.symmetric.fixreactivepower/io.openems.edge.controller.symmetric.fixactivepower.bndrun @@ -0,0 +1,14 @@ +# +# io.openems.edge.controller.symmetric.fixvalue LAUNCH SPECIFICATION +# + + +Bundle-Version: 1.0.0.${tstamp} +Bundle-SymbolicName: io.openems.edge.controller.symmetric.fixvalue.launch +JPM-Command: provider + + +-runrequires: \ + osgi.identity;filter:='(osgi.identity=io.openems.edge.controller.symmetric.fixvalue.provider)' + +-runbundles: ${error;You must first resolve this bndrun file before you can run it} diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/readme.md b/io.openems.edge.controller.symmetric.fixreactivepower/readme.md new file mode 100644 index 00000000000..b707f300e72 --- /dev/null +++ b/io.openems.edge.controller.symmetric.fixreactivepower/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.controller.symmetric.fixvalue Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/src/io/openems/edge/controller/symmetric/fixreactivepower/Config.java b/io.openems.edge.controller.symmetric.fixreactivepower/src/io/openems/edge/controller/symmetric/fixreactivepower/Config.java new file mode 100644 index 00000000000..26dba9ba3c3 --- /dev/null +++ b/io.openems.edge.controller.symmetric.fixreactivepower/src/io/openems/edge/controller/symmetric/fixreactivepower/Config.java @@ -0,0 +1,26 @@ +package io.openems.edge.controller.symmetric.fixreactivepower; + +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.osgi.service.metatype.annotations.AttributeDefinition;; + +@ObjectClassDefinition( // + name = "Controller Fix Reactive Power Symmetric", // + description = "Defines a fixed reactive power to a symmetric energy storage system.") +@interface Config { + String service_pid(); + + String id() default "ctrlFixReactivePower0"; + + boolean enabled() default true; + + @AttributeDefinition(name = "Ess-ID", description = "ID of Ess device.") + String ess_id(); + + @AttributeDefinition(name = "Charge/Discharge power [W]", description = "Negative values for Charge; positive for Discharge") + int power(); + + @AttributeDefinition(name = "Ess target filter", description = "This is auto-generated by 'Ess-ID'.") + String ess_target() default ""; + + String webconsole_configurationFactory_nameHint() default "Controller Fix Reactive Power Symmetric [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/src/io/openems/edge/controller/symmetric/fixreactivepower/SymmetricFixReactivePower.java b/io.openems.edge.controller.symmetric.fixreactivepower/src/io/openems/edge/controller/symmetric/fixreactivepower/SymmetricFixReactivePower.java new file mode 100644 index 00000000000..e2759092bc3 --- /dev/null +++ b/io.openems.edge.controller.symmetric.fixreactivepower/src/io/openems/edge/controller/symmetric/fixreactivepower/SymmetricFixReactivePower.java @@ -0,0 +1,71 @@ +package io.openems.edge.controller.symmetric.fixreactivepower; + +import org.apache.commons.math3.optim.linear.Relationship; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.controller.api.Controller; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.PowerException; +import io.openems.edge.ess.power.api.Pwr; + +@Designate(ocd = Config.class, factory = true) +@Component(name = "Controller.Symmetric.FixReactivePower", immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE) +public class SymmetricFixReactivePower extends AbstractOpenemsComponent implements Controller, OpenemsComponent { + + private final Logger log = LoggerFactory.getLogger(SymmetricFixReactivePower.class); + + @Reference + protected ConfigurationAdmin cm; + + /** + * the configured Charge ActivePower + * + * negative values for Charge; positive for Discharge + */ + private int power = 0; + + @Activate + void activate(ComponentContext context, Config config) { + super.activate(context, config.service_pid(), config.id(), config.enabled()); + // update filter for 'ess' + if (OpenemsComponent.updateReferenceFilter(cm, config.service_pid(), "ess", config.ess_id())) { + return; + } + + this.power = config.power(); + } + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + private ManagedSymmetricEss ess; + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + public void run() { + try { + this.ess.addPowerConstraintAndValidate(ConstraintType.CYCLE, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, + this.power); + } catch (PowerException e) { + logError(log, e.getMessage()); + } + } +} diff --git a/io.openems.edge.controller.symmetric.fixreactivepower/test/.gitignore b/io.openems.edge.controller.symmetric.fixreactivepower/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.core/.classpath b/io.openems.edge.core/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.core/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.core/bnd.bnd b/io.openems.edge.core/bnd.bnd index ca57e340223..b30ba7af533 100644 --- a/io.openems.edge.core/bnd.bnd +++ b/io.openems.edge.core/bnd.bnd @@ -5,8 +5,7 @@ Bundle-Version: 1.0.0.${tstamp} Private-Package: \ io.openems.edge.core.meta,\ io.openems.edge.core.sum,\ - io.openems.edge.core.sum.internal,\ - io.openems.edge.cycle + io.openems.edge.core.cycle -buildpath: \ osgi.enroute.base.api;version=2.1,\ @@ -16,4 +15,4 @@ Private-Package: \ io.openems.edge.meter.api;version=latest,\ io.openems.wrapper.sdnotify;version=latest,\ io.openems.edge.scheduler.api;version=latest,\ - io.openems.edge.controller.api;version=latest \ No newline at end of file + io.openems.edge.controller.api;version=latest diff --git a/io.openems.edge.core/src/io/openems/edge/cycle/Cycle.java b/io.openems.edge.core/src/io/openems/edge/core/cycle/Cycle.java similarity index 98% rename from io.openems.edge.core/src/io/openems/edge/cycle/Cycle.java rename to io.openems.edge.core/src/io/openems/edge/core/cycle/Cycle.java index fa8135c25db..786f0839420 100644 --- a/io.openems.edge.core/src/io/openems/edge/cycle/Cycle.java +++ b/io.openems.edge.core/src/io/openems/edge/core/cycle/Cycle.java @@ -1,4 +1,4 @@ -package io.openems.edge.cycle; +package io.openems.edge.core.cycle; import java.util.HashMap; import java.util.List; @@ -69,7 +69,7 @@ protected void activate() { } @Deactivate - protected void deactivate() { + public void deactivate() { super.deactivate(); } diff --git a/io.openems.edge.core/src/io/openems/edge/cycle/Utils.java b/io.openems.edge.core/src/io/openems/edge/core/cycle/Utils.java similarity index 98% rename from io.openems.edge.core/src/io/openems/edge/cycle/Utils.java rename to io.openems.edge.core/src/io/openems/edge/core/cycle/Utils.java index 38236f613c1..126f1e7db63 100644 --- a/io.openems.edge.core/src/io/openems/edge/cycle/Utils.java +++ b/io.openems.edge.core/src/io/openems/edge/core/cycle/Utils.java @@ -1,4 +1,4 @@ -package io.openems.edge.cycle; +package io.openems.edge.core.cycle; import java.util.Optional; import java.util.TreeMap; diff --git a/io.openems.edge.core/src/io/openems/edge/core/meta/Utils.java b/io.openems.edge.core/src/io/openems/edge/core/meta/Utils.java index dea7ac22336..e9f83c2e2d8 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/meta/Utils.java +++ b/io.openems.edge.core/src/io/openems/edge/core/meta/Utils.java @@ -5,7 +5,7 @@ import io.openems.common.OpenemsConstants; import io.openems.edge.common.channel.AbstractReadChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.channel.StringReadChannel; import io.openems.edge.common.component.OpenemsComponent; @@ -15,7 +15,7 @@ public static Stream> initializeChannels(Meta c Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; }), Arrays.stream(Meta.ChannelId.values()).map(channelId -> { diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/Sum.java b/io.openems.edge.core/src/io/openems/edge/core/sum/Sum.java index 7c51f615f82..871f49d9e92 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/Sum.java +++ b/io.openems.edge.core/src/io/openems/edge/core/sum/Sum.java @@ -18,16 +18,17 @@ import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.common.channel.merger.AverageInteger; +import io.openems.edge.common.channel.merger.ChannelMergerSumInteger; +import io.openems.edge.common.channel.merger.SumInteger; import io.openems.edge.common.channel.value.Value; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.core.sum.internal.AverageInteger; -import io.openems.edge.core.sum.internal.SumInteger; -import io.openems.edge.ess.api.Ess; -import io.openems.edge.ess.symmetric.api.SymmetricEss; -import io.openems.edge.ess.symmetric.readonly.api.SymmetricEssReadonly; -import io.openems.edge.meter.api.Meter; -import io.openems.edge.meter.symmetric.api.SymmetricMeter; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.MetaEss; +import io.openems.edge.ess.dccharger.api.EssDcCharger; +import io.openems.edge.meter.api.SymmetricMeter; /** * Enables access to sum/average data. @@ -60,7 +61,7 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { ESS_ACTIVE_POWER(new Doc() // .type(OpenemsType.INTEGER) // .unit(Unit.WATT) // - .text(SymmetricEss.POWER_DOC_TEXT)), + .text(ManagedSymmetricEss.POWER_DOC_TEXT)), /** * Grid: Active Power * @@ -107,7 +108,7 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { * Production: Active Power * *
        - *
      • Interface: Sum (origin: Meter Symmetric) + *
      • Interface: Sum (origin: Meter Symmetric and ESS DC Charger) *
      • Type: Integer *
      • Unit: W *
      • Range: should be only positive @@ -116,6 +117,32 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { PRODUCTION_ACTIVE_POWER(new Doc() // .type(OpenemsType.INTEGER) // .unit(Unit.WATT)), + /** + * Production: AC Active Power + * + *
          + *
        • Interface: Sum (origin: Meter Symmetric) + *
        • Type: Integer + *
        • Unit: W + *
        • Range: should be only positive + *
        + */ + PRODUCTION_AC_ACTIVE_POWER(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT)), + /** + * Production: DC Actual Power + * + *
          + *
        • Interface: Sum (origin: ESS DC Charger) + *
        • Type: Integer + *
        • Unit: W + *
        • Range: should be only positive + *
        + */ + PRODUCTION_DC_ACTUAL_POWER(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT)), /** * Production: Maximum Ever Active Power * @@ -129,6 +156,32 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { PRODUCTION_MAX_ACTIVE_POWER(new Doc() // .type(OpenemsType.INTEGER) // .unit(Unit.WATT)), + /** + * Production: Maximum Ever AC Active Power + * + *
          + *
        • Interface: Sum (origin: @see {@link SymmetricMeter})) + *
        • Type: Integer + *
        • Unit: W + *
        • Range: positive values or '0' + *
        + */ + PRODUCTION_MAX_AC_ACTIVE_POWER(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT)), + /** + * Production: Maximum Ever DC Actual Power + * + *
          + *
        • Interface: Sum (origin: @see {@link EssDcCharger})) + *
        • Type: Integer + *
        • Unit: W + *
        • Range: positive values or '0' + *
        + */ + PRODUCTION_MAX_DC_ACTUAL_POWER(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT)), /** * Consumption: Active Power * @@ -172,9 +225,9 @@ public Doc doc() { /* * Ess */ - private final List esss = new CopyOnWriteArrayList<>(); - private final AverageInteger essSoc; - private final SumInteger essActivePower; + private final List esss = new CopyOnWriteArrayList<>(); + private final AverageInteger essSoc; + private final SumInteger essActivePower; /* * Grid @@ -186,20 +239,28 @@ public Doc doc() { /* * Production */ - private final SumInteger productionActivePower; - private final SumInteger productionMaxActivePower; + private final SumInteger productionAcActivePower; + private final SumInteger productionMaxAcActivePower; + private final SumInteger productionDcActualPower; + private final SumInteger productionMaxDcActualPower; @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) - private void addEss(Ess ess) { + private void addEss(SymmetricEss ess) { + if (ess instanceof MetaEss) { + // ignore this Ess + return; + } this.esss.add(ess); this.essSoc.addComponent(ess); - if (ess instanceof SymmetricEssReadonly) { - this.essActivePower.addComponent((SymmetricEssReadonly) ess); - } + this.essActivePower.addComponent(ess); this.calculateMaxConsumption.accept(null /* ignored */); } - protected void removeEss(Ess ess) { + protected void removeEss(SymmetricEss ess) { + if (ess instanceof MetaEss) { + // ignore this Ess + return; + } this.esss.remove(ess); this.essSoc.removeComponent(ess); this.essActivePower.removeComponent(ess); @@ -207,7 +268,7 @@ protected void removeEss(Ess ess) { private final Consumer> calculateMaxConsumption = ignoreValue -> { int ess = 0; - for (Ess e : this.esss) { + for (SymmetricEss e : this.esss) { ess += e.getMaxActivePower().getNextValue().orElse(0); } int grid = this.getGridMaxActivePower().getNextValue().orElse(0); @@ -217,14 +278,18 @@ protected void removeEss(Ess ess) { }; @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) - private void addMeter(Meter meter) { + private void addMeter(SymmetricMeter meter) { switch (meter.getMeterType()) { + case PRODUCTION_AND_CONSUMPTION: + // TODO PRODUCTION_AND_CONSUMPTION + break; + case CONSUMPTION_METERED: - // TODO + // TODO CONSUMPTION_METERED break; case CONSUMPTION_NOT_METERED: - // TODO + // TODO CONSUMPTION_NOT_METERED break; case GRID: @@ -243,28 +308,41 @@ private void addMeter(Meter meter) { * Production-Meter */ if (meter instanceof SymmetricMeter) { - this.productionActivePower.addComponent((SymmetricMeter) meter); - this.productionMaxActivePower.addComponent((SymmetricMeter) meter); + this.productionAcActivePower.addComponent((SymmetricMeter) meter); + this.productionMaxAcActivePower.addComponent((SymmetricMeter) meter); } break; + } } - protected void removeMeter(Meter meter) { + protected void removeMeter(SymmetricMeter meter) { this.gridActivePower.removeComponent(meter); this.gridMinActivePower.removeComponent(meter); this.gridMaxActivePower.removeComponent(meter); - this.productionMaxActivePower.removeComponent(meter); + this.productionMaxAcActivePower.removeComponent(meter); + } + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) + private void addEssDcCharger(EssDcCharger charger) { + this.productionDcActualPower.addComponent(charger); + this.productionMaxDcActualPower.addComponent(charger); } + protected void removeEssDcCharger(EssDcCharger charger) { + this.productionDcActualPower.removeComponent(charger); + this.productionMaxDcActualPower.removeComponent(charger); + } + + @SuppressWarnings("unchecked") public Sum() { Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); /* * Ess */ - this.essSoc = new AverageInteger(this, ChannelId.ESS_SOC, Ess.ChannelId.SOC); - this.essActivePower = new SumInteger(this, ChannelId.ESS_ACTIVE_POWER, - SymmetricEssReadonly.ChannelId.ACTIVE_POWER); + this.essSoc = new AverageInteger(this, ChannelId.ESS_SOC, SymmetricEss.ChannelId.SOC); + this.essActivePower = new SumInteger(this, ChannelId.ESS_ACTIVE_POWER, + SymmetricEss.ChannelId.ACTIVE_POWER); /* * Grid */ @@ -277,10 +355,29 @@ public Sum() { /* * Production */ - this.productionActivePower = new SumInteger(this, ChannelId.PRODUCTION_ACTIVE_POWER, + this.productionAcActivePower = new SumInteger(this, ChannelId.PRODUCTION_AC_ACTIVE_POWER, SymmetricMeter.ChannelId.ACTIVE_POWER); - this.productionMaxActivePower = new SumInteger(this, ChannelId.PRODUCTION_MAX_ACTIVE_POWER, + this.productionDcActualPower = new SumInteger(this, ChannelId.PRODUCTION_DC_ACTUAL_POWER, + EssDcCharger.ChannelId.ACTUAL_POWER); + new ChannelMergerSumInteger( // + /* target */ this.getProductionActivePower(), // + /* sources */ (Channel[]) new Channel[] { // + this.getProductionAcActivePower(), // + this.getProductionDcActualPower() // + }); + // TODO Charger needs a 'MaxActualPower' as well. And it needs to be considered + // here. + this.productionMaxAcActivePower = new SumInteger(this, ChannelId.PRODUCTION_MAX_AC_ACTIVE_POWER, SymmetricMeter.ChannelId.MAX_ACTIVE_POWER); + this.productionMaxDcActualPower = new SumInteger(this, ChannelId.PRODUCTION_MAX_DC_ACTUAL_POWER, + EssDcCharger.ChannelId.MAX_ACTUAL_POWER); + new ChannelMergerSumInteger( // + /* target */ this.getProductionMaxActivePower(), // + /* sources */ (Channel[]) new Channel[] { // + this.getProductionMaxAcActivePower(), // + this.getProductionMaxDcActualPower() // + }); + /* * Consumption */ @@ -289,13 +386,13 @@ public Sum() { final Consumer> calculateConsumption = ignoreValue -> { int ess = this.getEssActivePower().getNextValue().orElse(0); int grid = this.getGridActivePower().getNextValue().orElse(0); - int production = this.getProductionActivePower().getNextValue().orElse(0); - int consumption = ess + grid + production; + int productionAc = this.getProductionAcActivePower().getNextValue().orElse(0); + int consumption = ess + grid + productionAc; this.getConsumptionActivePower().setNextValue(consumption); }; this.getEssActivePower().onSetNextValue(calculateConsumption); this.getGridActivePower().onSetNextValue(calculateConsumption); - this.getProductionActivePower().onSetNextValue(calculateConsumption); + this.getProductionAcActivePower().onSetNextValue(calculateConsumption); } @Activate @@ -310,12 +407,21 @@ protected void deactivate() { @Override public String debugLog() { + Value productionAc = this.getProductionAcActivePower().value(); + Value productionDc = this.getProductionDcActualPower().value(); + String production; + if (productionAc.asOptional().isPresent() && productionDc.asOptional().isPresent()) { + production = " Production:" + this.getProductionActivePower().value().asString(); + } else { + production = " Production Total:" + this.getProductionActivePower().value().asString() // + + ",AC:" + productionAc.asString() // + + ",DC:" + productionDc.asString(); // + } return "Ess SoC:" + this.getEssSoc().value().asString() // + "|L:" + this.getEssActivePower().value().asString() // - + " Grid L:" + this.getGridActivePower().value().asString() // - + " Production L:" + this.getProductionActivePower().value().asString() // - + " Consumption L:" + this.getConsumptionActivePower().value().asString() // - ; + + " Grid:" + this.getGridActivePower().value().asString() // + + production // + + " Consumption L:" + this.getConsumptionActivePower().value().asString(); // } public Channel getEssSoc() { @@ -342,10 +448,26 @@ public Channel getProductionActivePower() { return this.channel(ChannelId.PRODUCTION_ACTIVE_POWER); } + public Channel getProductionAcActivePower() { + return this.channel(ChannelId.PRODUCTION_AC_ACTIVE_POWER); + } + + public Channel getProductionDcActualPower() { + return this.channel(ChannelId.PRODUCTION_DC_ACTUAL_POWER); + } + public Channel getProductionMaxActivePower() { return this.channel(ChannelId.PRODUCTION_MAX_ACTIVE_POWER); } + public Channel getProductionMaxAcActivePower() { + return this.channel(ChannelId.PRODUCTION_MAX_AC_ACTIVE_POWER); + } + + public Channel getProductionMaxDcActualPower() { + return this.channel(ChannelId.PRODUCTION_MAX_DC_ACTUAL_POWER); + } + public Channel getConsumptionActivePower() { return this.channel(ChannelId.CONSUMPTION_ACTIVE_POWER); } diff --git a/io.openems.edge.core/src/io/openems/edge/core/sum/Utils.java b/io.openems.edge.core/src/io/openems/edge/core/sum/Utils.java index 9d56986d697..ac4bacc9d89 100644 --- a/io.openems.edge.core/src/io/openems/edge/core/sum/Utils.java +++ b/io.openems.edge.core/src/io/openems/edge/core/sum/Utils.java @@ -5,7 +5,7 @@ import io.openems.edge.common.channel.AbstractReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; public class Utils { @@ -14,7 +14,7 @@ public static Stream> initializeChannels(Sum c) Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; }), Arrays.stream(Sum.ChannelId.values()).map(channelId -> { @@ -26,6 +26,10 @@ public static Stream> initializeChannels(Sum c) case GRID_MIN_ACTIVE_POWER: case PRODUCTION_ACTIVE_POWER: case PRODUCTION_MAX_ACTIVE_POWER: + case PRODUCTION_AC_ACTIVE_POWER: + case PRODUCTION_MAX_AC_ACTIVE_POWER: + case PRODUCTION_DC_ACTUAL_POWER: + case PRODUCTION_MAX_DC_ACTUAL_POWER: case CONSUMPTION_ACTIVE_POWER: case CONSUMPTION_MAX_ACTIVE_POWER: return new IntegerReadChannel(c, channelId, 0); diff --git a/io.openems.edge.ess.api/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.ess.api/.settings/org.eclipse.core.resources.prefs index 7df979ca78c..8031f484afe 100644 --- a/io.openems.edge.ess.api/.settings/org.eclipse.core.resources.prefs +++ b/io.openems.edge.ess.api/.settings/org.eclipse.core.resources.prefs @@ -1,10 +1,9 @@ eclipse.preferences.version=1 -encoding//src/io/openems/edge/ess/api/Ess.java=UTF-8 +encoding//src/io/openems/edge/ess/api/AsymmetricEss.java=UTF-8 +encoding//src/io/openems/edge/ess/api/ManagedAsymmetricEss.java=UTF-8 +encoding//src/io/openems/edge/ess/api/ManagedSymmetricEss.java=UTF-8 +encoding//src/io/openems/edge/ess/api/SymmetricEss.java=UTF-8 encoding//src/io/openems/edge/ess/api/package-info.java=UTF-8 -encoding//src/io/openems/edge/ess/power/package-info.java=UTF-8 -encoding//src/io/openems/edge/ess/power/symmetric/package-info.java=UTF-8 -encoding//src/io/openems/edge/ess/symmetric/api/SymmetricEss.java=UTF-8 -encoding//src/io/openems/edge/ess/symmetric/api/package-info.java=UTF-8 encoding//test/.gitignore=UTF-8 encoding/bnd.bnd=UTF-8 encoding/readme.md=UTF-8 diff --git a/io.openems.edge.ess.api/bnd.bnd b/io.openems.edge.ess.api/bnd.bnd index 7c0d74a74e5..713467c41e2 100644 --- a/io.openems.edge.ess.api/bnd.bnd +++ b/io.openems.edge.ess.api/bnd.bnd @@ -6,18 +6,22 @@ Export-Package: \ io.openems.edge.ess.api,\ io.openems.edge.ess.symmetric.api,\ io.openems.edge.ess.symmetric.readonly.api,\ - io.openems.edge.ess.power,\ - io.openems.edge.ess.power.symmetric,\ - io.openems.edge.ess.dccharger.api - + io.openems.edge.ess.dccharger.api,\ + io.openems.edge.ess.asymmetric.api,\ + io.openems.edge.ess.core.power,\ + org.apache.commons.math3.optim.linear,\ + io.openems.edge.ess.power.api +Require-Capability: \ + compile-only + -includeresource: {readme.md} -buildpath: \ osgi.enroute.base.api;version=2.1,\ io.openems.edge.common;version=latest,\ com.google.guava,\ - io.openems.wrapper.jts;version=latest,\ - io.openems.common;version=latest + io.openems.common;version=latest,\ + org.apache.commons.math3;version=3.6 -testpath: \ osgi.enroute.junit.wrapper;version=4.12, \ diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/AsymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/AsymmetricEss.java new file mode 100644 index 00000000000..845211f18de --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/AsymmetricEss.java @@ -0,0 +1,176 @@ +package io.openems.edge.ess.api; + +import org.osgi.annotation.versioning.ProviderType; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Unit; + +@ProviderType +public interface AsymmetricEss extends SymmetricEss { + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + /** + * Active Power L1 + * + *
          + *
        • Interface: Ess Asymmetric + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Charge; positive for Discharge + *
        + */ + ACTIVE_POWER_L1(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT) // + .text(POWER_DOC_TEXT) // + ), + /** + * Active Power L2 + * + *
          + *
        • Interface: Ess Asymmetric + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Charge; positive for Discharge + *
        + */ + ACTIVE_POWER_L2(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT) // + .text(POWER_DOC_TEXT) // + ), + /** + * Active Power L3 + * + *
          + *
        • Interface: Ess Asymmetric + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Charge; positive for Discharge + *
        + */ + ACTIVE_POWER_L3(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT) // + .text(POWER_DOC_TEXT) // + ), + /** + * Reactive Power L1 + * + *
          + *
        • Interface: Ess Asymmetric + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Charge; positive for Discharge + *
        + */ + REACTIVE_POWER_L1(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // + .text(POWER_DOC_TEXT) // + ), + /** + * Reactive Power L2 + * + *
          + *
        • Interface: Ess Asymmetric + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Charge; positive for Discharge + *
        + */ + REACTIVE_POWER_L2(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // + .text(POWER_DOC_TEXT) // + ), + /** + * Reactive Power L3 + * + *
          + *
        • Interface: Ess Asymmetric + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Charge; positive for Discharge + *
        + */ + REACTIVE_POWER_L3(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // + .text(POWER_DOC_TEXT) // + ); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Active Power on L1 in [W]. Negative values for Charge; positive for + * Discharge + * + * @return + */ + default Channel getActivePowerL1() { + return this.channel(ChannelId.ACTIVE_POWER_L1); + } + + /** + * Gets the Active Power on L2 in [W]. Negative values for Charge; positive for + * Discharge + * + * @return + */ + default Channel getActivePowerL2() { + return this.channel(ChannelId.ACTIVE_POWER_L1); + } + + /** + * Gets the Active Power on L3 in [W]. Negative values for Charge; positive for + * Discharge + * + * @return + */ + default Channel getActivePowerL3() { + return this.channel(ChannelId.ACTIVE_POWER_L3); + } + + /** + * Gets the Reactive Power on L1 in [var]. Negative values for Charge; positive + * for Discharge + * + * @return + */ + default Channel getReactivePowerL1() { + return this.channel(ChannelId.REACTIVE_POWER_L1); + } + + /** + * Gets the Reactive Power on L2 in [var]. Negative values for Charge; positive + * for Discharge + * + * @return + */ + default Channel getReactivePowerL2() { + return this.channel(ChannelId.REACTIVE_POWER_L2); + } + + /** + * Gets the Reactive Power on L3 in [var]. Negative values for Charge; positive + * for Discharge + * + * @return + */ + default Channel getReactivePowerL3() { + return this.channel(ChannelId.REACTIVE_POWER_L3); + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/Ess.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/Ess.java deleted file mode 100644 index 8ec19a38e09..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/Ess.java +++ /dev/null @@ -1,93 +0,0 @@ -package io.openems.edge.ess.api; - -import org.osgi.annotation.versioning.ProviderType; - -import io.openems.common.types.OpenemsType; -import io.openems.edge.common.channel.Channel; -import io.openems.edge.common.channel.doc.Doc; -import io.openems.edge.common.channel.doc.Unit; -import io.openems.edge.common.component.OpenemsComponent; - -@ProviderType -public interface Ess extends OpenemsComponent { - - public enum GridMode { - UNDEFINED, ON_GRID, OFF_GRID - } - - public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { - /** - * State of Charge - * - *
          - *
        • Interface: Ess - *
        • Type: Integer - *
        • Unit: % - *
        • Range: 0..100 - *
        - */ - SOC(new Doc().type(OpenemsType.INTEGER).unit(Unit.PERCENT)), - /** - * Grid-Mode - * - *
          - *
        • Interface: Ess - *
        • Type: Integer/Enum - *
        • Range: 0=Undefined, 1=On-Grid, 2=Off-Grid - *
        - */ - GRID_MODE(new Doc().type(OpenemsType.INTEGER) // - .option(GridMode.UNDEFINED) // - .option(GridMode.ON_GRID) // - .option(GridMode.OFF_GRID) // - ), - /** - * Max Active Power - * - *
          - *
        • Interface: Ess - *
        • Type: Integer - *
        • Unit: W - *
        - */ - MAX_ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)); - - private final Doc doc; - - private ChannelId(Doc doc) { - this.doc = doc; - } - - @Override - public Doc doc() { - return this.doc; - } - } - - /** - * Gets the State of Charge in [%], range 0..100 % - * - * @return - */ - default Channel getSoc() { - return this.channel(ChannelId.SOC); - } - - /** - * Is the Ess On-Grid? - * - * @return - */ - default Channel getGridMode() { - return this.channel(ChannelId.GRID_MODE); - } - - /** - * Gets the maximum Active Power - * - * @return - */ - default Channel getMaxActivePower() { - return this.channel(ChannelId.MAX_ACTIVE_POWER); - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedAsymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedAsymmetricEss.java new file mode 100644 index 00000000000..9d8c1383e6c --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedAsymmetricEss.java @@ -0,0 +1,121 @@ +package io.openems.edge.ess.api; + +import org.osgi.annotation.versioning.ProviderType; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Unit; + +@ProviderType +public interface ManagedAsymmetricEss extends ManagedSymmetricEss, AsymmetricEss { + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + /** + * Holds settings of Active Power L1 for debugging + * + *
          + *
        • Interface: Managed Asymmetric Ess + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Charge; positive for Discharge + *
        • Implementation Note: value is automatically written by {@link Power} just + * before it calls the onWriteListener (which writes the value to the Ess) + *
        + */ + DEBUG_SET_ACTIVE_POWER_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // + /** + * Holds settings of Reactive Power for debugging + * + *
          + *
        • Interface: Managed Asymmetric Ess + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Charge; positive for Discharge + *
        • Implementation Note: value is automatically written by {@link Power} just + * before it calls the onWriteListener (which writes the value to the Ess) + *
        + */ + DEBUG_SET_REACTIVE_POWER_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // + /** + * Holds settings of Active Power L2 for debugging + * + *
          + *
        • Interface: Managed Asymmetric Ess + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Charge; positive for Discharge + *
        • Implementation Note: value is automatically written by {@link Power} just + * before it calls the onWriteListener (which writes the value to the Ess) + *
        + */ + DEBUG_SET_ACTIVE_POWER_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // + /** + * Holds settings of Reactive Power for debugging + * + *
          + *
        • Interface: Managed Asymmetric Ess + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Charge; positive for Discharge + *
        • Implementation Note: value is automatically written by {@link Power} just + * before it calls the onWriteListener (which writes the value to the Ess) + *
        + */ + DEBUG_SET_REACTIVE_POWER_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // + /** + * Holds settings of Active Power L1 for debugging + * + *
          + *
        • Interface: Managed Asymmetric Ess + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Charge; positive for Discharge + *
        • Implementation Note: value is automatically written by {@link Power} just + * before it calls the onWriteListener (which writes the value to the Ess) + *
        + */ + DEBUG_SET_ACTIVE_POWER_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // + /** + * Holds settings of Reactive Power for debugging + * + *
          + *
        • Interface: Managed Asymmetric Ess + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Charge; positive for Discharge + *
        • Implementation Note: value is automatically written by {@link Power} just + * before it calls the onWriteListener (which writes the value to the Ess) + *
        + */ + DEBUG_SET_REACTIVE_POWER_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + public Doc doc() { + return this.doc; + } + } + + @Override + default void applyPower(int activePower, int reactivePower) { + int activePowerBy3 = activePower / 3; + int reactivePowerBy3 = reactivePower / 3; + this.applyPower(activePowerBy3, reactivePowerBy3, activePowerBy3, reactivePowerBy3, activePowerBy3, + reactivePowerBy3); + } + + /** + * Apply the calculated Power + * + * @param activePower + * @param reactivePower + */ + public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, + int activePowerL3, int reactivePowerL3); + +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java new file mode 100644 index 00000000000..e244d7aedf4 --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedSymmetricEss.java @@ -0,0 +1,113 @@ +package io.openems.edge.ess.api; + +import org.apache.commons.math3.optim.linear.Relationship; +import org.osgi.annotation.versioning.ProviderType; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.power.api.PowerException; +import io.openems.edge.ess.power.api.Pwr; + +@ProviderType +public interface ManagedSymmetricEss extends SymmetricEss { + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + /** + * Holds settings of Active Power for debugging + * + *
          + *
        • Interface: Managed Symmetric Ess + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Charge; positive for Discharge + *
        • Implementation Note: value is automatically written by {@link Power} just + * before it calls the onWriteListener (which writes the value to the Ess) + *
        + */ + DEBUG_SET_ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // + /** + * Holds settings of Reactive Power for debugging + * + *
          + *
        • Interface: Managed Symmetric Ess + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Charge; positive for Discharge + *
        • Implementation Note: value is automatically written by {@link Power} just + * just before it calls the onWriteListener (which writes the value to the Ess) + *
        + */ + DEBUG_SET_REACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the 'Power' class, which allows to set limitations to Active and + * Reactive Power. + * + * @return + */ + public Power getPower(); + + /** + * Apply the calculated Power + * + * @param activePower + * @param reactivePower + */ + public void applyPower(int activePower, int reactivePower); + + /** + * Gets the smallest positive power that can be set (in W, VA or var). Example: + *
          + *
        • FENECON Commercial 40 allows setting of power in 100 W steps. It should + * return 100. + *
        • KACO blueplanet gridsave 50 allows setting of power in 0.1 % of 52 VA. It + * should return 52 (= 52000 * 0.001) + *
            + * + * @return + */ + public int getPowerPrecision(); + + /** + * Adds a Power constraint. + * + * @param relationship + * @param activePower + * @return + * @throws PowerException + */ + public default Constraint addPowerConstraint(ConstraintType type, Phase phase, Pwr pwr, Relationship relationship, + int value) { + return this.getPower().addSimpleConstraint(this, type, phase, pwr, relationship, value); + } + + /** + * Adds a Power constraint if the problem is still solvable after adding it. + * + * @param relationship + * @param activePower + * @return + * @throws PowerException + */ + public default Constraint addPowerConstraintAndValidate(ConstraintType type, Phase phase, Pwr pwr, + Relationship relationship, int value) throws PowerException { + return this.getPower().addSimpleConstraintAndValidate(this, type, phase, pwr, relationship, value); + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/MetaEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/MetaEss.java new file mode 100644 index 00000000000..2c562f8925c --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/MetaEss.java @@ -0,0 +1,14 @@ +package io.openems.edge.ess.api; + +import java.util.List; + +/** + * A MetaEss is a wrapper for physical energy storage systems. It is not a + * physical Ess itself. This is used to distinguish e.g. an EssCluster from an + * actual Ess. + */ +public interface MetaEss extends SymmetricEss { + + public List getEsss(); + +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java new file mode 100644 index 00000000000..f0b3b28f5d4 --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java @@ -0,0 +1,187 @@ +package io.openems.edge.ess.api; + +import org.osgi.annotation.versioning.ProviderType; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.common.component.OpenemsComponent; + +@ProviderType +public interface SymmetricEss extends OpenemsComponent { + + public final static String POWER_DOC_TEXT = "Negative values for Charge; positive for Discharge"; + + public enum GridMode { + UNDEFINED, ON_GRID, OFF_GRID + } + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + /** + * State of Charge + * + *
              + *
            • Interface: Ess + *
            • Type: Integer + *
            • Unit: % + *
            • Range: 0..100 + *
            + */ + SOC(new Doc().type(OpenemsType.INTEGER).unit(Unit.PERCENT)), + /** + * Grid-Mode + * + *
              + *
            • Interface: Ess + *
            • Type: Integer/Enum + *
            • Range: 0=Undefined, 1=On-Grid, 2=Off-Grid + *
            + */ + GRID_MODE(new Doc().type(OpenemsType.INTEGER) // + .option(GridMode.UNDEFINED) // + .option(GridMode.ON_GRID) // + .option(GridMode.OFF_GRID) // + ), + /** + * Active Power + * + *
              + *
            • Interface: Ess Symmetric + *
            • Type: Integer + *
            • Unit: W + *
            • Range: negative values for Charge; positive for Discharge + *
            + */ + ACTIVE_POWER(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT) // + .text(POWER_DOC_TEXT) // + ), + /** + * Reactive Power + * + *
              + *
            • Interface: Ess Symmetric + *
            • Type: Integer + *
            • Unit: var + *
            • Range: negative values for Charge; positive for Discharge + *
            + */ + REACTIVE_POWER(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // + .text(POWER_DOC_TEXT) // + ), + /** + * Max Active Power + * + *
              + *
            • Interface: Ess + *
            • Type: Integer + *
            • Unit: W + *
            + */ + MAX_ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), + /** + * Active Charge Energy + * + *
              + *
            • Interface: Ess Symmetric + *
            • Type: Integer + *
            • Unit: Wh + *
            + */ + ACTIVE_CHARGE_ENERGY(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT_HOURS)), + /** + * Active Discharge Energy + * + *
              + *
            • Interface: Ess Symmetric + *
            • Type: Integer + *
            • Unit: Wh + *
            + */ + ACTIVE_DISCHARGE_ENERGY(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT_HOURS)); + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the State of Charge in [%], range 0..100 % + * + * @return + */ + default Channel getSoc() { + return this.channel(ChannelId.SOC); + } + + /** + * Is the Ess On-Grid? + * + * @return + */ + default Channel getGridMode() { + return this.channel(ChannelId.GRID_MODE); + } + + /** + * Gets the Active Power in [W]. Negative values for Charge; positive for + * Discharge + * + * @return + */ + default Channel getActivePower() { + return this.channel(ChannelId.ACTIVE_POWER); + } + + /** + * Gets the maximum Active Power + * + * @return + */ + default Channel getMaxActivePower() { + return this.channel(ChannelId.MAX_ACTIVE_POWER); + } + + /** + * Gets the Reactive Power in [var]. Negative values for Charge; positive for + * Discharge + * + * @return + */ + default Channel getReactivePower() { + return this.channel(ChannelId.REACTIVE_POWER); + } + + /** + * Gets the Active Charge Energy in [Wh]. + * + * @return + */ + default Channel getActiveChargeEnergy() { + return this.channel(ChannelId.ACTIVE_CHARGE_ENERGY); + } + + /** + * Gets the Active Discharge Energy in [Wh]. + * + * @return + */ + default Channel getActiveDischargeEnergy() { + return this.channel(ChannelId.ACTIVE_CHARGE_ENERGY); + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java index fb4fe2cbc2d..40e627595e7 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java @@ -1,8 +1,11 @@ package io.openems.edge.ess.dccharger.api; import org.osgi.annotation.versioning.ProviderType; +import org.osgi.service.cm.ConfigurationAdmin; import io.openems.common.types.OpenemsType; +import io.openems.common.utils.IntUtils; +import io.openems.common.utils.IntUtils.Round; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.channel.doc.Unit; @@ -12,6 +15,18 @@ public interface EssDcCharger extends OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + /** + * Maximum Ever Actual Power + * + *
              + *
            • Interface: Ess DC Charger + *
            • Type: Integer + *
            • Unit: W + *
            • Range: positive or '0' + *
            • Implementation Note: value is automatically derived from ACTUAL_POWER + *
            + */ + MAX_ACTUAL_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // /** * Actual Power * @@ -22,7 +37,36 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { *
          • Range: positive *
          */ - ACTUAL_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)); // + ACTUAL_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT).onInit(channel -> { + channel.onSetNextValue(value -> { + /* + * Fill Max Actual Power channel + */ + if (value.asOptional().isPresent()) { + int newValue = (int) value.get(); + Channel maxActualPowerChannel = channel.getComponent().channel(ChannelId.MAX_ACTUAL_POWER); + int maxActualPower = maxActualPowerChannel.value().orElse(0); + int maxNextActualPower = maxActualPowerChannel.getNextValue().orElse(0); + if (newValue > Math.max(maxActualPower, maxNextActualPower)) { + // avoid getting called too often -> round to 100 + newValue = IntUtils.roundToPrecision(newValue, Round.UP, 100); + maxActualPowerChannel.setNextValue(newValue); + } + } + }); + })), + /** + * Actual Energy + * + *
            + *
          • Interface: Ess Symmetric + *
          • Type: Integer + *
          • Unit: Wh + *
          + */ + ACTUAL_ENERGY(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT_HOURS)); private final Doc doc; @@ -45,4 +89,43 @@ public Doc doc() { default Channel getActualPower() { return this.channel(ChannelId.ACTUAL_POWER); } + + /** + * Gets the Maximum Ever Actual Power. + * + * @return + */ + default Channel getMaxActualPower() { + return this.channel(ChannelId.MAX_ACTUAL_POWER); + } + + /** + * Gets the Actual Energy in [Wh]. + * + * @return + */ + default Channel getActualEnergy() { + return this.channel(ChannelId.ACTUAL_ENERGY); + } + + /** + * Internal helper method to handle storing MaxActualPower in config property + * 'maxActualPower' + * + * @param cm + * @param servicePid + * @param maxActualPowerConfig + */ + default void _initializMaxActualPower(ConfigurationAdmin cm, String servicePid, int maxActualPowerConfig) { + /* + * Update min/max active power channels + */ + this.getMaxActualPower().setNextValue(maxActualPowerConfig); + + this.getMaxActualPower().onChange(value -> { + if (value.get() != maxActualPowerConfig) { + OpenemsComponent.updateConfigurationProperty(cm, servicePid, "maxActualPower", value.get()); + } + }); + } } diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/PowerException.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/PowerException.java deleted file mode 100644 index 93a6cd72c52..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/PowerException.java +++ /dev/null @@ -1,17 +0,0 @@ -package io.openems.edge.ess.power; - -import io.openems.common.exceptions.OpenemsException; - -public class PowerException extends OpenemsException { - - private static final long serialVersionUID = 1L; - - public PowerException(String arg0, Throwable arg1) { - super(arg0, arg1); - } - - public PowerException(String arg0) { - super(arg0); - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/SVGWriter.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/SVGWriter.java deleted file mode 100644 index b7b61407214..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/SVGWriter.java +++ /dev/null @@ -1,597 +0,0 @@ -package io.openems.edge.ess.power; - -/* - * Copyright (c) 2016 Vivid Solutions. - * - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * and Eclipse Distribution License v. 1.0 which accompanies this distribution. - * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html - * and the Eclipse Distribution License is available at - * - * http://www.eclipse.org/org/documents/edl-v10.php. - */ - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.CoordinateSequence; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryCollection; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.LinearRing; -import com.vividsolutions.jts.geom.MultiLineString; -import com.vividsolutions.jts.geom.MultiPoint; -import com.vividsolutions.jts.geom.MultiPolygon; -import com.vividsolutions.jts.geom.Point; -import com.vividsolutions.jts.geom.Polygon; -import com.vividsolutions.jts.geom.PrecisionModel; -import com.vividsolutions.jts.io.WKTReader; -import com.vividsolutions.jts.util.Assert; - -/** - * Writes the Well-Known Text representation of a {@link Geometry}. The - * Well-Known Text format is defined in the OGC - * Simple Features - * Specification for SQL. See {@link WKTReader} for a formal - * specification of the format syntax. - *

          - * The WKTWriter outputs coordinates rounded to the precision - * model. Only the maximum number of decimal places necessary to represent the - * ordinates to the required precision will be output. - *

          - * The SFS WKT spec does not define a special tag for {@link LinearRing}s. Under - * the spec, rings are output as LINESTRINGs. In order to allow - * precisely specifying constructed geometries, JTS also supports a non-standard - * LINEARRING tag which is used to output LinearRings. - * - * @version 1.7 - * @see WKTReader - */ -public class SVGWriter { - - /** - * Creates the DecimalFormat used to write doubles - * with a sufficient number of decimal places. - * - * @param precisionModel - * the PrecisionModel used to determine the number of - * decimal places to write. - * @return a DecimalFormat that write double s without - * scientific notation. - */ - private static DecimalFormat createFormatter(PrecisionModel precisionModel) { - // the default number of decimal places is 16, which is sufficient - // to accomodate the maximum precision of a double. - int decimalPlaces = precisionModel.getMaximumSignificantDigits(); - // specify decimal separator explicitly to avoid problems in other locales - DecimalFormatSymbols symbols = new DecimalFormatSymbols(); - symbols.setDecimalSeparator('.'); - String fmtString = "0" + (decimalPlaces > 0 ? "." : "") + stringOfChar('#', decimalPlaces); - return new DecimalFormat(fmtString, symbols); - } - - /** - * Returns a String of repeated characters. - * - * @param ch - * the character to repeat - * @param count - * the number of times to repeat the character - * @return a String of characters - */ - public static String stringOfChar(char ch, int count) { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < count; i++) { - buf.append(ch); - } - return buf.toString(); - } - - private int outputDimension = 2; - private DecimalFormat formatter; - private boolean isFormatted = false; - private boolean useFormatting = false; - private int coordsPerLine = -1; - private String indentTabStr = " "; - - /** - * Creates a new SVGWriter with default settings - */ - public SVGWriter() { - } - - /** - * Converts a Geometry to its Well-known Text representation. - * - * @param geometry - * a Geometry to process - * @return a string (see the OpenGIS Simple Features - * Specification) - */ - public String write(Geometry geometry) { - Writer sw = new StringWriter(); - try { - writeFormatted(geometry, isFormatted, sw); - } catch (IOException ex) { - Assert.shouldNeverReachHere(); - } - return sw.toString(); - } - - /** - * Converts a Geometry to its Well-known Text representation. - * - * @param geometry - * a Geometry to process - */ - public void write(Geometry geometry, Writer writer) throws IOException { - writeFormatted(geometry, false, writer); - } - - /** - * Same as write, but with newlines and spaces to make the - * well-known text more readable. - * - * @param geometry - * a Geometry to process - * @return a string (see the OpenGIS Simple Features - * Specification), with newlines and spaces - */ - public String writeFormatted(Geometry geometry) { - Writer sw = new StringWriter(); - try { - writeFormatted(geometry, true, sw); - } catch (IOException ex) { - Assert.shouldNeverReachHere(); - } - return sw.toString(); - } - - /** - * Same as write, but with newlines and spaces to make the - * well-known text more readable. - * - * @param geometry - * a Geometry to process - */ - public void writeFormatted(Geometry geometry, Writer writer) throws IOException { - writeFormatted(geometry, true, writer); - } - - /** - * Converts a Geometry to its Well-known Text representation. - * - * @param geometry - * a Geometry to process - */ - private void writeFormatted(Geometry geometry, boolean useFormatting, Writer writer) throws IOException { - this.useFormatting = useFormatting; - formatter = createFormatter(geometry.getPrecisionModel()); - // writer.write("\n"); - appendGeometryTaggedText(geometry, 0, writer); - // writer.write("\n"); - } - - /** - * Converts a Geometry to <Geometry Tagged Text> format, then - * appends it to the writer. - * - * @param geometry - * the Geometry to process - * @param writer - * the output writer to append to - */ - private void appendGeometryTaggedText(Geometry geometry, int level, Writer writer) throws IOException { - indent(level, writer); - - if (geometry instanceof Point) { - Point point = (Point) geometry; - appendPointTaggedText(point.getCoordinate(), level, writer, point.getPrecisionModel()); - } else if (geometry instanceof LinearRing) { - appendLinearRingTaggedText((LinearRing) geometry, level, writer); - } else if (geometry instanceof LineString) { - appendLineStringTaggedText((LineString) geometry, level, writer); - } else if (geometry instanceof Polygon) { - appendPolygon((Polygon) geometry, level, writer); - } else if (geometry instanceof MultiPoint) { - appendMultiPointTaggedText((MultiPoint) geometry, level, writer); - } else if (geometry instanceof MultiLineString) { - appendMultiLineStringTaggedText((MultiLineString) geometry, level, writer); - } else if (geometry instanceof MultiPolygon) { - appendMultiPolygonTaggedText((MultiPolygon) geometry, level, writer); - } else if (geometry instanceof GeometryCollection) { - appendGeometryCollectionTaggedText((GeometryCollection) geometry, level, writer); - } else { - Assert.shouldNeverReachHere("Unsupported Geometry implementation:" + geometry.getClass()); - } - - } - - /** - * Converts a Coordinate to <Point Tagged Text> format, then - * appends it to the writer. - * - * @param coordinate - * the Coordinate to process - * @param writer - * the output writer to append to - * @param precisionModel - * the PrecisionModel to use to convert from a precise - * coordinate to an external coordinate - */ - private void appendPointTaggedText(Coordinate coordinate, int level, Writer writer, PrecisionModel precisionModel) - throws IOException { - appendPoint(coordinate, level, writer, precisionModel); - } - - /** - * Converts a LineString to <LineString Tagged Text> format, - * then appends it to the writer. - * - * @param lineString - * the LineString to process - * @param writer - * the output writer to append to - */ - private void appendLineStringTaggedText(LineString lineString, int level, Writer writer) throws IOException { - appendLineString(lineString, level, false, writer); - } - - /** - * Converts a LinearRing to <LinearRing Tagged Text> format, - * then appends it to the writer. - * - * @param linearRing - * the LinearRing to process - * @param writer - * the output writer to append to - */ - private void appendLinearRingTaggedText(LinearRing linearRing, int level, Writer writer) throws IOException { - appendLineString(linearRing, level, false, writer); - } - - /** - * Converts a Polygon to <Polygon Tagged Text> format, then - * appends it to the writer. - * - * @param polygon - * the Polygon to process - * @param writer - * the output writer to append to - */ - private void appendPolygon(Polygon polygon, int level, Writer writer) throws IOException { - if (polygon.getNumInteriorRing() == 0) { - appendPolygonPolygon(polygon, level, false, writer); - } else { - appendPolygonPath(polygon, level, false, writer); - } - } - - /** - * Converts a MultiPoint to <MultiPoint Tagged Text> format, - * then appends it to the writer. - * - * @param multipoint - * the MultiPoint to process - * @param writer - * the output writer to append to - */ - private void appendMultiPointTaggedText(MultiPoint multipoint, int level, Writer writer) throws IOException { - appendMultiPointText(multipoint, level, writer); - } - - /** - * Converts a MultiLineString to <MultiLineString Tagged - * Text> format, then appends it to the writer. - * - * @param multiLineString - * the MultiLineString to process - * @param writer - * the output writer to append to - */ - private void appendMultiLineStringTaggedText(MultiLineString multiLineString, int level, Writer writer) - throws IOException { - appendMultiLineStringText(multiLineString, level, false, writer); - } - - /** - * Converts a MultiPolygon to <MultiPolygon Tagged Text> - * format, then appends it to the writer. - * - * @param multiPolygon - * the MultiPolygon to process - * @param writer - * the output writer to append to - */ - private void appendMultiPolygonTaggedText(MultiPolygon multiPolygon, int level, Writer writer) throws IOException { - appendMultiPolygonText(multiPolygon, level, writer); - } - - /** - * Converts a GeometryCollection to <GeometryCollection Tagged - * Text> format, then appends it to the writer. - * - * @param geometryCollection - * the GeometryCollection to process - * @param writer - * the output writer to append to - */ - private void appendGeometryCollectionTaggedText(GeometryCollection geometryCollection, int level, Writer writer) - throws IOException { - appendGeometryCollectionText(geometryCollection, level, writer); - } - - /** - * Converts a Coordinate to <Point Text> format, then appends - * it to the writer. - * - * @param coordinate - * the Coordinate to process - * @param writer - * the output writer to append to - * @param precisionModel - * the PrecisionModel to use to convert from a precise - * coordinate to an external coordinate - */ - private void appendPoint(Coordinate coordinate, int level, Writer writer, PrecisionModel precisionModel) - throws IOException { - writer.write("("); - appendCoordinate(coordinate, writer); - writer.write(")"); - } - - /** - * Appends the i'th coordinate from the sequence to the writer - * - * @param seq - * the CoordinateSequence to process - * @param i - * the index of the coordinate to write - * @param writer - * the output writer to append to - */ - private void appendCoordinate(CoordinateSequence seq, int i, Writer writer) throws IOException { - writer.write(writeNumber(seq.getX(i)) + "," + writeNumber(seq.getY(i))); - } - - /** - * Converts a Coordinate to <Point> format, then - * appends it to the writer. - * - * @param coordinate - * the Coordinate to process - * @param writer - * the output writer to append to - */ - private void appendCoordinate(Coordinate coordinate, Writer writer) throws IOException { - writer.write(writeNumber(coordinate.x) + " " + writeNumber(coordinate.y)); - if (outputDimension >= 3 && !Double.isNaN(coordinate.z)) { - writer.write(" "); - writer.write(writeNumber(coordinate.z)); - } - } - - /** - * Converts a double to a String, not in scientific - * notation. - * - * @param d - * the double to convert - * @return the double as a String, not in scientific - * notation - */ - private String writeNumber(double d) { - return formatter.format(d); - } - - /** - * Converts a LineString to <LineString Text> format, then - * appends it to the writer. - * - * @param lineString - * the LineString to process - * @param writer - * the output writer to append to - */ - private void appendSequencePath(CoordinateSequence seq, int level, boolean doIndent, Writer writer) - throws IOException { - if (seq.size() == 0) { - // writer.write("EMPTY"); - } else { - if (doIndent) { - indent(level, writer); - } - for (int i = 0; i < seq.size(); i++) { - writer.write(" " + ((i == 0) ? "M" : "L")); - if (i > 0) { - if (coordsPerLine > 0 && i % coordsPerLine == 0) { - indent(level + 1, writer); - } - } - appendCoordinate(seq, i, writer); - } - } - } - - private void appendSequencePoints(CoordinateSequence seq, int level, boolean doIndent, Writer writer) - throws IOException { - if (seq.size() == 0) { - // writer.write("EMPTY"); - } else { - if (doIndent) { - indent(level, writer); - } - for (int i = 0; i < seq.size(); i++) { - writer.write(" "); - if (i > 0) { - if (coordsPerLine > 0 && i % coordsPerLine == 0) { - indent(level + 1, writer); - } - } - appendCoordinate(seq, i, writer); - } - } - } - - /** - * Converts a LineString to <LineString Text> format, then - * appends it to the writer. - * - * @param lineString - * the LineString to process - * @param writer - * the output writer to append to - */ - private void appendLineString(LineString lineString, int level, boolean doIndent, Writer writer) - throws IOException { - if (doIndent) { - indent(level, writer); - } - writer.write("\n"); - } - - /** - * Converts a Polygon to <Polygon Text> format, then appends - * it to the writer. - * - * @param polygon - * the Polygon to process - * @param writer - * the output writer to append to - */ - private void appendPolygonPolygon(Polygon polygon, int level, boolean indentFirst, Writer writer) - throws IOException { - if (indentFirst) { - indent(level, writer); - } - writer.write("\n"); - } - - private void appendPolygonPath(Polygon polygon, int level, boolean indentFirst, Writer writer) throws IOException { - if (indentFirst) { - indent(level, writer); - } - writer.write("\n"); - } - - /** - * Converts a MultiPoint to <MultiPoint Text> format, then - * appends it to the writer. - * - * @param multiPoint - * the MultiPoint to process - * @param writer - * the output writer to append to - */ - private void appendMultiPointText(MultiPoint multiPoint, int level, Writer writer) throws IOException { - if (multiPoint.isEmpty()) { - writer.write("EMPTY"); - } else { - writer.write("("); - for (int i = 0; i < multiPoint.getNumGeometries(); i++) { - if (i > 0) { - writer.write(", "); - indentCoords(i, level + 1, writer); - } - writer.write("("); - appendCoordinate(((Point) multiPoint.getGeometryN(i)).getCoordinate(), writer); - writer.write(")"); - } - writer.write(")"); - } - } - - /** - * Converts a MultiLineString to <MultiLineString Text> - * format, then appends it to the writer. - * - * @param multiLineString - * the MultiLineString to process - * @param writer - * the output writer to append to - */ - private void appendMultiLineStringText(MultiLineString multiLineString, int level, boolean indentFirst, - Writer writer) throws IOException { - int level2 = level; - boolean doIndent = indentFirst; - for (int i = 0; i < multiLineString.getNumGeometries(); i++) { - if (i > 0) { - level2 = level + 1; - doIndent = true; - } - appendLineString((LineString) multiLineString.getGeometryN(i), level2, doIndent, writer); - } - } - - /** - * Converts a MultiPolygon to <MultiPolygon Text> format, - * then appends it to the writer. - * - * @param multiPolygon - * the MultiPolygon to process - * @param writer - * the output writer to append to - */ - private void appendMultiPolygonText(MultiPolygon multiPolygon, int level, Writer writer) throws IOException { - int level2 = level; - for (int i = 0; i < multiPolygon.getNumGeometries(); i++) { - if (i > 0) { - level2 = level + 1; - } - appendPolygon((Polygon) multiPolygon.getGeometryN(i), level2, writer); - } - } - - /** - * Converts a GeometryCollection to <GeometryCollectionText> - * format, then appends it to the writer. - * - * @param geometryCollection - * the GeometryCollection to process - * @param writer - * the output writer to append to - */ - private void appendGeometryCollectionText(GeometryCollection geometryCollection, int level, Writer writer) - throws IOException { - int level2 = level; - for (int i = 0; i < geometryCollection.getNumGeometries(); i++) { - if (i > 0) { - level2 = level + 1; - } - appendGeometryTaggedText(geometryCollection.getGeometryN(i), level2, writer); - } - } - - private void indentCoords(int coordIndex, int level, Writer writer) throws IOException { - if (coordsPerLine <= 0 || coordIndex % coordsPerLine != 0) { - return; - } - indent(level, writer); - } - - private void indent(int level, Writer writer) throws IOException { - if (!useFormatting || level <= 0) { - return; - } - writer.write("\n"); - for (int i = 0; i < level; i++) { - writer.write(indentTabStr); - } - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/CircleConstraint.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/CircleConstraint.java new file mode 100644 index 00000000000..186690e2412 --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/CircleConstraint.java @@ -0,0 +1,123 @@ +package io.openems.edge.ess.power.api; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.math3.optim.linear.Relationship; + +import com.google.common.base.Objects; + +import io.openems.edge.ess.api.ManagedSymmetricEss; + +/** + * Defines constraints that force points to be inside a circle. The circle is + * defined as a list of Constraints in the form of tangents to the circle. + * + * This can be used for a MaxApparentPower constraint. + */ +public class CircleConstraint { + + private final static int CIRCLE_SECTIONS_PER_QUARTER = 1; // don't set higher than 90 + + private final ManagedSymmetricEss ess; + private final List constraints = new ArrayList<>(); + + private Integer radius = null; + + private class Point { + protected final double x; + protected final double y; + + Point(double x, double y) { + this.x = x; + this.y = y; + } + + @Override + public String toString() { + return "Point [x=" + Math.round(x) + ", y=" + Math.round(y) + "]"; + } + } + + public CircleConstraint(ManagedSymmetricEss ess) { + this.ess = ess; + } + + public CircleConstraint(ManagedSymmetricEss ess, int radius) { + this(ess); + this.setRadius(radius); + } + + /** + * Disable these constraints + */ + public void disable() { + this.setRadius(null); + } + + public synchronized void setRadius(Integer radius) { + if (Objects.equal(radius, this.radius)) { + // unchanged -> nothing to do + return; + } + + // store radius + this.radius = radius; + + // remove all existing constraints from power + this.constraints.forEach(constraint -> { + this.ess.getPower().removeConstraint(constraint); + }); + this.constraints.clear(); + + if (radius == null) { + // no new radius given -> stop + return; + } + + double degreeDelta = 90.0 / CIRCLE_SECTIONS_PER_QUARTER; + Point p1 = this.getPointOnCircle(radius, 0); + + for (double degree = degreeDelta; Math.floor(degree) <= 360; degree += degreeDelta) { + Point p2 = this.getPointOnCircle(radius, degree); + + Relationship relationship; + if (Math.floor(degree) <= 180) { + relationship = Relationship.GEQ; + } else { + relationship = Relationship.LEQ; + } + + Constraint constraint = this.getConstraintThroughPoints(p1, p2, relationship); + this.ess.getPower().addConstraint(constraint); + this.constraints.add(constraint); + + // set p2 -> p1 for next loop + p1 = p2; + } + } + + private Point getPointOnCircle(double radius, double degree) { + return new Point(Math.cos(Math.toRadians(degree)) * radius, Math.sin(Math.toRadians(degree)) * radius); + } + + private Constraint getConstraintThroughPoints(Point p1, Point p2, Relationship relationship) { + /** + * Build the LinearConstraint. + * + *

          +		 *  We use the formula:
          +		 *  y = ((y2-y1)/(x2-x1)) * x + ((x2*y1-x1*y2)/(x2-x1))
          +		 * 
          + */ + double constraintValue = -1 * (p1.y * p2.x - p2.y * p1.x) / (p2.x - p1.x); + double coefficient1 = (p2.y - p1.y) / (p2.x - p1.x); + double coefficient2 = -1; + + return new Constraint(ConstraintType.STATIC, // + new Coefficient[] { // + new Coefficient(this.ess, Phase.ALL, Pwr.ACTIVE, coefficient1), // + new Coefficient(this.ess, Phase.ALL, Pwr.REACTIVE, coefficient2) // + }, relationship, constraintValue); + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Coefficient.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Coefficient.java new file mode 100644 index 00000000000..bef9fce006b --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Coefficient.java @@ -0,0 +1,45 @@ +package io.openems.edge.ess.power.api; + +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; + +public class Coefficient { + + private final ManagedSymmetricEss ess; + private final Phase phase; + private final Pwr pwr; + private final double value; + + public Coefficient(ManagedSymmetricEss ess, Pwr pwr, double value) { + this(ess, Phase.ALL, pwr, value); + } + + public Coefficient(ManagedSymmetricEss ess, Phase phase, Pwr pwr, double value) { + this.ess = ess; + this.phase = phase; + this.pwr = pwr; + this.value = value; + } + + @Override + public String toString() { + return "[" + ess.id() + "," + phase.name() + "," + pwr + "=" + value + "]"; + } + + public ManagedSymmetricEss getEss() { + return ess; + } + + public Phase getPhase() { + return phase; + } + + public Pwr getPwr() { + return pwr; + } + + public double getValue() { + return value; + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Constraint.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Constraint.java new file mode 100644 index 00000000000..9b0e770bc13 --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Constraint.java @@ -0,0 +1,84 @@ +package io.openems.edge.ess.power.api; + +import java.util.Arrays; +import java.util.Optional; + +import org.apache.commons.math3.optim.linear.Relationship; + +import io.openems.edge.ess.power.api.Coefficient; +import io.openems.edge.ess.power.api.ConstraintType; + +/** + * Creates a constraint with following settings: + *
            + *
          • Relationship (EQ, GEQ, LEQ) as given in constructor + *
          • Value as given in constructor + *
          • Setting each coefficient, i.e. + * + *
            + * y = 1*p1 + 0*q1 * + 1*p2 + 0*q1 +...
            + * 
            + *
          + */ +public class Constraint { + + private final ConstraintType type; + private final Coefficient[] coefficients; + private final Relationship relationship; + + private Optional value; + + public Constraint(ConstraintType type, Coefficient[] coefficients, Relationship relationship, Double value) { + this.type = type; + this.coefficients = coefficients; + this.relationship = relationship; + this.value = Optional.ofNullable(value); + } + + public Constraint(ConstraintType type, Coefficient[] coefficients, Relationship relationship, Integer value) { + this(type, coefficients, relationship, value == null ? null : value.doubleValue()); + } + + @Override + public String toString() { + return "Constraint [coefficients=" + Arrays.toString(coefficients) + ", relationship=" + relationship.name() + + ", value=" + value + "]"; + } + + /** + * Whether this Constraint is Enabled and valid. + * + * @return + */ + public boolean isEnabled() { + return this.value.isPresent(); + } + + public ConstraintType getType() { + return type; + } + + public Coefficient[] getCoefficients() { + return coefficients; + } + + public Relationship getRelationship() { + return relationship; + } + + public Optional getValue() { + return this.value; + } + + public void setDoubleValue(Double value) { + this.value = Optional.ofNullable(value); + } + + public void setIntValue(Integer value) { + if (value == null) { + this.value = Optional.empty(); + } else { + this.value = Optional.ofNullable(value.doubleValue()); + } + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/ConstraintBuilder.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/ConstraintBuilder.java new file mode 100644 index 00000000000..3042026e845 --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/ConstraintBuilder.java @@ -0,0 +1,55 @@ +package io.openems.edge.ess.power.api; + +import org.apache.commons.math3.optim.linear.Relationship; + +public class ConstraintBuilder { + + private final Power parent; + private ConstraintType type = ConstraintType.CYCLE; + private Coefficient[] coefficients; + private Relationship relationship = Relationship.EQ; + private double value = 0; + + /** + * Creates a Constraint. Make sure to call 'build()' to actually apply the + * constraint + * + * Defaults are: + *
            + *
          • type = ConstraintType.CYCLE + *
          • relationship = Relationship.EQ + *
          • value = 0 + * + * @param parent + */ + public ConstraintBuilder(Power parent) { + this.parent = parent; + } + + public ConstraintBuilder type(ConstraintType type) { + this.type = type; + return this; + } + + public ConstraintBuilder coefficients(Coefficient... coefficients) { + this.coefficients = coefficients; + return this; + } + + public ConstraintBuilder relationship(Relationship relationship) { + this.relationship = relationship; + return this; + } + + public ConstraintBuilder value(double value) { + this.value = value; + return this; + } + + /** + * Builds the Constraint and adds it + */ + public Constraint build() { + return parent.addConstraint(new Constraint(type, coefficients, relationship, value)); + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/ConstraintType.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/ConstraintType.java new file mode 100644 index 00000000000..837b554c863 --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/ConstraintType.java @@ -0,0 +1,12 @@ +package io.openems.edge.ess.power.api; + +public enum ConstraintType { + /** + * Static constraints. Those constraints stay forever. + */ + STATIC, + /** + * Cycle constraints. Those constraints are cleared on every Cycle + */ + CYCLE; +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Phase.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Phase.java new file mode 100644 index 00000000000..5fa895f0546 --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Phase.java @@ -0,0 +1,15 @@ +package io.openems.edge.ess.power.api; + +public enum Phase { + ALL(null), L1(0), L2(2), L3(4); + + Integer offset; + + Phase(Integer offset) { + this.offset = offset; + } + + public Integer getOffset() { + return offset; + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Power.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Power.java new file mode 100644 index 00000000000..6bbf113e3ec --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Power.java @@ -0,0 +1,82 @@ +package io.openems.edge.ess.power.api; + +import org.apache.commons.math3.optim.linear.Relationship; + +import io.openems.edge.ess.api.ManagedSymmetricEss; + +public interface Power { + + /** + * Adds a Constraint. + * + * @param type + * @param constraint + */ + public Constraint addConstraint(Constraint constraint); + + /** + * Adds a Constraint using a ConstraintBuilder. Make sure to call 'build()' once + * finished. + * + * @return + */ + public default ConstraintBuilder addConstraint() { + return new ConstraintBuilder(this); + } + + /** + * Adds a Constraint if the problem is still solvable afterwards. + * + * @param type + * @param constraint + * @throws PowerException + */ + public Constraint addConstraintAndValidate(Constraint constraint) throws PowerException; + + /** + * Adds a simple constraint + * + * @param ess + * @param type + * @param phase + * @param pwr + * @param relationship + * @param value + * @return + */ + public Constraint addSimpleConstraint(ManagedSymmetricEss ess, ConstraintType type, Phase phase, Pwr pwr, + Relationship relationship, int value); + + /** + * Adds a simple constraint if the problem is still solvable afterwards. + * + * @param ess + * @param type + * @param phase + * @param pwr + * @param relationship + * @param value + * @return + * @throws PowerException + */ + public Constraint addSimpleConstraintAndValidate(ManagedSymmetricEss ess, ConstraintType type, Phase phase, Pwr pwr, + Relationship relationship, int value) throws PowerException; + + /** + * Removes a Constraint. + * + * @param type + * @param constraint + */ + public void removeConstraint(Constraint constraint); + + /** + * Gets the maximum possible total Active Power under the active Constraints. + */ + public int getMaxActivePower(); + + /** + * Gets the minimum possible total Active Power under the active Constraints. + */ + public int getMinActivePower(); +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/PowerException.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/PowerException.java new file mode 100644 index 00000000000..2d970c203c2 --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/PowerException.java @@ -0,0 +1,31 @@ +package io.openems.edge.ess.power.api; + +import org.apache.commons.math3.optim.linear.NoFeasibleSolutionException; +import org.apache.commons.math3.optim.linear.UnboundedSolutionException; + +import io.openems.common.exceptions.OpenemsException; + +public class PowerException extends OpenemsException { + + private static final long serialVersionUID = 1L; + + public enum Type { + NO_FEASIBLE_SOLUTION, UNBOUNDED_SOLUTION + } + + private final Type type; + + public PowerException(NoFeasibleSolutionException e) { + super("No Feasible Solution"); + this.type = Type.NO_FEASIBLE_SOLUTION; + } + + public PowerException(UnboundedSolutionException e) { + super("Unbounded Solution"); + this.type = Type.UNBOUNDED_SOLUTION; + } + + public Type getType() { + return type; + } +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Pwr.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Pwr.java new file mode 100644 index 00000000000..cabdf773a1b --- /dev/null +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/Pwr.java @@ -0,0 +1,15 @@ +package io.openems.edge.ess.power.api; + +public enum Pwr { + ACTIVE(0), REACTIVE(1); + + private final int offset; + + Pwr(int offset) { + this.offset = offset; + } + + public int getOffset() { + return offset; + } +} diff --git a/io.openems.backend.common/src/io/openems/backend/common/events/package-info.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/package-info.java similarity index 53% rename from io.openems.backend.common/src/io/openems/backend/common/events/package-info.java rename to io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/package-info.java index efff016e72c..9803a4cae35 100644 --- a/io.openems.backend.common/src/io/openems/backend/common/events/package-info.java +++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/package-info.java @@ -1,2 +1,2 @@ @org.osgi.annotation.versioning.Version("1.0.0") -package io.openems.backend.common.events; +package io.openems.edge.ess.power.api; diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/CosPhiLineCharacteristicLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/CosPhiLineCharacteristicLimitation.java deleted file mode 100644 index f00ca406db2..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/CosPhiLineCharacteristicLimitation.java +++ /dev/null @@ -1,89 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; -import java.util.TreeMap; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.operation.distance.DistanceOp; -import com.vividsolutions.jts.operation.distance.GeometryLocation; - -import io.openems.edge.ess.power.PowerException; - -public class CosPhiLineCharacteristicLimitation extends Limitation { - - private final TreeMap characteristic = new TreeMap<>(); - - private Geometry line = null; - private Long xNull = null; - private Long yNull = null; - - public CosPhiLineCharacteristicLimitation(SymmetricPower power) { - super(power); - } - - public CosPhiLineCharacteristicLimitation setCosPhi(Long xNull, Long yNull, TreeMap characteristic) { - if (this.characteristic.equals(characteristic) || this.xNull != xNull || this.yNull != yNull) { - if (characteristic != null && !characteristic.isEmpty() && xNull != null && yNull != null) { - long maxApparentPower = this.power.getMaxApparentPower(); - boolean isFirs = true; - List coordinates = new ArrayList<>(); - Double y = null; - for (Entry point : characteristic.entrySet()) { - double cosPhi = point.getValue(); - double m = Math.tan(Math.acos(Math.abs(cosPhi))); - double x = point.getKey(); - double t = yNull - m * xNull; - if ((x < 0 && cosPhi > 0) || (x > 0 && cosPhi > 0)) { - m *= -1; - } - y = m * x + t; - if (isFirs) { - coordinates.add(new Coordinate(maxApparentPower * -1, y)); - isFirs = false; - } - coordinates.add(new Coordinate(x, y)); - } - if (y != null) { - coordinates.add(new Coordinate(maxApparentPower, y)); - } - this.line = Utils.FACTORY.createLineString(coordinates.toArray(new Coordinate[coordinates.size()])); - } else { - this.line = null; - } - this.characteristic.clear(); - this.characteristic.putAll(characteristic); - this.xNull = xNull; - this.yNull = yNull; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - protected Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.line != null) { - Geometry newGeometry = geometry.intersection(this.line); - if (newGeometry.isEmpty()) { - DistanceOp distance = new DistanceOp(geometry, this.line); - GeometryLocation[] locations = distance.nearestLocations(); - for (GeometryLocation location : locations) { - if (!location.getGeometryComponent().equals(this.line)) { - return Utils.FACTORY.createPoint(location.getCoordinate()); - } - } - } else { - return newGeometry; - } - } - return geometry; - } - - @Override - public String toString() { - return "CosPhiLineCharacteristicLimitation [x=" + xNull + ", y=" + yNull + "]"; - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/CosPhiLineLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/CosPhiLineLimitation.java deleted file mode 100644 index a95e2dc79c4..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/CosPhiLineLimitation.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.operation.distance.DistanceOp; -import com.vividsolutions.jts.operation.distance.GeometryLocation; - -import io.openems.edge.ess.power.PowerException; - -/** - * Active- and ReactivePower have to be on cosPhi - * - */ -public class CosPhiLineLimitation extends Limitation { - - private Geometry line = null; - private Double cosPhi = null; - private Boolean capacitive = null; - private Integer xNull = null; - private Integer yNull = null; - - public CosPhiLineLimitation(SymmetricPower power) { - super(power); - } - - /** - * Defines the limitation - * - * @param cosPhi - * the cosPhi - * @param capacitive - * is 'inductive' or 'capacitive'? - * @param xNull - * base x coordinate - * @param yNull - * base y coordinate - * @return - */ - public CosPhiLineLimitation setCosPhi(Double cosPhi, Boolean capacitive, Integer xNull, Integer yNull) { - if (this.cosPhi != cosPhi || this.capacitive != capacitive || this.xNull != xNull || this.yNull != yNull) { - if (cosPhi != null && capacitive != null && xNull != null && yNull != null) { - long maxApparentPower = power.getMaxApparentPower(); - double m1 = Math.tan(Math.acos(Math.abs(cosPhi))); - if (capacitive) { - m1 *= -1; - } - double m2 = m1 * -1; - double t1 = yNull - m1 * xNull; - double t2 = yNull - m2 * xNull; - double y1 = m1 * maxApparentPower + t1; - double y2 = m2 * maxApparentPower * -1 + t2; - Coordinate[] coordinates = new Coordinate[] { new Coordinate(maxApparentPower, y1), - new Coordinate(xNull, yNull), new Coordinate(maxApparentPower * -1, y2) }; - line = Utils.FACTORY.createLineString(coordinates); - } else { - line = null; - } - this.cosPhi = cosPhi; - this.capacitive = capacitive; - this.xNull = xNull; - this.yNull = yNull; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - protected Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.line != null) { - Geometry newGeometry = geometry.intersection(this.line); - if (newGeometry.isEmpty()) { - DistanceOp distance = new DistanceOp(geometry, this.line); - GeometryLocation[] locations = distance.nearestLocations(); - for (GeometryLocation location : locations) { - if (!location.getGeometryComponent().equals(this.line)) { - return Utils.FACTORY.createPoint(location.getCoordinate()); - } - } - } else { - return newGeometry; - } - } - return geometry; - } - - @Override - public String toString() { - return "CosPhiLineLimitation [cosPhi=" + cosPhi + " " + (capacitive ? "inductive" : "capacitive") + ", x=" - + xNull + ", y=" + yNull + "]"; - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/EssSymmetricPowerManager.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/EssSymmetricPowerManager.java deleted file mode 100644 index 040acc287d8..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/EssSymmetricPowerManager.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.osgi.service.component.annotations.ReferencePolicyOption; -import org.osgi.service.component.annotations.ServiceScope; -import org.osgi.service.event.Event; -import org.osgi.service.event.EventConstants; -import org.osgi.service.event.EventHandler; - -import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.ess.symmetric.api.SymmetricEss; - -/** - * This helper component handles the ControllerExecuter Cycle for SymmetricPower - * objects. - * - * @author stefan.feilmeier - */ -@Component(scope = ServiceScope.SINGLETON, property = { // - EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_WRITE, - EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE }) -public class EssSymmetricPowerManager implements EventHandler { - - @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) - private volatile List components = new CopyOnWriteArrayList<>(); - - @Override - public void handleEvent(Event event) { - for (SymmetricEss component : this.components) { - SymmetricPower power = component.getPower(); - switch (event.getTopic()) { - case EdgeEventConstants.TOPIC_CYCLE_BEFORE_WRITE: - power.onTopicCycleBeforeWrite(); - break; - case EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE: - power.onTopicCycleAfterWrite(); - break; - } - } - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/Limitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/Limitation.java deleted file mode 100644 index 2ab1be70edc..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/Limitation.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; - -import io.openems.edge.ess.power.PowerException; - -public abstract class Limitation { - - protected static final Coordinate ZERO = new Coordinate(0, 0); - - protected final SymmetricPower power; - - private final List onChangeCallbacks = new CopyOnWriteArrayList<>(); - - public Limitation(SymmetricPower power) { - this.power = power; - } - - protected void emitOnChangeEvent() { - for (Runnable callback : this.onChangeCallbacks) { - callback.run(); - } - } - - public Limitation onChange(Runnable callback) { - this.onChangeCallbacks.add(callback); - return this; - } - - protected abstract Geometry applyLimit(Geometry geometry) throws PowerException; - - @Override - public abstract String toString(); -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/MaxCosPhiLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/MaxCosPhiLimitation.java deleted file mode 100644 index 5493b0f47d3..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/MaxCosPhiLimitation.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; - -import io.openems.edge.ess.power.PowerException; - -/** - * Power has to be between CosPhi inductive and capacitive - * - */ -public class MaxCosPhiLimitation extends Limitation { - - private Geometry polygon = null; - private Double cosPhi = null; - - public MaxCosPhiLimitation(SymmetricPower power) { - super(power); - } - - public MaxCosPhiLimitation setMaxCosPhi(Double cosPhi) { - if (cosPhi != this.cosPhi) { - if (cosPhi != null) { - int maxApparentPower = this.power.getMaxApparentPower(); - double m = Math.tan(Math.acos(cosPhi)); - double y = m * maxApparentPower; - Coordinate[] coordinates = new Coordinate[] { new Coordinate(ZERO), new Coordinate(maxApparentPower, y), - new Coordinate(maxApparentPower, y * -1), new Coordinate(ZERO), - new Coordinate(maxApparentPower * -1, y * -1), new Coordinate(maxApparentPower * -1, y), - new Coordinate(ZERO) }; - this.polygon = Utils.FACTORY.createPolygon(coordinates); - } else { - this.polygon = null; - } - this.cosPhi = cosPhi; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - public Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.polygon != null) { - Geometry newGeometry = geometry.intersection(this.polygon); - if (newGeometry.isEmpty()) { - throw new PowerException("MaxCosPhiLimitation [CosPhi <= " + this.cosPhi - + "] is too restrictive! There needs to be at least one point after the limitation."); - } - return newGeometry; - } - return geometry; - } - - @Override - public String toString() { - return "MaxCosPhiLimitation [polygon=" + polygon + ", cosPhi=" + cosPhi + "]"; - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/NoPBetweenLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/NoPBetweenLimitation.java deleted file mode 100644 index f7c98b5b41f..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/NoPBetweenLimitation.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; - -import io.openems.edge.ess.power.PowerException; - -/** - * Do not allow ActivePower between two values - */ -public class NoPBetweenLimitation extends Limitation { - - private Geometry rect = null; - private Integer pMin = null; - private Integer pMax = null; - - public NoPBetweenLimitation(SymmetricPower power) { - super(power); - } - - public NoPBetweenLimitation setP(Integer pMin, Integer pMax) { - if (pMin != this.pMin || pMax != this.pMax) { - if (pMin != null && pMax != null) { - long qMin = power.getMaxApparentPower() * -1; - long qMax = power.getMaxApparentPower(); - Coordinate[] coordinates = new Coordinate[] { new Coordinate(pMin + 0.1, qMax), - new Coordinate(pMin + 0.1, qMin), new Coordinate(pMax - 0.1, qMin), - new Coordinate(pMax - 0.1, qMax), new Coordinate(pMin + 0.1, qMax) }; - this.rect = Utils.FACTORY.createPolygon(coordinates); - } else { - this.rect = null; - } - this.pMin = pMin; - this.pMax = pMax; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - protected Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.rect != null) { - Geometry newGeometry = geometry.difference(this.rect); - if (newGeometry.isEmpty()) { - throw new PowerException("NoPBetweenLimitation [p < " + this.pMin + " || p > " + this.pMax - + "] is too restrictive! There needs to be at least one point after the limitation."); - } - return newGeometry; - } - return geometry; - } - - @Override - public String toString() { - return "NoPBetweenLimitation [pMin=" + pMin + ", pMax=" + pMax + "]"; - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/NoQBetweenLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/NoQBetweenLimitation.java deleted file mode 100644 index 2940c5fadf7..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/NoQBetweenLimitation.java +++ /dev/null @@ -1,59 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; - -import io.openems.edge.ess.power.PowerException; - -/** - * Do not allow ReactivePower between two values - * - */ -public class NoQBetweenLimitation extends Limitation { - - private Geometry rect = null; - private Integer qMin = null; - private Integer qMax = null; - - public NoQBetweenLimitation(SymmetricPower power) { - super(power); - } - - public NoQBetweenLimitation setQ(Integer qMin, Integer qMax) { - if (qMin != this.qMin || qMax != this.qMax) { - if (qMin != null && qMax != null) { - long pMin = power.getMaxApparentPower() * -1; - long pMax = power.getMaxApparentPower(); - Coordinate[] coordinates = new Coordinate[] { new Coordinate(pMin, qMax - 0.1), - new Coordinate(pMin, qMin + 0.1), new Coordinate(pMax, qMin + 0.1), - new Coordinate(pMax, qMax - 0.1), new Coordinate(pMin, qMax - 0.1) }; - this.rect = Utils.FACTORY.createPolygon(coordinates); - } else { - this.rect = null; - } - this.qMin = qMin; - this.qMax = qMax; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - protected Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.rect != null) { - Geometry newGeometry = geometry.difference(this.rect); - if (newGeometry.isEmpty()) { - throw new PowerException("NoQBetweenLimitation [q < " + this.qMin + " || q > " + this.qMax - + "] is too restrictive! There needs to be at least one point after the limitation."); - } - return newGeometry; - } - return geometry; - } - - @Override - public String toString() { - return "NoQBetweenLimitation [qMin=" + qMin + ", qMax=" + qMax + "]"; - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PEqualLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PEqualLimitation.java deleted file mode 100644 index bb4a3878bf0..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PEqualLimitation.java +++ /dev/null @@ -1,94 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.operation.distance.DistanceOp; -import com.vividsolutions.jts.operation.distance.GeometryLocation; - -import io.openems.common.exceptions.OpenemsException; -import io.openems.edge.ess.power.PowerException; - -public class PEqualLimitation extends Limitation { - - private Geometry line = null; - private Integer p = null; - - public PEqualLimitation(SymmetricPower power) { - super(power); - } - - /** - * Sets the ActivePower - * - * @param value - * - *
            -	 *            < 0 (negative) = Charge
            -	 *            > 0 (positive) = Discharge
            -	 *            
            - * - * @throws OpenemsException - */ - public PEqualLimitation setP(Integer p) { - if (p != this.p) { - if (p != null) { - Coordinate[] coordinates = new Coordinate[] { new Coordinate(p, power.getMaxApparentPower()), - new Coordinate(p, power.getMaxApparentPower() * -1) }; - this.line = Utils.FACTORY.createLineString(coordinates); - } else { - this.line = null; - } - // store P so the line does not need to be recalculated if P is not changed - this.p = p; - this.emitOnChangeEvent(); - } - return this; - - } - - @Override - protected Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.line != null) { - Geometry newGeometry = geometry.intersection(this.line); - long maxApparentPower = power.getMaxApparentPower(); - if (newGeometry.isEmpty()) { - Geometry smallerP = Utils.intersectRect(geometry, 0, p, maxApparentPower * -1, maxApparentPower); - if (!smallerP.isEmpty()) { - DistanceOp distance = new DistanceOp(smallerP, this.line); - GeometryLocation[] locations = distance.nearestLocations(); - long maxP = 0; - for (GeometryLocation location : locations) { - if (!location.getGeometryComponent().equals(this.line)) { - maxP = (long) location.getCoordinate().x; - break; - } - } - // apply new temporary line - Coordinate[] coordinates = new Coordinate[] { new Coordinate(maxP, maxApparentPower), - new Coordinate(maxP, maxApparentPower * -1) }; - return geometry.intersection(Utils.FACTORY.createLineString(coordinates)); - } else { - DistanceOp distance = new DistanceOp(geometry, this.line); - GeometryLocation[] locations = distance.nearestLocations(); - for (GeometryLocation location : locations) { - if (!location.getGeometryComponent().equals(this.line)) { - Coordinate[] coordinates = new Coordinate[] { - new Coordinate(location.getCoordinate().x, maxApparentPower), - new Coordinate(location.getCoordinate().x, maxApparentPower * -1) }; - // apply new temporary line - return geometry.intersection(Utils.FACTORY.createLineString(coordinates)); - } - } - } - } else { - return newGeometry; - } - } - return geometry; - } - - @Override - public String toString() { - return "PEqualLimitation [p=" + p + "]"; - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PGreaterEqualLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PGreaterEqualLimitation.java deleted file mode 100644 index c9a407ba410..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PGreaterEqualLimitation.java +++ /dev/null @@ -1,55 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; - -import io.openems.edge.ess.power.PowerException; - -public class PGreaterEqualLimitation extends Limitation { - - private Geometry rect = null; - private Integer p = null; - - public PGreaterEqualLimitation(SymmetricPower power) { - super(power); - } - - public PGreaterEqualLimitation setP(Integer p) { - if (p == this.p || (p != null && p.equals(this.p))) { - return this; - } - - if (p != null) { - long pMin = p - 1; - long pMax = power.getMaxApparentPower() + 1; - long qMin = power.getMaxApparentPower() * -1 - 1; - long qMax = power.getMaxApparentPower() + 1; - Coordinate[] coordinates = new Coordinate[] { new Coordinate(pMin, qMax), new Coordinate(pMin, qMin), - new Coordinate(pMax, qMin), new Coordinate(pMax, qMax), new Coordinate(pMin, qMax) }; - this.rect = Utils.FACTORY.createPolygon(coordinates); - } else { - this.rect = null; - } - this.p = p; - this.emitOnChangeEvent(); - return this; - } - - @Override - public Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.rect != null) { - Geometry newGeometry = geometry.intersection(this.rect); - if (newGeometry.isEmpty()) { - throw new PowerException("PGreaterEqualLimitation [p >= " + this.p - + "] is too restrictive! There needs to be at least one point after the limitation."); - } - return newGeometry; - } - return geometry; - } - - @Override - public String toString() { - return "PGreaterEqualLimitation [p=" + p + "]"; - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PSmallerEqualLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PSmallerEqualLimitation.java deleted file mode 100644 index 722856af9ae..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/PSmallerEqualLimitation.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.geom.Geometry; - -import io.openems.edge.ess.power.PowerException; - -public class PSmallerEqualLimitation extends Limitation { - - private Geometry rect = null; - private Integer p = null; - - public PSmallerEqualLimitation(SymmetricPower power) { - super(power); - } - - public PSmallerEqualLimitation setP(Integer p) { - if (p == this.p || (p != null && p.equals(this.p))) { - return this; - } - - if (p != null) { - long pMin = power.getMaxApparentPower() * -1 - 1; - long pMax = p + 1; - long qMin = power.getMaxApparentPower() * -1 - 1; - long qMax = power.getMaxApparentPower() + 1; - this.rect = Utils.FACTORY.toGeometry(new Envelope(pMin, pMax, qMin, qMax)); - } else { - this.rect = null; - } - this.p = p; - this.emitOnChangeEvent(); - return this; - } - - @Override - public Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.rect != null) { - Geometry newGeometry = geometry.intersection(this.rect); - if (newGeometry.isEmpty()) { - throw new PowerException("PSmallerEqualLimitation [p <= " + this.p - + "] is too restrictive! There needs to be at least one point after the limitation."); - } - return newGeometry; - } - return geometry; - } - - @Override - public String toString() { - return "PSmallerEqualLimitation [p=" + p + "]"; - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QEqualLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QEqualLimitation.java deleted file mode 100644 index 28fcc2b6bf4..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QEqualLimitation.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.operation.distance.DistanceOp; -import com.vividsolutions.jts.operation.distance.GeometryLocation; - -import io.openems.edge.ess.power.PowerException; - -public class QEqualLimitation extends Limitation { - - private Geometry line = null; - private Integer q = null; - - public QEqualLimitation(SymmetricPower power) { - super(power); - } - - public QEqualLimitation setQ(Integer q) { - if (q != this.q) { - if (q != null) { - Coordinate[] coordinates = new Coordinate[] { new Coordinate(power.getMaxApparentPower(), q), - new Coordinate(power.getMaxApparentPower() * -1, q) }; - this.line = Utils.FACTORY.createLineString(coordinates); - } else { - this.line = null; - } - this.q = q; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - protected Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.line != null) { - Geometry newGeometry = geometry.intersection(this.line); - long maxApparentPower = power.getMaxApparentPower(); - if (newGeometry.isEmpty()) { - Geometry smallerQ = Utils.intersectRect(geometry, maxApparentPower * -1, maxApparentPower, 0, q); - if (!smallerQ.isEmpty()) { - DistanceOp distance = new DistanceOp(smallerQ, this.line); - GeometryLocation[] locations = distance.nearestLocations(); - long maxQ = 0; - for (GeometryLocation location : locations) { - if (!location.getGeometryComponent().equals(this.line)) { - maxQ = (long) location.getCoordinate().y; - break; - } - } - Coordinate[] coordinates = new Coordinate[] { new Coordinate(maxApparentPower, maxQ), - new Coordinate(maxApparentPower * -1, maxQ) }; - // apply new temporary line - return geometry.intersection(Utils.FACTORY.createLineString(coordinates)); - } else { - DistanceOp distance = new DistanceOp(geometry, this.line); - GeometryLocation[] locations = distance.nearestLocations(); - for (GeometryLocation location : locations) { - if (!location.getGeometryComponent().equals(this.line)) { - Coordinate[] coordinates = new Coordinate[] { - new Coordinate(maxApparentPower, location.getCoordinate().y), - new Coordinate(maxApparentPower * -1, location.getCoordinate().y) }; - // apply new temporary line - return geometry.intersection(Utils.FACTORY.createLineString(coordinates)); - } - } - } - } else { - return newGeometry; - } - } - return geometry; - } - - @Override - public String toString() { - return "QEqualLimitation [q=" + q + "]"; - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QGreaterEqualLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QGreaterEqualLimitation.java deleted file mode 100644 index 020c509e70a..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QGreaterEqualLimitation.java +++ /dev/null @@ -1,54 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; - -import io.openems.edge.ess.power.PowerException; - -public class QGreaterEqualLimitation extends Limitation { - - private Geometry rect = null; - private Integer q = null; - - public QGreaterEqualLimitation(SymmetricPower power) { - super(power); - } - - public QGreaterEqualLimitation setQ(Integer q) { - if (q != this.q) { - if (q != null) { - long pMin = power.getMaxApparentPower() * -1 - 1; - long pMax = power.getMaxApparentPower() + 1; - long qMin = q; - long qMax = power.getMaxApparentPower() + 1; - Coordinate[] coordinates = new Coordinate[] { new Coordinate(pMin, qMax), new Coordinate(pMin, qMin), - new Coordinate(pMax, qMin), new Coordinate(pMax, qMax), new Coordinate(pMin, qMax) }; - this.rect = Utils.FACTORY.createPolygon(coordinates); - } else { - this.rect = null; - } - this.q = q; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - public Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.rect != null) { - Geometry newGeometry = geometry.intersection(this.rect); - if (newGeometry.isEmpty()) { - throw new PowerException("QGreaterEqualLimitation [q >= " + this.q - + "] is too restrictive! There needs to be at least one point after the limitation."); - } - return newGeometry; - } - return geometry; - } - - @Override - public String toString() { - return "QGreaterEqualLimitation [q=" + q + "]"; - } - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QSmallerEqualLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QSmallerEqualLimitation.java deleted file mode 100644 index cf929b2e0af..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/QSmallerEqualLimitation.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; - -import io.openems.edge.ess.power.PowerException; - -public class QSmallerEqualLimitation extends Limitation { - - private Geometry rect = null; - private Integer q = null; - - public QSmallerEqualLimitation(SymmetricPower power) { - super(power); - } - - public QSmallerEqualLimitation setQ(Integer q) { - if (q != this.q) { - if (q != null) { - long pMin = power.getMaxApparentPower() * -1 - 1; - long pMax = power.getMaxApparentPower() + 1; - long qMin = power.getMaxApparentPower() * -1 - 1; - long qMax = q; - Coordinate[] coordinates = new Coordinate[] { new Coordinate(pMin, qMax), new Coordinate(pMin, qMin), - new Coordinate(pMax, qMin), new Coordinate(pMax, qMax), new Coordinate(pMin, qMax) }; - rect = Utils.FACTORY.createPolygon(coordinates); - } else { - this.rect = null; - } - this.q = q; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - public Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.rect != null) { - Geometry newGeometry = geometry.intersection(this.rect); - if (newGeometry.isEmpty()) { - throw new PowerException("QSmallerEqualLimitation [q <= " + this.q - + "] is too restrictive! There needs to be at least one point after the limitation."); - } - return newGeometry; - } - return geometry; - } - - @Override - public String toString() { - return "QSmallerEqualLimitation [q=" + q + "]"; - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/SMaxLimitation.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/SMaxLimitation.java deleted file mode 100644 index cc6a1d17a0c..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/SMaxLimitation.java +++ /dev/null @@ -1,56 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.util.GeometricShapeFactory; - -import io.openems.edge.ess.power.PowerException; - -public class SMaxLimitation extends Limitation { - - private Geometry circle = null; - private Integer sMax = null; - - public SMaxLimitation(SymmetricPower power) { - super(power); - } - - public SMaxLimitation setSMax(Integer sMax, int xNull, int yNull) { - if (sMax != this.sMax) { - if (sMax == null) { - this.circle = null; - - } else if (sMax == 0) { - this.circle = Utils.FACTORY.createPoint(new Coordinate(xNull, yNull)); - - } else { - GeometricShapeFactory shapeFactory = new GeometricShapeFactory(Utils.FACTORY); - shapeFactory.setCentre(new Coordinate(xNull, yNull)); - shapeFactory.setSize(sMax * 2); - shapeFactory.setNumPoints(32); - this.circle = shapeFactory.createCircle(); - } - this.sMax = sMax; - this.emitOnChangeEvent(); - } - return this; - } - - @Override - public Geometry applyLimit(Geometry geometry) throws PowerException { - if (this.circle != null) { - Geometry newGeometry = geometry.intersection(this.circle); - if (newGeometry.isEmpty()) { - throw new PowerException("SMaxLimitation [ApparentPower <= " + this.sMax - + "] is too restrictive! There needs to be at least one point after the limitation."); - } - return newGeometry; - } - return geometry; - } - - @Override - public String toString() { - return "SMaxLimitation [sMax=" + sMax + "]"; - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/SymmetricPower.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/SymmetricPower.java deleted file mode 100644 index 2d9ca41c07a..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/SymmetricPower.java +++ /dev/null @@ -1,352 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.function.BiConsumer; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.Point; -import com.vividsolutions.jts.operation.distance.DistanceOp; -import com.vividsolutions.jts.operation.distance.GeometryLocation; -import com.vividsolutions.jts.util.GeometricShapeFactory; - -import io.openems.common.utils.IntUtils; -import io.openems.common.utils.IntUtils.Round; -import io.openems.edge.ess.power.PowerException; -import io.openems.edge.ess.symmetric.api.SymmetricEss; - -public class SymmetricPower { - - private final Logger log = LoggerFactory.getLogger(SymmetricPower.class); - private final SymmetricEss parent; - private final int powerPrecision; - private final List geometries; - private final BiConsumer onWriteListener; - - private Geometry geometry; - private Optional minP; - private Optional maxP; - private Optional minQ; - private Optional maxQ; - private int maxApparentPower = 0; - - /** - * Initialises the SymmetricPower Object - * - * @param parent - * the OpenemsComponent that implements SymmetricEss - * @param maxApparentPower - * max apparent power in [VA] of the battery inverter - * @param powerPrecision - * the precision of power that can be handled by the inverter. - * Example: if this parameter is '100' it shows that the inverter is - * only capable to handle a precision of 100 W - and not 50 W. The - * onWriteListener is called with an appropriately rounded value for - * active and reactive power. - * @param onWriteListener - * callback for setting active and reactive power - */ - public SymmetricPower(SymmetricEss parent, int maxApparentPower, int powerPrecision, - BiConsumer onWriteListener) { - if (maxApparentPower < 0) { - throw new IllegalArgumentException("MaxApprentPower [" + maxApparentPower + "] must be positive!"); - } - this.parent = parent; - this.powerPrecision = powerPrecision; - this.maxApparentPower = maxApparentPower; - this.geometries = new ArrayList<>(); - this.onWriteListener = onWriteListener; - - createBaseGeometry(); - reset(); - } - - /** - * Returns the maximum possible ApparentPower - * - * @return - */ - public int getMaxApparentPower() { - return this.maxApparentPower; - } - - public Geometry getGeometry() { - return this.geometry; - } - - /** - * updates the geometry, calculates the min and max power and notifies all - * powerChangedListener - * - * @param g - * @throws PowerException - */ - private void setGeometry(Geometry g) throws PowerException { - if (g.isEmpty()) { - throw new PowerException("Geometry is Empty!"); - } - this.geometry = g; - this.geometries.add(g); - this.calculateMinMax(); - } - - /** - * Calculates the min and max active and reactivePower possible in the geometry. - */ - private void calculateMinMax() { - this.maxP = getClosestP(maxApparentPower); - this.minP = getClosestP(maxApparentPower * -1); - this.maxQ = getClosestQ(maxApparentPower); - this.minQ = getClosestQ(maxApparentPower * -1); - } - - /** - * Calculates the closest ActivePower point to the parameter p - * - * @param p - * @return - */ - private Optional getClosestP(int p) { - Coordinate[] coordinates = new Coordinate[] { new Coordinate(p, this.maxApparentPower), - new Coordinate(p, this.maxApparentPower * -1) }; - LineString line = Utils.FACTORY.createLineString(coordinates); - DistanceOp distance = new DistanceOp(this.geometry, line); - GeometryLocation[] locations = distance.nearestLocations(); - for (GeometryLocation location : locations) { - if (!location.getGeometryComponent().equals(line)) { - return Optional.of((int) Math.round(location.getCoordinate().x)); - } - } - return Optional.empty(); - } - - /** - * Calculates the closest ReactivePower point to the parameter q - * - * @param p - * @return - */ - private Optional getClosestQ(int q) { - Coordinate[] coordinates = new Coordinate[] { new Coordinate(this.maxApparentPower, q), - new Coordinate(this.maxApparentPower * -1, q) }; - LineString line = Utils.FACTORY.createLineString(coordinates); - DistanceOp distance = new DistanceOp(this.geometry, line); - GeometryLocation[] locations = distance.nearestLocations(); - for (GeometryLocation location : locations) { - if (!location.getGeometryComponent().equals(line)) { - return Optional.of((int) Math.round(location.getCoordinate().y)); - } - } - return Optional.empty(); - } - - /** - * Returns the max ActivePower, after all limitations applied. - * - * @return - */ - public Optional getMaxP() { - return this.maxP; - } - - /** - * Returns the min ActivePower, after all limitations applied. - * - * @return - */ - public Optional getMinP() { - return this.minP; - } - - /** - * Returns the max ReactivePower, after all limitations applied. - * - * @return - */ - public Optional getMaxQ() { - return this.maxQ; - } - - /** - * Returns the min RectivePower, after all limitations applied. - * - * @return - */ - public Optional getMinQ() { - return this.minQ; - } - - protected void reset() { - this.dynamicLimitations.clear(); - try { - this.setGeometry(baseGeometry); - } catch (PowerException e) { - log.error("BaseGeometry is Empty!"); - } - this.geometries.clear(); - this.geometries.add(this.geometry); - } - - protected Point reduceToZero() { - if (this.geometries instanceof Point) { - return (Point) this.geometry; - } - Point pZero = Utils.FACTORY.createPoint(Utils.ZERO); - DistanceOp distance = new DistanceOp(this.geometry, pZero); - GeometryLocation[] locations = distance.nearestLocations(); - Point result = pZero; - for (GeometryLocation location : locations) { - Geometry g = location.getGeometryComponent(); - if (!g.equals(pZero)) { - result = Utils.FACTORY.createPoint(location.getCoordinate()); - break; - } - } - return result; - } - - private Geometry baseGeometry; - private final List staticLimitations = new ArrayList<>(); - private final List dynamicLimitations = new ArrayList<>(); - private int lastActivePower = 0; - private int lastReactivePower = 0; - - public void addStaticLimitation(Limitation limit) { - this.staticLimitations.add(limit); - limit.onChange(() -> { - // recalculate base geometry on change of static limitation - this.createBaseGeometry(); - }); - createBaseGeometry(); - } - - /** - * Applies a limit to the current power representing polygon. - * - * @param limit - * the Limitation implementation to apply - * @throws PowerException - * this Exception is thrown if the result is empty - */ - public void applyLimitation(Limitation limit) throws PowerException { - Geometry limitedPower = limit.applyLimit(this.geometry); - if (!limitedPower.isEmpty()) { - setGeometry(limitedPower); - this.dynamicLimitations.add(limit); - } else { - throw new PowerException("No possible Power after applying Limit. Limit is not applied!"); - } - } - - protected void writePower() { - // } - if (!this.dynamicLimitations.isEmpty()) { - Point p = this.reduceToZero(); - Coordinate c = p.getCoordinate(); - try { - this.setGeometry(p); - } catch (PowerException e1) { - } - /* - * Avoid extreme changes in active/reactive power - * - * calculate the delta between last set power and current calculation and apply - * it only partly - */ - int activePowerDelta = (int) c.x - this.lastActivePower + 1 /* add 1 to avoid rounding issues */; - int reactivePowerDelta = (int) c.y - this.lastReactivePower + 1 /* add 1 to avoid rounding issues */; - int activePower = this.lastActivePower + activePowerDelta / 2; - int reactivePower = this.lastReactivePower + reactivePowerDelta / 2; - /** - * round values to required accuracy by inverter; following this logic: - * - * On Discharge (Power > 0) - * - *
              - *
            • if SoC > 50 %: round up (more discharge) - *
            • if SoC < 50 %: round down (less discharge) - *
            - * - * On Charge (Power < 0) - * - *
              - *
            • if SoC > 50 %: round down (less charge) - *
            • if SoC < 50 %: round up (more discharge) - *
            - */ - Round round = Round.DOWN; - Optional socOpt = this.parent.getSoc().value().asOptional(); - if (socOpt.isPresent()) { - int soc = socOpt.get(); - if (activePower > 0 && soc > 50 || activePower < 0 && soc < 50) { - round = Round.UP; - } - } - activePower = IntUtils.roundToPrecision(activePower, round, powerPrecision); - reactivePower = IntUtils.roundToPrecision(reactivePower, round, powerPrecision); - - // set debug channels on parent - this.parent.channel(SymmetricEss.ChannelId.DEBUG_SET_ACTIVE_POWER).setNextValue(activePower); - this.parent.channel(SymmetricEss.ChannelId.DEBUG_SET_REACTIVE_POWER).setNextValue(reactivePower); - - // call listener - this.onWriteListener.accept(activePower, reactivePower); - - // store for next call - this.lastActivePower = activePower; - this.lastReactivePower = reactivePower; - } - } - - private void createBaseGeometry() { - GeometricShapeFactory shapeFactory = new GeometricShapeFactory(Utils.FACTORY); - shapeFactory.setCentre(Utils.ZERO); - shapeFactory.setSize(this.maxApparentPower * 2); - shapeFactory.setNumPoints(20); - this.baseGeometry = shapeFactory.createCircle(); - for (Limitation limit : this.staticLimitations) { - try { - Geometry limitedPower = limit.applyLimit(this.baseGeometry); - if (!limitedPower.isEmpty()) { - this.baseGeometry = limitedPower; - } else { - log.error("Power is empty after applying Limit. " + limit.toString()); - } - } catch (PowerException e) { - log.error("Failed to limit Power: " + e.getMessage()); - } - } - } - - /** - * This is executed by {@link EssSymmetricPowerManager} on - * TOPIC_CYCLE_BEFORE_WRITE event - */ - protected void onTopicCycleBeforeWrite() { - this.writePower(); - } - - /** - * This is executed by {@link EssSymmetricPowerManager} on - * TOPIC_CYCLE_AFTER_WRITE event - */ - protected void onTopicCycleAfterWrite() { - this.reset(); - } - - /** - * Output the geometries as SVG - * - * @return - */ - public String getAsSVG() { - return Utils.getAsSVG(this.maxApparentPower * -1, this.maxApparentPower * -1, this.maxApparentPower, - this.maxApparentPower, this.geometries.toArray(new Geometry[this.geometries.size()])); - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/Utils.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/Utils.java deleted file mode 100644 index bff619d5abf..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/symmetric/Utils.java +++ /dev/null @@ -1,81 +0,0 @@ -package io.openems.edge.ess.power.symmetric; - -import java.awt.Color; - -import com.vividsolutions.jts.geom.Coordinate; -import com.vividsolutions.jts.geom.Envelope; -import com.vividsolutions.jts.geom.Geometry; -import com.vividsolutions.jts.geom.GeometryFactory; - -import io.openems.edge.ess.power.SVGWriter; - -public class Utils { - - protected final static GeometryFactory FACTORY = new GeometryFactory(); - - protected static final SVGWriter writer = new SVGWriter(); - protected static final Color[] COLORS = new Color[] { Color.GREEN, Color.BLUE, Color.MAGENTA, Color.YELLOW, - Color.ORANGE, Color.RED }; - protected static final Coordinate ZERO = new Coordinate(0, 0); - - /** - * Creates a Rect with the coordinates pMin, pMax, qMin, qMax and intersects the - * rect with the base geometry. - * - * @param base - * @param pMin - * @param pMax - * @param qMin - * @param qMax - * @return resulting polygon after the intersection - */ - public static Geometry intersectRect(Geometry base, double pMin, double pMax, double qMin, double qMax) { - Coordinate[] coordinates = new Coordinate[] { new Coordinate(pMin, qMax), new Coordinate(pMin, qMin), - new Coordinate(pMax, qMin), new Coordinate(pMax, qMax), new Coordinate(pMin, qMax) }; - Geometry rect = new GeometryFactory().createPolygon(coordinates); - return base.intersection(rect); - } - - public static String getAsSVG(long viewBoxMinX, long viewBoxMinY, long viewBoxMaxX, long viewBoxMaxY, - Geometry... geometries) { - String viewBox = viewBoxMinX + " " + viewBoxMinY + " " + viewBoxMaxX * 2 + " " + viewBoxMaxY * 2; - - StringBuilder b = new StringBuilder(); - b.append("\n"); - b.append( - "\n"); - b.append("\n"); - int i = 0; - for (Geometry geo : geometries) { - String color = "#" + Integer.toHexString(Utils.COLORS[i].getRGB()).substring(2); - String a = Utils.writeGeometryStyled(geo, color, color); - b.append(a + "\n"); - b.append("\n"); - i++; - i %= Utils.COLORS.length; - } - b.append("\n"); - return b.toString(); - } - - public static String getAsSVG(Geometry geometry) { - Envelope env = geometry.getEnvelopeInternal(); - return Utils.getAsSVG(Math.round(env.getMinX()), Math.round(env.getMinY()), Math.round(env.getMaxX()), - Math.round(env.getMaxY()), geometry); - } - - protected static String writeGeometryStyled(Geometry g, String fillClr, String strokeClr) { - String s = "\n"; - s += write(g); - s += ""; - return s; - } - - private static String write(Geometry geometry) { - if (geometry == null) { - return ""; - } - return Utils.writer.write(geometry); - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/api/SymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/api/SymmetricEss.java deleted file mode 100644 index 8fe3b48d8cb..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/api/SymmetricEss.java +++ /dev/null @@ -1,62 +0,0 @@ -package io.openems.edge.ess.symmetric.api; - -import org.osgi.annotation.versioning.ProviderType; - -import io.openems.common.types.OpenemsType; -import io.openems.edge.common.channel.doc.Doc; -import io.openems.edge.common.channel.doc.Unit; -import io.openems.edge.ess.power.symmetric.SymmetricPower; -import io.openems.edge.ess.symmetric.readonly.api.SymmetricEssReadonly; - -@ProviderType -public interface SymmetricEss extends SymmetricEssReadonly { - - public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { - /** - * Holds settings of Active Power for debugging - * - *
              - *
            • Interface: Symmetric Ess - *
            • Type: Integer - *
            • Unit: W - *
            • Range: negative values for Charge; positive for Discharge - *
            • Implementation Note: value is automatically written by SymmetricPower - * just before it calls the onWriteListener (which writes the value to the Ess) - *
            - */ - DEBUG_SET_ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Holds settings of Reactive Power for debugging - * - *
              - *
            • Interface: Symmetric Ess - *
            • Type: Integer - *
            • Unit: var - *
            • Range: negative values for Charge; positive for Discharge - *
            • Implementation Note: value is automatically written by SymmetricPower - * just before it calls the onWriteListener (which writes the value to the Ess) - *
            - */ - DEBUG_SET_REACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - ; - - private final Doc doc; - - private ChannelId(Doc doc) { - this.doc = doc; - } - - public Doc doc() { - return this.doc; - } - } - - /** - * Gets the 'Power' class, which allows to set limitations to Active and - * Reactive Power. - * - * @return - */ - public SymmetricPower getPower(); - -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/readonly/api/SymmetricEssReadonly.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/readonly/api/SymmetricEssReadonly.java deleted file mode 100644 index 7ac34009cbc..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/readonly/api/SymmetricEssReadonly.java +++ /dev/null @@ -1,187 +0,0 @@ -package io.openems.edge.ess.symmetric.readonly.api; - -import org.osgi.annotation.versioning.ProviderType; - -import io.openems.common.types.OpenemsType; -import io.openems.edge.common.channel.Channel; -import io.openems.edge.common.channel.doc.Doc; -import io.openems.edge.common.channel.doc.Unit; -import io.openems.edge.common.converter.StaticConverters; -import io.openems.edge.ess.api.Ess; - -@ProviderType -public interface SymmetricEssReadonly extends Ess { - - public final static String POWER_DOC_TEXT = "Negative values for Charge; positive for Discharge"; - - public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { - /** - * Charge Active Power - * - *
              - *
            • Interface: Ess Symmetric - *
            • Type: Integer - *
            • Unit: W - *
            • Range: only positive values - *
            • Implementation Note: value is automatically derived from negative - * ACTIVE_POWER - *
            - */ - CHARGE_ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Discharge Active Power - * - *
              - *
            • Interface: Ess Symmetric - *
            • Type: Integer - *
            • Unit: W - *
            • Range: only positive values - *
            • Implementation Note: value is automatically derived from ACTIVE_POWER - *
            - */ - DISCHARGE_ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Active Power - * - *
              - *
            • Interface: Ess Symmetric - *
            • Type: Integer - *
            • Unit: W - *
            • Range: negative values for Charge; positive for Discharge - *
            - */ - ACTIVE_POWER(new Doc() // - .type(OpenemsType.INTEGER) // - .unit(Unit.WATT) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - // derive DISCHARGE_ACTIVE_POWER and CHARGE_ACTIVE_POWER from ACTIVE_POWER - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.DISCHARGE_ACTIVE_POWER).setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CHARGE_ACTIVE_POWER).setNextValue(chargeValue); - }); - })), // - /** - * Charge Reactive Power - * - *
              - *
            • Interface: Ess Symmetric - *
            • Type: Integer - *
            • Unit: var - *
            • Range: only positive values - *
            • Implementation Note: value is automatically derived from negative - * REACTIVE_POWER - *
            - */ - CHARGE_REACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - /** - * Discharge Reactive Power - * - *
              - *
            • Interface: Ess Symmetric - *
            • Type: Integer - *
            • Unit: var - *
            • Range: only positive values - *
            • Implementation Note: value is automatically derived from REACTIVE_POWER - *
            - */ - DISCHARGE_REACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - /** - * Reactive Power - * - *
              - *
            • Interface: Ess Symmetric - *
            • Type: Integer - *
            • Unit: var - *
            • Range: negative values for Charge; positive for Discharge - *
            - */ - REACTIVE_POWER(new Doc() // - .type(OpenemsType.INTEGER) // - .unit(Unit.VOLT_AMPERE_REACTIVE) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - // derive DISCHARGE_REACTIVE_POWER and CHARGE_REACTIVE_POWER from REACTIVE_POWER - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.DISCHARGE_REACTIVE_POWER).setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CHARGE_REACTIVE_POWER).setNextValue(chargeValue); - }); - })); - - private final Doc doc; - - private ChannelId(Doc doc) { - this.doc = doc; - } - - public Doc doc() { - return this.doc; - } - } - - /** - * Gets the Active Power in [W]. Negative values for Charge; positive for - * Discharge - * - * @return - */ - default Channel getActivePower() { - return this.channel(ChannelId.ACTIVE_POWER); - } - - /** - * Gets the Charge Active Power in [W]. This is derived from negative - * 'getActivePower()' values; 0 for positive. - * - * @return - */ - default Channel getChargeActivePower() { - return this.channel(ChannelId.CHARGE_ACTIVE_POWER); - } - - /** - * Gets the Discharge Active Power in [W]. This is derived from positive - * 'getActivePower()' values; 0 for negative. - * - * @return - */ - default Channel getDischargeActivePower() { - return this.channel(ChannelId.DISCHARGE_ACTIVE_POWER); - } - - /** - * Gets the Reactive Power in [var]. Negative values for Charge; positive for - * Discharge - * - * @return - */ - default Channel getReactivePower() { - return this.channel(ChannelId.REACTIVE_POWER); - } - - /** - * Gets the Charge Reactive Power in [var]. This is derived from negative - * 'getReactivePower()' values; 0 for positive. - * - * @return - */ - default Channel getChargeReactivePower() { - return this.channel(ChannelId.CHARGE_REACTIVE_POWER); - } - - /** - * Gets the Discharge Reactive Power in [var]. This is derived from positive - * 'getReactivePower()' values; 0 for negative. - * - * @return - */ - default Channel getDischargeReactivePower() { - return this.channel(ChannelId.DISCHARGE_REACTIVE_POWER); - } -} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/readonly/api/package-info.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/readonly/api/package-info.java deleted file mode 100644 index 9f99018d00f..00000000000 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/readonly/api/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -@org.osgi.annotation.versioning.Version("1.0.0") -package io.openems.edge.ess.symmetric.readonly.api; diff --git a/io.openems.edge.ess.cluster/.classpath b/io.openems.edge.ess.cluster/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.ess.cluster/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.ess.cluster/.gitignore b/io.openems.edge.ess.cluster/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.ess.cluster/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.ess.cluster/bnd.bnd b/io.openems.edge.ess.cluster/bnd.bnd new file mode 100644 index 00000000000..4da3a114777 --- /dev/null +++ b/io.openems.edge.ess.cluster/bnd.bnd @@ -0,0 +1,25 @@ +Bundle-Name: OpenEMS Edge ESS Cluster +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.ess.symmetric.readonly.api,\ + io.openems.edge.ess.api,\ + io.openems.edge.ess.symmetric.api,\ + io.openems.edge.ess.power.symmetric,\ + io.openems.edge.ess.power.api + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.ess.api;version=latest,\ + io.openems.edge.common;version=latest,\ + io.openems.common;version=latest,\ + io.openems.edge.bridge.modbus;version=latest,\ + org.apache.commons.math3 + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 +Private-Package: io.openems.edge.ess.cluster \ No newline at end of file diff --git a/io.openems.edge.ess.cluster/debug.bndrun b/io.openems.edge.ess.cluster/debug.bndrun new file mode 100644 index 00000000000..974345fac54 --- /dev/null +++ b/io.openems.edge.ess.cluster/debug.bndrun @@ -0,0 +1,13 @@ +# +# io.openems.edge.ess.cluster DEBUG LAUNCH SPECFICATION +# + +-include: ~io.openems.edge.ess.cluster.bndrun + +-runrequires.debug: \ + ${debug-bundles} + +-runtrace: true + +-runbundles: \ + ${error;Resolve first} diff --git a/io.openems.edge.ess.cluster/io.openems.edge.ess.cluster.bndrun b/io.openems.edge.ess.cluster/io.openems.edge.ess.cluster.bndrun new file mode 100644 index 00000000000..aa5d6fbe7e5 --- /dev/null +++ b/io.openems.edge.ess.cluster/io.openems.edge.ess.cluster.bndrun @@ -0,0 +1,14 @@ +# +# io.openems.edge.ess.cluster LAUNCH SPECIFICATION +# + + +Bundle-Version: 1.0.0.${tstamp} +Bundle-SymbolicName: io.openems.edge.ess.cluster.launch +JPM-Command: provider + + +-runrequires: \ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.cluster.provider)' + +-runbundles: ${error;You must first resolve this bndrun file before you can run it} diff --git a/io.openems.edge.ess.cluster/readme.md b/io.openems.edge.ess.cluster/readme.md new file mode 100644 index 00000000000..281af8de593 --- /dev/null +++ b/io.openems.edge.ess.cluster/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.ess.cluster Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/Config.java b/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/Config.java new file mode 100644 index 00000000000..e9a6e56feea --- /dev/null +++ b/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/Config.java @@ -0,0 +1,23 @@ +package io.openems.edge.ess.cluster; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition( // + name = "ESS Cluster", // + description = "Combines several energy storage systems to one.") +@interface Config { + String service_pid(); + + String id() default "ess0"; + + boolean enabled() default true; + + @AttributeDefinition(name = "ESS-IDs", description = "IDs of Ess devices.") + String[] ess_ids(); + + @AttributeDefinition(name = "ESS target filter", description = "This is auto-generated by 'ESS-IDs'.") + String esss_target() default ""; + + String webconsole_configurationFactory_nameHint() default "ESS Cluster [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/EssCluster.java b/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/EssCluster.java new file mode 100644 index 00000000000..7c8c2173605 --- /dev/null +++ b/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/EssCluster.java @@ -0,0 +1,191 @@ +package io.openems.edge.ess.cluster; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.EventConstants; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.common.channel.merger.AverageInteger; +import io.openems.edge.common.channel.merger.SumInteger; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.api.AsymmetricEss; +import io.openems.edge.ess.api.ManagedAsymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.MetaEss; + +@Designate(ocd = Config.class, factory = true) +@Component( // + name = "Ess.Cluster", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_CONTROLLERS // +) +public class EssCluster extends AbstractOpenemsComponent + implements ManagedAsymmetricEss, AsymmetricEss, ManagedSymmetricEss, SymmetricEss, MetaEss, OpenemsComponent { + + private final AverageInteger soc; + private final SumInteger activePower; + private final SumInteger reactivePower; + private final SumInteger activePowerL1; + private final SumInteger reactivePowerL1; + private final SumInteger activePowerL2; + private final SumInteger reactivePowerL2; + private final SumInteger activePowerL3; + private final SumInteger reactivePowerL3; + private final SumInteger maxActivePower; + private final SumInteger activeChargeEnergy; + private final SumInteger activeDischargeEnergy; + + @Reference + private Power power = null; + + @Reference + protected ConfigurationAdmin cm; + + private final List esss = new CopyOnWriteArrayList<>(); + private final List managedEsss = new CopyOnWriteArrayList<>(); + + @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) + protected void addEss(SymmetricEss ess) { + if (ess == this) { + return; + } + + this.esss.add(ess); + if (ess instanceof ManagedSymmetricEss) { + this.managedEsss.add((ManagedSymmetricEss) ess); + } + + this.soc.addComponent(ess); + this.activePower.addComponent(ess); + this.reactivePower.addComponent(ess); + this.maxActivePower.addComponent(ess); + this.activeChargeEnergy.addComponent(ess); + this.activeDischargeEnergy.addComponent(ess); + if (ess instanceof AsymmetricEss) { + AsymmetricEss e = (AsymmetricEss) ess; + this.activePowerL1.addComponent(e); + this.reactivePowerL1.addComponent(e); + this.activePowerL2.addComponent(e); + this.reactivePowerL2.addComponent(e); + this.activePowerL3.addComponent(e); + this.reactivePowerL3.addComponent(e); + } + } + + protected void removeEss(SymmetricEss ess) { + if (ess == this) { + return; + } + + this.esss.remove(ess); + if (ess instanceof ManagedSymmetricEss) { + this.managedEsss.remove((ManagedSymmetricEss) ess); + } + + this.soc.removeComponent(ess); + this.activePower.removeComponent(ess); + this.reactivePower.removeComponent(ess); + this.maxActivePower.removeComponent(ess); + this.activeChargeEnergy.removeComponent(ess); + this.activeDischargeEnergy.removeComponent(ess); + if (ess instanceof AsymmetricEss) { + AsymmetricEss e = (AsymmetricEss) ess; + this.activePowerL1.removeComponent(e); + this.reactivePowerL1.removeComponent(e); + this.activePowerL2.removeComponent(e); + this.reactivePowerL2.removeComponent(e); + this.activePowerL3.removeComponent(e); + this.reactivePowerL3.removeComponent(e); + } + } + + public EssCluster() { + Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); + /* + * Define Channel Mergers + */ + this.soc = new AverageInteger(this, SymmetricEss.ChannelId.SOC, SymmetricEss.ChannelId.SOC); + this.activePower = new SumInteger(this, SymmetricEss.ChannelId.ACTIVE_POWER, + SymmetricEss.ChannelId.ACTIVE_POWER); + this.reactivePower = new SumInteger(this, SymmetricEss.ChannelId.REACTIVE_POWER, + SymmetricEss.ChannelId.REACTIVE_POWER); + this.activePowerL1 = new SumInteger(this, AsymmetricEss.ChannelId.ACTIVE_POWER_L1, + AsymmetricEss.ChannelId.ACTIVE_POWER_L1); + this.reactivePowerL1 = new SumInteger(this, AsymmetricEss.ChannelId.REACTIVE_POWER_L1, + AsymmetricEss.ChannelId.REACTIVE_POWER_L1); + this.activePowerL2 = new SumInteger(this, AsymmetricEss.ChannelId.ACTIVE_POWER_L2, + AsymmetricEss.ChannelId.ACTIVE_POWER_L2); + this.reactivePowerL2 = new SumInteger(this, AsymmetricEss.ChannelId.REACTIVE_POWER_L2, + AsymmetricEss.ChannelId.REACTIVE_POWER_L2); + this.activePowerL3 = new SumInteger(this, AsymmetricEss.ChannelId.ACTIVE_POWER_L3, + AsymmetricEss.ChannelId.ACTIVE_POWER_L3); + this.reactivePowerL3 = new SumInteger(this, AsymmetricEss.ChannelId.REACTIVE_POWER_L3, + AsymmetricEss.ChannelId.REACTIVE_POWER_L3); + this.maxActivePower = new SumInteger(this, SymmetricEss.ChannelId.MAX_ACTIVE_POWER, + SymmetricEss.ChannelId.MAX_ACTIVE_POWER); + this.activeChargeEnergy = new SumInteger(this, SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY, + SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY); + this.activeDischargeEnergy = new SumInteger(this, SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY, + SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY); + } + + @Activate + void activate(ComponentContext context, Config config) throws OpenemsException { + // update filter for 'esss' component + if (OpenemsComponent.updateReferenceFilter(this.cm, config.service_pid(), "esss", config.ess_ids())) { + return; + } + + super.activate(context, config.service_pid(), config.id(), config.enabled()); + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + @Override + public void applyPower(int activePower, int reactivePower) { + throw new IllegalArgumentException("EssClusterImpl.applyPower() should never be called."); + } + + @Override + public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, + int activePowerL3, int reactivePowerL3) { + throw new IllegalArgumentException("EssClusterImpl.applyPower() should never be called."); + } + + @Override + public int getPowerPrecision() { + // TODO kleinstes gemeinsames Vielfaches von PowerPrecision + return 0; + } + + @Override + public synchronized List getEsss() { + return Collections.unmodifiableList(this.managedEsss); + } + + @Override + public Power getPower() { + return this.power; + } +} diff --git a/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/Utils.java b/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/Utils.java new file mode 100644 index 00000000000..7dcdddac0aa --- /dev/null +++ b/io.openems.edge.ess.cluster/src/io/openems/edge/ess/cluster/Utils.java @@ -0,0 +1,68 @@ +package io.openems.edge.ess.cluster; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.AbstractReadChannel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.api.AsymmetricEss; +import io.openems.edge.ess.api.ManagedAsymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; + +public class Utils { + public static Stream> initializeChannels(EssCluster c) { + return Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(c, channelId); + } + return null; + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case ACTIVE_POWER: + case REACTIVE_POWER: + case MAX_ACTIVE_POWER: + case ACTIVE_CHARGE_ENERGY: + case ACTIVE_DISCHARGE_ENERGY: + return new IntegerReadChannel(c, channelId); + case GRID_MODE: + return new IntegerReadChannel(c, channelId, SymmetricEss.GridMode.UNDEFINED.ordinal()); + } + return null; + }), Arrays.stream(ManagedSymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER: + case DEBUG_SET_REACTIVE_POWER: + return new IntegerReadChannel(c, channelId); + } + return null; + }), Arrays.stream(AsymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case ACTIVE_POWER_L1: + case ACTIVE_POWER_L2: + case ACTIVE_POWER_L3: + case REACTIVE_POWER_L1: + case REACTIVE_POWER_L2: + case REACTIVE_POWER_L3: + return new IntegerReadChannel(c, channelId); + } + return null; + }), Arrays.stream(ManagedAsymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER_L1: + case DEBUG_SET_ACTIVE_POWER_L2: + case DEBUG_SET_ACTIVE_POWER_L3: + case DEBUG_SET_REACTIVE_POWER_L1: + case DEBUG_SET_REACTIVE_POWER_L2: + case DEBUG_SET_REACTIVE_POWER_L3: + return new IntegerReadChannel(c, channelId); + } + return null; + })).flatMap(channel -> channel); + } +} diff --git a/io.openems.edge.ess.cluster/test/.gitignore b/io.openems.edge.ess.cluster/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.ess.core/.classpath b/io.openems.edge.ess.core/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.ess.core/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.ess.core/.gitignore b/io.openems.edge.ess.core/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.ess.core/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.ess.core/bnd.bnd b/io.openems.edge.ess.core/bnd.bnd new file mode 100644 index 00000000000..67a506c3796 --- /dev/null +++ b/io.openems.edge.ess.core/bnd.bnd @@ -0,0 +1,19 @@ +Bundle-Name: OpenEMS Edge ESS Core +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: io.openems.edge.ess.core.power + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.common;version=latest,\ + org.apache.commons.math3;version=3.6,\ + io.openems.edge.ess.api;version=latest,\ + io.openems.common,\ + com.google.guava + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 diff --git a/io.openems.edge.ess.core/debug.bndrun b/io.openems.edge.ess.core/debug.bndrun new file mode 100644 index 00000000000..32c82885db0 --- /dev/null +++ b/io.openems.edge.ess.core/debug.bndrun @@ -0,0 +1,13 @@ +# +# io.openems.edge.ess.core DEBUG LAUNCH SPECFICATION +# + +-include: ~io.openems.edge.ess.core.bndrun + +-runrequires.debug: \ + ${debug-bundles} + +-runtrace: true + +-runbundles: \ + ${error;Resolve first} diff --git a/io.openems.edge.ess.core/io.openems.edge.ess.core.bndrun b/io.openems.edge.ess.core/io.openems.edge.ess.core.bndrun new file mode 100644 index 00000000000..89547d3814e --- /dev/null +++ b/io.openems.edge.ess.core/io.openems.edge.ess.core.bndrun @@ -0,0 +1,14 @@ +# +# io.openems.edge.ess.core LAUNCH SPECIFICATION +# + + +Bundle-Version: 1.0.0.${tstamp} +Bundle-SymbolicName: io.openems.edge.ess.core.launch +JPM-Command: provider + + +-runrequires: \ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.core.provider)' + +-runbundles: ${error;You must first resolve this bndrun file before you can run it} diff --git a/io.openems.edge.ess.core/readme.md b/io.openems.edge.ess.core/readme.md new file mode 100644 index 00000000000..ff957365709 --- /dev/null +++ b/io.openems.edge.ess.core/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.ess.core Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/AsymmetricSolution.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/AsymmetricSolution.java new file mode 100644 index 00000000000..bafd2c7c22e --- /dev/null +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/AsymmetricSolution.java @@ -0,0 +1,56 @@ +package io.openems.edge.ess.core.power; + +import io.openems.edge.ess.api.ManagedAsymmetricEss; + +public class AsymmetricSolution extends SymmetricSolution { + + private final int activePowerL1; + private final int reactivePowerL1; + private final int activePowerL2; + private final int reactivePowerL2; + private final int activePowerL3; + private final int reactivePowerL3; + + public AsymmetricSolution(ManagedAsymmetricEss ess, int activePowerL1, int reactivePowerL1, int activePowerL2, + int reactivePowerL2, int activePowerL3, int reactivePowerL3) { + super(ess, // + activePowerL1 + activePowerL2 + activePowerL3, // + reactivePowerL1 + reactivePowerL2 + reactivePowerL3); + this.activePowerL1 = activePowerL1; + this.reactivePowerL1 = reactivePowerL1; + this.activePowerL2 = activePowerL2; + this.reactivePowerL2 = reactivePowerL2; + this.activePowerL3 = activePowerL3; + this.reactivePowerL3 = reactivePowerL3; + } + + public int getActivePowerL1() { + return activePowerL1; + } + + public int getReactivePowerL1() { + return reactivePowerL1; + } + + public int getActivePowerL2() { + return activePowerL2; + } + + public int getReactivePowerL2() { + return reactivePowerL2; + } + + public int getActivePowerL3() { + return activePowerL3; + } + + public int getReactivePowerL3() { + return reactivePowerL3; + } + + @Override + public String toString() { + return "AsymmetricSolution [ess=" + this.getEss().id() + ", L1 P=" + activePowerL1 + ", Q=" + reactivePowerL1 + ", L2 P=" + + activePowerL2 + ", Q=" + reactivePowerL2 + ", L3 P=" + activePowerL3 + ", Q=" + reactivePowerL3 + "]"; + } +} diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Data.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Data.java new file mode 100644 index 00000000000..038c2f8fdce --- /dev/null +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Data.java @@ -0,0 +1,376 @@ +package io.openems.edge.ess.core.power; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.apache.commons.math3.optim.linear.LinearConstraint; +import org.apache.commons.math3.optim.linear.LinearObjectiveFunction; +import org.apache.commons.math3.optim.linear.Relationship; + +import io.openems.edge.ess.api.ManagedAsymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.MetaEss; +import io.openems.edge.ess.power.api.Coefficient; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; + +public class Data { + + /** + * Holds all ManagedSymmetricEss objects covered by this Power object + */ + protected final Set allEsss = new HashSet<>(); + + private final int COEFFICIENTS_PER_ESS = 6; + + /** + * Holds the cycle constraints. Those constraints are cleared on every Cycle by + * the applyPower()-method. + */ + private final List cycleConstraints = new ArrayList<>(); + + /** + * Holds all MetaEss objects + */ + protected final Set metaEsss = new HashSet<>(); + + /** + * Holds all ManagedSymmetricEss objects that represent physical ESS (i.e. no + * MetaEss). + */ + protected final Set realEsss = new HashSet<>(); + + /** + * Holds the static constraints. Those constraints stay forever. They can be + * adjusted by keeping a reference and calling the setValue() method. + */ + private final List staticConstraints = new ArrayList<>(); + + /** + * Recursive helper method for getEssIndex + * + * @param ess + * @param retry + * @return + */ + private synchronized int _getEssIndex(ManagedSymmetricEss ess) { + boolean found = false; + int essIndex = 0; + for (ManagedSymmetricEss realEss : this.realEsss) { + if (realEss.equals(ess)) { + found = true; + break; + } else { + essIndex += COEFFICIENTS_PER_ESS; + } + } + if (found) { + return essIndex; + } + + // not found -> add ess + throw new IllegalArgumentException( + "Ess [" + ess.id() + "; " + ess.hashCode() + "] was not found in the system."); + } + + /** + * Add a Constraint + * + * @param constraint + * @return + */ + public synchronized Constraint addConstraint(Constraint constraint) { + this.getConstraintListForType(constraint.getType()).add(constraint); + return constraint; + } + + /** + * Add an ManagedSymmetricEss + * + * @param ess + */ + public synchronized void addEss(ManagedSymmetricEss ess) { + boolean wasAlreadyAdded = !this.allEsss.add(ess); + if (wasAlreadyAdded) { + return; + } + if (ess instanceof MetaEss) { + this.metaEsss.add((MetaEss) ess); + + } else { + if (!(this.realEsss.contains(ess))) { + this.realEsss.add(ess); + + if (ess instanceof ManagedAsymmetricEss) { + // nothing + } else { + /* + * ManagedSymmetricEss: all phases need to be equal + */ + this.addConstraint(new Constraint( // + ConstraintType.STATIC, // + new Coefficient[] { // + new Coefficient(ess, Phase.L1, Pwr.ACTIVE, 1), // + new Coefficient(ess, Phase.L2, Pwr.ACTIVE, -1), // + }, Relationship.EQ, 0)); + this.addConstraint(new Constraint( // + ConstraintType.STATIC, // + new Coefficient[] { // + new Coefficient(ess, Phase.L1, Pwr.ACTIVE, 1), // + new Coefficient(ess, Phase.L3, Pwr.ACTIVE, -1), // + }, Relationship.EQ, 0)); + this.addConstraint(new Constraint( // + ConstraintType.STATIC, // + new Coefficient[] { // + new Coefficient(ess, Phase.L1, Pwr.REACTIVE, 1), // + new Coefficient(ess, Phase.L2, Pwr.REACTIVE, -1), // + }, Relationship.EQ, 0)); + this.addConstraint(new Constraint( // + ConstraintType.STATIC, // + new Coefficient[] { // + new Coefficient(ess, Phase.L1, Pwr.REACTIVE, 1), // + new Coefficient(ess, Phase.L3, Pwr.REACTIVE, -1), // + }, Relationship.EQ, 0)); + } + } + } + } + + /** + * Removes a ManagedSymmetricEss + * + * @param ess + */ + public synchronized void removeEss(ManagedSymmetricEss ess) { + this.allEsss.remove(ess); + if (ess instanceof MetaEss) { + this.metaEsss.remove((MetaEss) ess); + + } else { + /* + * find all existing Constraints for this Ess and remove them + */ + Consumer> constraintHandler = (i) -> { + while (i.hasNext()) { + Constraint ct = i.next(); + boolean constraintHasThisEss = Stream.of(ct.getCoefficients()) // + .anyMatch(co -> co.getEss().equals(ess)); + if (constraintHasThisEss) { + i.remove(); + // NOTE: what happens if this Constraint is for several Ess? Should we keep it + // and only remove the matching coefficients? + } + } + }; + constraintHandler.accept(this.staticConstraints.iterator()); + constraintHandler.accept(this.cycleConstraints.iterator()); + + this.realEsss.remove(ess); + } + } + + /** + * Add a simple Constraint + * + * @param ess + * @param type + * @param phase + * @param pwr + * @param relationship + * @param value + * @return + */ + public synchronized Constraint addSimpleConstraint(ManagedSymmetricEss ess, ConstraintType type, Phase phase, + Pwr pwr, Relationship relationship, int value) { + return this.addConstraint(Utils.createSimpleConstraint(ess, type, phase, pwr, relationship, value)); + } + + /** + * Clear Cycle constraints, keeping only the 'staticConstraints' for next Cycle. + */ + public synchronized void clearCycleConstraints() { + this.cycleConstraints.clear(); + } + + /** + * Get Indices of ActivePower coefficients + * + * @return + */ + public synchronized IntStream getActivePowerCoefficientIndices() { + return IntStream.iterate(0, i -> i + 2).limit(this.getNoOfCoefficients() / 2); + } + + /** + * Gets all Constraints (Static + Cycle) + * + * @return + */ + public synchronized List getAllConstraints() { + return Stream.concat(this.staticConstraints.stream(), this.cycleConstraints.stream()) + .collect(Collectors.toList()); + } + + /** + * Gets all Constraints as LinearConstraints + * + * @return + */ + public synchronized List getAllLinearConstraints() { + List constraints = new ArrayList(); + for (Constraint c : this.getAllConstraints()) { + LinearConstraint lc = this.toLinearConstraint(c); + if (lc != null) { + constraints.add(lc); + } + } + return constraints; + } + + /** + * Get the correct list for the ConstraintType + * + * @param type + * @return + */ + private synchronized List getConstraintListForType(ConstraintType type) { + switch (type) { + case STATIC: + return this.staticConstraints; + case CYCLE: + return this.cycleConstraints; + } + throw new IllegalArgumentException("This should never happen!"); + } + + /** + * Create Constraints to keep all coefficients in Quadrant I + * + * @return + */ + public synchronized LinearConstraint[] createConstraintsForQuadrantI() { + LinearConstraint[] result = new LinearConstraint[this.getNoOfCoefficients()]; + for (int i = 0; i < this.getNoOfCoefficients(); i++) { + double[] coefficients = this.createEmptyCoefficients(); + coefficients[i] = 1; + result[i] = new LinearConstraint(coefficients, Relationship.GEQ, 0); + } + return result; + } + + /** + * Creates an empty Coefficient array + * + * @return + */ + public synchronized double[] createEmptyCoefficients() { + return new double[this.getNoOfCoefficients()]; + } + + /** + * Gets the coefficient start index for the given ManagedSymmetricEss - if it is + * available + * + * @param ess + * @return + */ + public synchronized int getEssIndex(ManagedSymmetricEss ess) { + return this._getEssIndex(ess); + } + + /** + * Gets the total number of Coefficients + */ + public synchronized int getNoOfCoefficients() { + return this.realEsss.size() * COEFFICIENTS_PER_ESS; + } + + /** + * Creates a Simple Objective Function: 1*p1 + 1*q1 + 1*p2 + 1*q2 + ... + * + * @return + */ + public synchronized LinearObjectiveFunction createSimpleObjectiveFunction() { + double[] c = this.createEmptyCoefficients(); + for (int i = 0; i < c.length; i++) { + c[i] = 1; + } + return new LinearObjectiveFunction(c, 0); + } + + /** + * Removes a Constraint + * + * @param constraint + */ + public synchronized void removeConstraint(Constraint constraint) { + if (constraint == null) { + return; + } + this.getConstraintListForType(constraint.getType()).remove(constraint); + } + + /** + * Creates a LinearConstraint - suitable for linear optimization problem - from + * a OpenEMS Constraint object + * + * @param constraint + * @return + */ + protected synchronized LinearConstraint toLinearConstraint(Constraint constraint) { + if (constraint.isEnabled()) { + double[] coefficients = this.createEmptyCoefficients(); + for (Coefficient coefficient : constraint.getCoefficients()) { + this.getCoefficients(coefficients, coefficient.getEss(), coefficient.getPhase(), coefficient.getPwr(), + coefficient.getValue()); + } + return new LinearConstraint(coefficients, constraint.getRelationship(), constraint.getValue().get()); + } else { + return null; + } + } + + /** + * Helper for toLinearConstraint-method. Creates the coefficients array for a + * LinearConstraint from given meta data + * + * @param coefficients + * @param ess + * @param phase + * @param pwr + * @param value + */ + private synchronized void getCoefficients(double[] coefficients, ManagedSymmetricEss ess, Phase phase, Pwr pwr, + double value) { + if (ess instanceof MetaEss) { + for (ManagedSymmetricEss subEss : ((MetaEss) ess).getEsss()) { + this.getCoefficients(coefficients, subEss, phase, pwr, value); + } + return; + } + + int essIndex = this.getEssIndex(ess); + int pwrOffset = pwr.getOffset(); + switch (phase) { + case ALL: + coefficients[essIndex + Phase.L1.getOffset() + pwrOffset] = value; + coefficients[essIndex + Phase.L2.getOffset() + pwrOffset] = value; + coefficients[essIndex + Phase.L3.getOffset() + pwrOffset] = value; + break; + case L1: + case L2: + case L3: + coefficients[essIndex + phase.getOffset() + pwrOffset] = value; + break; + } + } +} diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/LinearPower.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/LinearPower.java new file mode 100644 index 00000000000..6bff2b2a9b9 --- /dev/null +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/LinearPower.java @@ -0,0 +1,427 @@ +package io.openems.edge.ess.core.power; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import org.apache.commons.math3.optim.PointValuePair; +import org.apache.commons.math3.optim.linear.LinearConstraint; +import org.apache.commons.math3.optim.linear.LinearConstraintSet; +import org.apache.commons.math3.optim.linear.LinearObjectiveFunction; +import org.apache.commons.math3.optim.linear.NoFeasibleSolutionException; +import org.apache.commons.math3.optim.linear.PivotSelectionRule; +import org.apache.commons.math3.optim.linear.Relationship; +import org.apache.commons.math3.optim.linear.SimplexSolver; +import org.apache.commons.math3.optim.linear.UnboundedSolutionException; +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.edge.ess.api.ManagedAsymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.power.api.Coefficient; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.power.api.PowerException; +import io.openems.edge.ess.power.api.Pwr; + +/** + * This holds the the linear solver. It tries to solve the distribution of + * Active and Reactive Power among the ESSs using a linear objective function. + * + * The LinearSolver is a fast approach to prove that a solution to a problem is + * available and gives a first solution. It fails in taking in account more + * complicated constraints that cannot be wrapped in a linear equation. + */ +public class LinearPower implements Power { + + private final Logger log = LoggerFactory.getLogger(LinearPower.class); + + /* + * Holds a reference to the Data POJO + */ + private final Data data = new Data(); + + public Constraint addSimpleConstraintAndValidate(ManagedSymmetricEss ess, ConstraintType type, Phase phase, Pwr pwr, + Relationship relationship, int value) throws PowerException { + return this.addConstraintAndValidate(// + Utils.createSimpleConstraint(ess, type, phase, pwr, relationship, value)); + } + + /** + * Adds a Constraint + * + * @param constraint + * @return + */ + public synchronized Constraint addConstraint(Constraint constraint) { + return this.data.addConstraint(constraint); + } + + /** + * Adds a Constraint if + * + * @param constraint + * @return + * @throws PowerException + */ + public synchronized Constraint addConstraintAndValidate(Constraint constraint) throws PowerException { + LinearConstraint lc = this.data.toLinearConstraint(constraint); + if (!this.isSolvable(lc)) { + // throws the exception if it is not solvable + throw new PowerException(new NoFeasibleSolutionException()); + } + this.addConstraint(constraint); + return constraint; + } + + public synchronized void addEss(ManagedSymmetricEss ess) { + this.data.addEss(ess); + } + + public Constraint addSimpleConstraint(ManagedSymmetricEss ess, ConstraintType type, Phase phase, Pwr pwr, + Relationship relationship, int value) { + return this.data.addSimpleConstraint(ess, type, phase, pwr, relationship, value); + } + + /** + * This is the final method of the Power class. It should never be called + * manually, as it is getting called by the framework. + *
              + *
            • It solves the Linear Objective Function + *
            • It tries to improve the result using Genetic Algorithms + *
            • It calls the applyPower() methods of each Ess + *
            + * + * @throws Exception + */ + public synchronized void applyPower() { + // solve using linear solver + double[] solutionArray = this.solveOptimally(); + + Map solutions = Utils.toSolutions(this.data, solutionArray); + + // set debug channels on parent + this.data.allEsss.forEach(ess -> { + AtomicInteger activePower = new AtomicInteger(0); + AtomicInteger reactivePower = new AtomicInteger(0); + AtomicInteger activePowerL1 = new AtomicInteger(0); + AtomicInteger reactivePowerL1 = new AtomicInteger(0); + AtomicInteger activePowerL2 = new AtomicInteger(0); + AtomicInteger reactivePowerL2 = new AtomicInteger(0); + AtomicInteger activePowerL3 = new AtomicInteger(0); + AtomicInteger reactivePowerL3 = new AtomicInteger(0); + Utils.sumSolutions(ess, solutions, activePower, reactivePower, activePowerL1, reactivePowerL1, + activePowerL2, reactivePowerL2, activePowerL3, reactivePowerL3); + if (ess instanceof ManagedAsymmetricEss) { + ess.channel(ManagedAsymmetricEss.ChannelId.DEBUG_SET_ACTIVE_POWER_L1).setNextValue(activePowerL1.get()); + ess.channel(ManagedAsymmetricEss.ChannelId.DEBUG_SET_REACTIVE_POWER_L1) + .setNextValue(reactivePowerL1.get()); + ess.channel(ManagedAsymmetricEss.ChannelId.DEBUG_SET_ACTIVE_POWER_L2).setNextValue(activePowerL2.get()); + ess.channel(ManagedAsymmetricEss.ChannelId.DEBUG_SET_REACTIVE_POWER_L2) + .setNextValue(reactivePowerL2.get()); + ess.channel(ManagedAsymmetricEss.ChannelId.DEBUG_SET_ACTIVE_POWER_L3).setNextValue(activePowerL3.get()); + ess.channel(ManagedAsymmetricEss.ChannelId.DEBUG_SET_REACTIVE_POWER_L3) + .setNextValue(reactivePowerL3.get()); + } + ess.channel(ManagedSymmetricEss.ChannelId.DEBUG_SET_ACTIVE_POWER).setNextValue(activePower.get()); + ess.channel(ManagedSymmetricEss.ChannelId.DEBUG_SET_REACTIVE_POWER).setNextValue(reactivePower.get()); + }); + + this.data.realEsss.forEach(ess -> { + SymmetricSolution ss = solutions.get(ess); + if (ss == null) { + return; + } + + if (ess instanceof ManagedAsymmetricEss && ss instanceof AsymmetricSolution) { + /* + * ManagedAsymmetricEss + */ + ManagedAsymmetricEss e = (ManagedAsymmetricEss) ess; + AsymmetricSolution as = (AsymmetricSolution) ss; + + e.applyPower(as.getActivePowerL1(), as.getReactivePowerL1(), as.getActivePowerL2(), + as.getReactivePowerL2(), as.getActivePowerL3(), as.getReactivePowerL3()); + } else { + /* + * ManagedSymmetricEss + */ + ess.applyPower(ss.getActivePower(), ss.getReactivePower()); + } + }); + } + + public synchronized void clearCycleConstraints() { + this.data.clearCycleConstraints(); + } + + private synchronized int getActivePowerExtrema(GoalType goalType) { + double[] coefficients = this.data.createEmptyCoefficients(); + this.data.getActivePowerCoefficientIndices().forEach(i -> coefficients[i] = 1); + double[] solution; + try { + solution = this.solve(new LinearObjectiveFunction(coefficients, 0), goalType); + return (int) (this.data.getActivePowerCoefficientIndices().mapToDouble(i -> solution[i]).sum()); + } catch (PowerException e) { + log.warn("Unable to " + goalType.name() + " Active Power. Setting it to zero."); + return 0; + } + } + + /** + * Gets the maximum possible total Active Power under the active Constraints. + */ + public synchronized int getMaxActivePower() { + return this.getActivePowerExtrema(GoalType.MAXIMIZE); + } + + /** + * Gets the minimum possible total Active Power under the active Constraints. + */ + public synchronized int getMinActivePower() { + return this.getActivePowerExtrema(GoalType.MINIMIZE); + } + + /** + * Returns whether the objective function is solvable under the currently given + * constraints. + * + * @return + */ + public synchronized boolean isSolvable(LinearConstraint... additionalConstraints) { + try { + this.solve(this.data.createSimpleObjectiveFunction(), GoalType.MINIMIZE, additionalConstraints); + return true; + } catch (PowerException e) { + switch (e.getType()) { + case NO_FEASIBLE_SOLUTION: + return false; + case UNBOUNDED_SOLUTION: + return true; // it's unbounded, but still solvable + } + } + throw new IllegalArgumentException("LinearPower.isSolvable() - Should never come here..."); + } + + public synchronized void removeConstraint(Constraint constraint) { + this.data.removeConstraint(constraint); + } + + public synchronized void removeEss(ManagedSymmetricEss ess) { + this.data.removeEss(ess); + } + + /** + * Solves the Objective Function + * + * @return + * @throws PowerException + */ + public synchronized double[] solve(LinearObjectiveFunction objectiveFunction, GoalType goalType, + LinearConstraint... additionalConstraints) throws PowerException { + List constraints = this.data.getAllLinearConstraints(); + // log.info("Constraints"); + // for (LinearConstraint c : constraints) { + // log.info(Utils.linearConstraintToString(c, "")); + // } + // log.info("Additional Constraints"); + // for (LinearConstraint c : additionalConstraints) { + // log.info(Utils.linearConstraintToString(c, "")); + // } + // log.info(Utils.objectiveFunctionToString(objectiveFunction, goalType)); + + // copy to array (let space for 'additionalConstraints') + Arrays.stream(additionalConstraints).forEach(c -> constraints.add(c)); + LinearConstraint[] c = Utils.copyToArray(constraints); + + // solve + return result or throw Exception + SimplexSolver solver = new SimplexSolver(); + try { + PointValuePair solution = solver.optimize( // + objectiveFunction, // + new LinearConstraintSet(c), // + goalType, // + PivotSelectionRule.BLAND); + return solution.getPoint(); + } catch (NoFeasibleSolutionException e) { + throw new PowerException(e); + } catch (UnboundedSolutionException e) { + throw new PowerException(e); + } + } + + /** + * Solves the Objective Function + * + * @return + * @throws PowerException + */ + public synchronized double[] solve(LinearObjectiveFunction objectiveFunction, GoalType goalType, + List additionalConstraints) throws PowerException { + LinearConstraint[] cs = new LinearConstraint[additionalConstraints.size()]; + for (int i = 0; i < additionalConstraints.size(); i++) { + cs[i] = additionalConstraints.get(i); + } + return this.solve(objectiveFunction, goalType, cs); + } + + /** + * Gets Constraints for "0" if there is no definitive Constraint existing yet. + * + * @return + */ + public List getNullConstraints() { + List allPossibleCoefficients = new ArrayList<>(); + for (ManagedSymmetricEss ess : this.data.realEsss) { + for (Pwr pwr : Pwr.values()) { + Stream.of(Phase.L1, Phase.L2, Phase.L3) + .forEach(phase -> allPossibleCoefficients.add(new Coefficient(ess, phase, pwr, 1))); + } + } + + /* + * Remove Constraints from temporary list, that are already covered. i.e. + * Relationship is EQUALS and Constraint-Value is != 0 + */ + for (Constraint constraint : this.data.getAllConstraints()) { + if (constraint.getRelationship() != Relationship.EQ || constraint.getValue().orElse(0d) == 0) { + continue; + } + for (Coefficient thisCoefficient : constraint.getCoefficients()) { + Iterator i = allPossibleCoefficients.iterator(); + while (i.hasNext()) { + Coefficient possibleCoefficient = i.next(); + if (Utils.coefficientIsCoveredBy(possibleCoefficient, thisCoefficient.getEss(), thisCoefficient.getPhase(), + thisCoefficient.getPwr())) { + i.remove(); + } + } + } + } + + // For every Possible Coefficient that is left: create a Null-Constraint + // (Coefficient == 0) and return it + List result = new ArrayList<>(); + for (Coefficient coefficient : allPossibleCoefficients) { +// log.info("Add Null-Constraint for [" + coefficient.getEss().id() + "], " + coefficient.getPwr().name() +// + ", " + coefficient.getPhase().name()); + result.add(new Constraint(ConstraintType.CYCLE, new Coefficient[] { coefficient }, Relationship.EQ, 0)); + } + return result; + } + + /** + * Solves the linear objective function and tries to optimize the result as much + * as possible + * + * @return + * @throws Exception + */ + private synchronized double[] solveOptimally() { + /* + * Test if Objective Function is solvable. Otherwise return zeros. + */ + if (!this.isSolvable()) { + return this.data.createEmptyCoefficients(); + } + + /** + * If there is no Constraint for an Ess, add a "0"-Constraint + */ + this.getNullConstraints().forEach(constraint -> this.addConstraint(constraint)); + + /* + * Try to solve with Constraints to keep Ess1 == Ess2 == Ess3 + */ + try { + List constraints = new ArrayList<>(); + for (int i = 2; i < this.data.getNoOfCoefficients(); i += 2) { + // Active Power + double[] coefficients = this.data.createEmptyCoefficients(); + coefficients[0] = 1; + coefficients[i] = -1; + constraints.add(new LinearConstraint(coefficients, Relationship.EQ, 0)); + // Reactive Power + coefficients = this.data.createEmptyCoefficients(); + coefficients[1] = 1; + coefficients[i + 1] = -1; + constraints.add(new LinearConstraint(coefficients, Relationship.EQ, 0)); + } + return this.solve(this.data.createSimpleObjectiveFunction(), GoalType.MINIMIZE, constraints); + } catch (PowerException e) { + // Error -> next try + } + + for (GoalType goalType : new GoalType[] { GoalType.MINIMIZE, GoalType.MAXIMIZE }) { + /** + *
              + *
            • try to MINIMIZE p >= 0; then MINIMIZE q >= 0 + *
            • Fails? try to MAXIMIZE p >= 0; then MAXIMIZE q >= 0 + *
            + */ + try { + double[] coefficients = this.data.createEmptyCoefficients(); + + // solve function that finds extremal for p + this.data.getActivePowerCoefficientIndices().forEach(i -> coefficients[i] = 1); + final double[] solution = this.solve(new LinearObjectiveFunction(coefficients, 0), goalType, + this.data.createConstraintsForQuadrantI()); + + // set result as fixed values for p and try to solve q. + final List pConstraints = new ArrayList<>(); + this.data.getActivePowerCoefficientIndices().forEach(i -> { + double[] cs = this.data.createEmptyCoefficients(); + cs[i] = 1; + pConstraints.add(new LinearConstraint(cs, Relationship.EQ, solution[i])); + }); + pConstraints.addAll(Arrays.asList(this.data.createConstraintsForQuadrantI())); + return this.solve(this.data.createSimpleObjectiveFunction(), goalType, pConstraints); + } catch (PowerException e) { + // Error -> next try + } + } + + for (GoalType goalType : new GoalType[] { GoalType.MINIMIZE, GoalType.MAXIMIZE }) { + /** + *
              + *
            • Try to MINIMIZE without additional constraints + *
            • Fails? try to MAXIMIZE without additional constraints + *
            + */ + try { + return this.solve(this.data.createSimpleObjectiveFunction(), goalType); + } catch (PowerException e) { + // Error -> next try + } + } + + /* + * We should never get here... Objective Function is not solvable -> return + * zeros + */ + return this.data.createEmptyCoefficients(); + + // TODO evaluate if this should be migrated from old implementation + // /* + // * Avoid extreme changes in active/reactive power + // * + // * calculate the delta between last set power and current calculation and + // apply + // * it only partly + // */ + // int activePowerDelta = (int) c.x - this.lastActivePower + 1 /* add 1 to avoid + // rounding issues */; + // int reactivePowerDelta = (int) c.y - this.lastReactivePower + 1 /* add 1 to + // avoid rounding issues */; + // activePower = this.lastActivePower + activePowerDelta / 2; + // reactivePower = this.lastReactivePower + reactivePowerDelta / 2; + } + +} diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/PowerComponent.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/PowerComponent.java new file mode 100644 index 00000000000..6df14fdd84a --- /dev/null +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/PowerComponent.java @@ -0,0 +1,94 @@ +package io.openems.edge.ess.core.power; + +import org.apache.commons.math3.optim.linear.Relationship; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; + +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.power.api.PowerException; +import io.openems.edge.ess.power.api.Pwr; + +@Component( // + immediate = true, // + property = { // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_WRITE, // + EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE // + }) +public class PowerComponent implements EventHandler, Power { + + private final LinearPower linearPower = new LinearPower(); + + @Reference( // + policy = ReferencePolicy.DYNAMIC, // + policyOption = ReferencePolicyOption.GREEDY, // + cardinality = ReferenceCardinality.MULTIPLE, // + target = "(enabled=true)") + protected synchronized void addEss(ManagedSymmetricEss ess) { + this.linearPower.addEss(ess); + } + + protected synchronized void removeEss(ManagedSymmetricEss ess) { + this.linearPower.removeEss(ess); + } + + @Override + public Constraint addSimpleConstraint(ManagedSymmetricEss ess, ConstraintType type, Phase phase, Pwr pwr, + Relationship relationship, int value) { + return this.linearPower.addSimpleConstraint(ess, type, phase, pwr, relationship, value); + } + + @Override + public Constraint addConstraint(Constraint constraint) { + return this.linearPower.addConstraint(constraint); + } + + @Override + public Constraint addSimpleConstraintAndValidate(ManagedSymmetricEss ess, ConstraintType type, Phase phase, Pwr pwr, + Relationship relationship, int value) throws PowerException { + return this.linearPower.addSimpleConstraint(ess, type, phase, pwr, relationship, value); + } + + @Override + public Constraint addConstraintAndValidate(Constraint constraint) throws PowerException { + return this.linearPower.addConstraintAndValidate(constraint); + } + + @Override + public void removeConstraint(Constraint constraint) { + this.linearPower.removeConstraint(constraint); + } + + @Override + public int getMaxActivePower() { + return this.linearPower.getMaxActivePower(); + } + + @Override + public int getMinActivePower() { + return this.linearPower.getMinActivePower(); + } + + @Override + public void handleEvent(Event event) { + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_WRITE: + this.linearPower.applyPower(); + break; + case EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE: + this.linearPower.clearCycleConstraints(); + break; + } + } + +} diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/SymmetricSolution.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/SymmetricSolution.java new file mode 100644 index 00000000000..99c0da5c927 --- /dev/null +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/SymmetricSolution.java @@ -0,0 +1,33 @@ +package io.openems.edge.ess.core.power; + +import io.openems.edge.ess.api.ManagedSymmetricEss; + +public class SymmetricSolution { + + private final ManagedSymmetricEss ess; + private final int activePower; + private final int reactivePower; + + public SymmetricSolution(ManagedSymmetricEss ess, int activePower, int reactivePower) { + this.ess = ess; + this.activePower = activePower; + this.reactivePower = reactivePower; + } + + public ManagedSymmetricEss getEss() { + return ess; + } + + public int getActivePower() { + return activePower; + } + + public int getReactivePower() { + return reactivePower; + } + + @Override + public String toString() { + return "SymmetricSolution [ess=" + ess.id() + ", P=" + activePower + ", Q=" + reactivePower + "]"; + } +} diff --git a/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Utils.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Utils.java new file mode 100644 index 00000000000..fd1c4395fd4 --- /dev/null +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/Utils.java @@ -0,0 +1,244 @@ +package io.openems.edge.ess.core.power; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.math3.optim.linear.LinearConstraint; +import org.apache.commons.math3.optim.linear.LinearObjectiveFunction; +import org.apache.commons.math3.optim.linear.Relationship; +import org.apache.commons.math3.optim.nonlinear.scalar.GoalType; + +import io.openems.common.utils.IntUtils; +import io.openems.common.utils.IntUtils.Round; +import io.openems.edge.ess.api.ManagedAsymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.MetaEss; +import io.openems.edge.ess.power.api.Coefficient; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; + +public class Utils { + + private static String coefficientsToString(double[] coefficients) { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < coefficients.length; i++) { + double x = coefficients[i]; + b.append(String.format("%+.1f*", x)); + switch (i % 2) { + case 0: + b.append("p"); + break; + case 1: + b.append("q"); + break; + } + b.append((i / 2) % 3 + 1); + if (i < coefficients.length - 1) { + b.append(" "); + } + } + return b.toString(); + } + + /** + * Helper: Copies the LinearConstraints list to an array + * + * @param constraints + * @return + */ + public static LinearConstraint[] copyToArray(List constraints) { + LinearConstraint[] c = new LinearConstraint[constraints.size()]; + for (int i = 0; i < constraints.size(); i++) { + c[i] = constraints.get(i); + } + return c; + } + + public static String linearConstraintToString(LinearConstraint constraint, String note) { + StringBuilder b = new StringBuilder(); + b.append(String.format("%-30s ", note)); + double[] coefficients = constraint.getCoefficients().toArray(); + b.append(coefficientsToString(coefficients)); + b.append(" " + constraint.getRelationship().toString() + " " + String.format("%.1f", constraint.getValue())); + return b.toString(); + } + + public static String objectiveFunctionToString(LinearObjectiveFunction function, GoalType goalType) { + StringBuilder b = new StringBuilder(); + b.append(String.format("%-30s ", "Objective Function")); + double[] coefficients = function.getCoefficients().toArray(); + b.append(coefficientsToString(coefficients)); + b.append(" -> " + goalType.toString()); + return b.toString(); + } + + /** + * Round values to accuracy of inverter; following this logic: + * + * On Discharge (Power > 0) + * + *
              + *
            • if SoC > 50 %: round up (more discharge) + *
            • if SoC < 50 %: round down (less discharge) + *
            + * + * On Charge (Power < 0) + * + *
              + *
            • if SoC > 50 %: round down (less charge) + *
            • if SoC < 50 %: round up (more discharge) + *
            + */ + public static int roundToInverterPrecision(ManagedSymmetricEss ess, double value) { + Round round = Round.DOWN; + int precision = ess.getPowerPrecision(); + int soc = ess.getSoc().value().orElse(0); + + if (value > 0 && soc > 50 || value < 0 && soc < 50) { + round = Round.UP; + } + + return IntUtils.roundToPrecision((float) value, round, precision); + } + + public static String solutionToString(double[] solution) { + StringBuilder b = new StringBuilder(); + for (int i = 0; i < solution.length; i++) { + double x = solution[i]; + switch (i % 2) { + case 0: + b.append("p"); + break; + case 1: + b.append("q"); + break; + } + b.append((i / 2) % 3 + 1 + String.format(" = % .1f", x)); + if (i < solution.length - 1) { + b.append(String.format("%n")); + } + } + return b.toString(); + } + + public static void sumSolutions(ManagedSymmetricEss ess, Map solutions, + AtomicInteger activePower, AtomicInteger reactivePower, AtomicInteger activePowerL1, + AtomicInteger reactivePowerL1, AtomicInteger activePowerL2, AtomicInteger reactivePowerL2, + AtomicInteger activePowerL3, AtomicInteger reactivePowerL3) { + if (ess instanceof MetaEss) { + for (ManagedSymmetricEss subEss : ((MetaEss) ess).getEsss()) { + Utils.sumSolutions(subEss, solutions, activePower, reactivePower, activePowerL1, reactivePowerL1, + activePowerL2, reactivePowerL2, activePowerL3, reactivePowerL3); + } + } else { + SymmetricSolution ss = solutions.get(ess); + if (ss != null) { + activePower.addAndGet(ss.getActivePower()); + + if (ess instanceof ManagedAsymmetricEss && ss instanceof AsymmetricSolution) { + AsymmetricSolution as = (AsymmetricSolution) ss; + activePowerL1.addAndGet(as.getActivePowerL1()); + reactivePowerL1.addAndGet(as.getReactivePowerL1()); + activePowerL2.addAndGet(as.getActivePowerL2()); + reactivePowerL2.addAndGet(as.getReactivePowerL2()); + activePowerL3.addAndGet(as.getActivePowerL3()); + reactivePowerL3.addAndGet(as.getReactivePowerL3()); + } + } + } + } + + /** + * Create SymmetricSolution objects for easier handling of a Solution + * + * @param data + * @param solution + * @return + */ + public static Map toSolutions(Data data, double[] solution) { + Map solutions = new HashMap<>(); + data.realEsss.forEach(ess -> { + int i = data.getEssIndex(ess); + + if (ess instanceof ManagedAsymmetricEss) { + /* + * ManagedAsymmetricEss + */ + solutions.put(ess, // + new AsymmetricSolution((ManagedAsymmetricEss) ess, // + Utils.roundToInverterPrecision(ess, + solution[i + Phase.L1.getOffset() + Pwr.ACTIVE.getOffset()]), // + Utils.roundToInverterPrecision(ess, + solution[i + Phase.L1.getOffset() + Pwr.REACTIVE.getOffset()]), // + Utils.roundToInverterPrecision(ess, + solution[i + Phase.L2.getOffset() + Pwr.ACTIVE.getOffset()]), // + Utils.roundToInverterPrecision(ess, + solution[i + Phase.L2.getOffset() + Pwr.REACTIVE.getOffset()]), // + Utils.roundToInverterPrecision(ess, + solution[i + Phase.L3.getOffset() + Pwr.ACTIVE.getOffset()]), // + Utils.roundToInverterPrecision(ess, + solution[i + Phase.L3.getOffset() + Pwr.REACTIVE.getOffset()]))); + } else { + /* + * ManagedSymmetricEss + */ + solutions.put(ess, // + new SymmetricSolution(ess, // + Utils.roundToInverterPrecision(ess, // + solution[i + Phase.L1.getOffset() + Pwr.ACTIVE.getOffset()] // + + solution[i + Phase.L2.getOffset() + Pwr.ACTIVE.getOffset()] // + + solution[i + Phase.L3.getOffset() + Pwr.ACTIVE.getOffset()]), // + Utils.roundToInverterPrecision(ess, // + solution[i + Phase.L1.getOffset() + Pwr.REACTIVE.getOffset()] // + + solution[i + Phase.L2.getOffset() + Pwr.REACTIVE.getOffset()] // + + solution[i + Phase.L3.getOffset() + Pwr.REACTIVE.getOffset()]))); + } + }); + return solutions; + } + + /** + * Create a Simple Constraint + * + * @param ess + * @param type + * @param phase + * @param pwr + * @param relationship + * @param value + * @return + */ + public static Constraint createSimpleConstraint(ManagedSymmetricEss ess, ConstraintType type, Phase phase, Pwr pwr, + Relationship relationship, int value) { + return new Constraint( // + type, new Coefficient[] { // + new Coefficient(ess, phase, pwr, 1) }, // + relationship, // + value); + } + + public static boolean coefficientIsCoveredBy(Coefficient c, ManagedSymmetricEss ess, Phase phase, Pwr pwr) { + if (ess instanceof MetaEss) { + for (ManagedSymmetricEss subEss : ((MetaEss) ess).getEsss()) { + if (Utils.coefficientIsCoveredBy(c, subEss, phase, pwr)) { + return true; + } + } + return false; + } else { + if (c.getEss() == ess // + && c.getPwr() == pwr // + && (phase == Phase.ALL // + || c.getPhase() == phase // + )) { + return true; + } + return false; + } + } + +} diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/api/package-info.java b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/package-info.java similarity index 53% rename from io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/api/package-info.java rename to io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/package-info.java index d3fbc40ece7..ab23779f33c 100644 --- a/io.openems.edge.ess.api/src/io/openems/edge/ess/symmetric/api/package-info.java +++ b/io.openems.edge.ess.core/src/io/openems/edge/ess/core/power/package-info.java @@ -1,2 +1,2 @@ @org.osgi.annotation.versioning.Version("1.0.0") -package io.openems.edge.ess.symmetric.api; +package io.openems.edge.ess.core.power; diff --git a/io.openems.edge.ess.core/test/.gitignore b/io.openems.edge.ess.core/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/api/EssClusterDummy.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/api/EssClusterDummy.java new file mode 100644 index 00000000000..5737d4eae62 --- /dev/null +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/api/EssClusterDummy.java @@ -0,0 +1,122 @@ +package io.openems.edge.ess.api; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.core.power.LinearPower; +import io.openems.edge.ess.power.api.Power; + +public class EssClusterDummy extends AbstractOpenemsComponent implements ManagedAsymmetricEss, MetaEss { + + private final List managedEsss = new ArrayList<>(); + private LinearPower power; + + public EssClusterDummy(SymmetricEss... esss) { + Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(this, channelId); + } + return null; + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case ACTIVE_POWER: + case REACTIVE_POWER: + case MAX_ACTIVE_POWER: + case ACTIVE_CHARGE_ENERGY: + case ACTIVE_DISCHARGE_ENERGY: + return new IntegerReadChannel(this, channelId); + case GRID_MODE: + return new IntegerReadChannel(this, channelId, SymmetricEss.GridMode.UNDEFINED); + } + return null; + }), Arrays.stream(AsymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case ACTIVE_POWER_L1: + case ACTIVE_POWER_L2: + case ACTIVE_POWER_L3: + case REACTIVE_POWER_L1: + case REACTIVE_POWER_L2: + case REACTIVE_POWER_L3: + return new IntegerReadChannel(this, channelId); + } + return null; + }), Arrays.stream(ManagedSymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER: + case DEBUG_SET_REACTIVE_POWER: + return new IntegerReadChannel(this, channelId); + } + return null; + }), Arrays.stream(ManagedAsymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER_L1: + case DEBUG_SET_ACTIVE_POWER_L2: + case DEBUG_SET_ACTIVE_POWER_L3: + case DEBUG_SET_REACTIVE_POWER_L1: + case DEBUG_SET_REACTIVE_POWER_L2: + case DEBUG_SET_REACTIVE_POWER_L3: + return new IntegerReadChannel(this, channelId); + } + return null; + })).flatMap(channel -> channel).forEach(channel -> this.addChannel(channel)); + + /* + * Add all ManagedSymmetricEss devices to this.managedEsss + */ + for (SymmetricEss ess : esss) { + if (ess instanceof ManagedSymmetricEss) { + this.managedEsss.add((ManagedSymmetricEss) ess); + } + } + } + + @Override + public int getPowerPrecision() { + return 1; + } + + @Override + public String id() { + return "dummy"; + } + + @Override + public String servicePid() { + return "no_service_pid"; + } + + @Override + public boolean isEnabled() { + return true; + } + + @Override + public List getEsss() { + return this.managedEsss; + } + + @Override + public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, + int activePowerL3, int reactivePowerL3) { + throw new IllegalArgumentException("EssClusterImpl.applyPower() should never be called."); + } + + public void addToPower(LinearPower power) { + this.power = power; + power.addEss(this); + } + + @Override + public Power getPower() { + return this.power; + } +} diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/api/LinearPowerTest.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/api/LinearPowerTest.java new file mode 100644 index 00000000000..88b1afc4e48 --- /dev/null +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/api/LinearPowerTest.java @@ -0,0 +1,458 @@ +package io.openems.edge.ess.api; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.commons.math3.optim.linear.Relationship; +import org.junit.Test; + +import io.openems.edge.ess.core.power.LinearPower; +import io.openems.edge.ess.power.api.CircleConstraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.power.api.PowerException; +import io.openems.edge.ess.power.api.Pwr; + +public class LinearPowerTest { + + public static final double DELTA_IN_PERCENT = 10; // + + private static final double ZERO_TOLERANCE = 0; + + Power sut; + + @Test + public void testSymmetric() throws Exception { + ManagedSymmetricEssDummy ess0 = new ManagedSymmetricEssDummy() { + @Override + public void applyPower(int activePower, int reactivePower) { + assertEquals(1000, activePower); + assertEquals(500, reactivePower); + } + }; + + LinearPower power = new LinearPower(); + ess0.addToPower(power); + + ess0.addPowerConstraint(ConstraintType.CYCLE, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, 1000); + ess0.addPowerConstraint(ConstraintType.CYCLE, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, 500); + + power.applyPower(); + } + + @Test + public void testAsymmetric() throws Exception { + ManagedAsymmetricEssDummy ess0 = new ManagedAsymmetricEssDummy() { + @Override + public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, + int activePowerL3, int reactivePowerL3) { + assertEquals(999 /* caused by rounding errors */, activePowerL1 + activePowerL2 + activePowerL3); + assertEquals(498 /* caused by rounding errors */, reactivePowerL1 + reactivePowerL2 + reactivePowerL3); + } + }; + + LinearPower power = new LinearPower(); + ess0.addToPower(power); + + ess0.addPowerConstraint(ConstraintType.CYCLE, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, 1000); + ess0.addPowerConstraint(ConstraintType.CYCLE, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, 500); + + power.applyPower(); + } + + @Test + public void testCluster() throws Exception { + AtomicInteger totalActivePower = new AtomicInteger(); + AtomicInteger totalReactivePower = new AtomicInteger(); + + ManagedSymmetricEssDummy ess1 = new ManagedSymmetricEssDummy() { + @Override + public void applyPower(int activePower, int reactivePower) { + totalActivePower.addAndGet(activePower); + totalReactivePower.addAndGet(reactivePower); + } + }; + + ManagedAsymmetricEssDummy ess2 = new ManagedAsymmetricEssDummy() { + @Override + public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, + int activePowerL3, int reactivePowerL3) { + totalActivePower.addAndGet(activePowerL1 + activePowerL2 + activePowerL3); + totalReactivePower.addAndGet(reactivePowerL1 + reactivePowerL2 + reactivePowerL3); + } + }; + EssClusterDummy ess0 = new EssClusterDummy(ess1, ess2); + + LinearPower power = new LinearPower(); + ess1.addToPower(power); + ess2.addToPower(power); + ess0.addToPower(power); + + ess0.addPowerConstraint(ConstraintType.CYCLE, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, 1000); + ess0.addPowerConstraint(ConstraintType.CYCLE, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, 500); + + power.applyPower(); + + assertEquals(998 /* caused by rounding errors */, totalActivePower.get()); + assertEquals(499 /* caused by rounding errors */, totalReactivePower.get()); + } + + @Test + public void testClusterDistribution() throws Exception { + ManagedSymmetricEssDummy ess1 = new ManagedSymmetricEssDummy() { + @Override + public void applyPower(int activePower, int reactivePower) { + assertEquals(500, activePower); + assertEquals(250, reactivePower); + } + }; + + ManagedAsymmetricEssDummy ess2 = new ManagedAsymmetricEssDummy() { + @Override + public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, + int activePowerL3, int reactivePowerL3) { + assertEquals(498 /* caused by rounding errors */, activePowerL1 + activePowerL2 + activePowerL3); + assertEquals(249 /* caused by rounding errors */, reactivePowerL1 + reactivePowerL2 + reactivePowerL3); + } + }; + EssClusterDummy ess0 = new EssClusterDummy(ess1, ess2); + + LinearPower power = new LinearPower(); + ess1.addToPower(power); + ess2.addToPower(power); + ess0.addToPower(power); + + ess0.addPowerConstraint(ConstraintType.CYCLE, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, 1000); + ess0.addPowerConstraint(ConstraintType.CYCLE, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, 500); + + power.applyPower(); + } + + @Test + public void testMaxActivePower() throws Exception { + ManagedAsymmetricEssDummy ess0 = new ManagedAsymmetricEssDummy() { + @Override + public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, + int activePowerL3, int reactivePowerL3) { + } + }; + + LinearPower power = new LinearPower(); + ess0.addToPower(power); + + new CircleConstraint(ess0, 1000); + + assertEquals(1000, ess0.getPower().getMaxActivePower()); + } + + @Test + public void testMinActivePower() throws Exception { + ManagedAsymmetricEssDummy ess0 = new ManagedAsymmetricEssDummy() { + @Override + public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, + int activePowerL3, int reactivePowerL3) { + } + }; + + LinearPower power = new LinearPower(); + ess0.addToPower(power); + + new CircleConstraint(ess0, 1000); + + assertEquals(-1000, ess0.getPower().getMinActivePower()); + } + + @Test + public void testSetActiveAndReactiveToZero() { + int givenActivePower = 0; + int givenReactivePower = 0; + + ManagedSymmetricEssDummy ess = createSymmetricEss(givenActivePower, givenReactivePower, ZERO_TOLERANCE); + + LinearPower power = new LinearPower(); + ess.addToPower(power); + + ess.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, 0); + ess.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, 0); + + power.applyPower(); + } + + @Test + public void testSetActivePower() { + int givenActivePower = 1000; + int givenReactivePower = 0; + + ManagedSymmetricEssDummy ess = createSymmetricEss(givenActivePower, givenReactivePower, ZERO_TOLERANCE); + + LinearPower power = new LinearPower(); + ess.addToPower(power); + + ess.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, givenActivePower); + ess.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, givenReactivePower); + + power.applyPower(); + } + + @Test + public void testApparentPowerAndActivePower() { + int maxApparentPower = 2000; + int givenActivePower = 1000; + int givenReactivePower = 0; + + ManagedSymmetricEssDummy ess0 = createSymmetricEss(givenActivePower, givenReactivePower, DELTA_IN_PERCENT); + + LinearPower power = new LinearPower(); + ess0.addToPower(power); + + try { + ess0.addPowerConstraintAndValidate(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, Relationship.EQ, + givenActivePower); + ess0.addPowerConstraintAndValidate(ConstraintType.STATIC, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, + givenReactivePower); + + new CircleConstraint(ess0, maxApparentPower); + } catch (PowerException e) { + fail(e.getMessage()); + } + + power.applyPower(); + } + + @Test + public void testGivenPowerGreaterThanMaxApparentPower() { + int maxApparentPower = 1000; + int givenActivePower = 2000; + int givenReactivePower = 0; + + ManagedSymmetricEssDummy ess = createSymmetricEss(givenActivePower, givenReactivePower, DELTA_IN_PERCENT); + + LinearPower power = new LinearPower(); + ess.addToPower(power); + + try { + new CircleConstraint(ess, maxApparentPower); + + ess.addPowerConstraintAndValidate(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, Relationship.GEQ, + givenActivePower); + ess.addPowerConstraintAndValidate(ConstraintType.STATIC, Phase.ALL, Pwr.REACTIVE, Relationship.EQ, + givenReactivePower); + + fail("GivenPowerGreaterThanMaxApparentPower"); + + } catch (PowerException e) { + assertEquals(PowerException.Type.NO_FEASIBLE_SOLUTION, e.getType()); + } + } + +// @Test // TODO +// public void testGivenPowerAndReactivePower() { +// int maxApparentPower = 2000; +// int givenActivePower = 1800; +// int givenReactivePower = 1000; +// +// // fails currently, because reactive power result was -835 => Math.sqrt(1800 + +// // (-835)) = 1984, should we work with a delta percent=? +// // awaited result Math.sqrt(2000 - 1800) = +/-871,779... Difference = +// // 36,779... ==> 36,../871,.. * 100 = 4,21...% +// // do i know if it was plus or minus? +// ManagedSymmetricEssDummy ess = createSymmetricEss(givenActivePower, givenReactivePower, DELTA_IN_PERCENT); +// sut = new Power(ess); +// +// try { +// sut.setActivePowerAndSolve(ConstraintType.STATIC, Relationship.GEQ, 0); +// sut.setActivePowerAndSolve(ConstraintType.STATIC, Relationship.GEQ, givenActivePower); +// sut.setReactivePower(ConstraintType.STATIC, Relationship.LEQ, givenReactivePower); +// sut.setMaxApparentPower(ess, maxApparentPower); +// sut.applyPower(); +// } catch (PowerException e) { +// fail(e.getMessage()); +// } +// } +// +// @Test +// public void testAsymmetricAllSetToZero() { +// int givenActivePowerL1 = 0; +// int givenActivePowerL2 = 0; +// int givenActivePowerL3 = 0; +// +// int givenReactivePowerL1 = 0; +// int givenReactivePowerL2 = 0; +// int givenReactivePowerL3 = 0; +// +// ManagedAsymmetricEssDummy ess = createAsymmetricEss( +// Arrays.asList(givenActivePowerL1, givenActivePowerL2, givenActivePowerL3), +// Arrays.asList(givenReactivePowerL1, givenReactivePowerL2, givenReactivePowerL3), DELTA_IN_PERCENT); +// +// sut = new Power(ess); +// try { +// ConstraintType constraintType = ConstraintType.STATIC; +// Relationship relationship = Relationship.EQ; +// +// sut.setActivePowerAndSolve(constraintType, relationship, ess, Phase.L1, givenActivePowerL1); +// sut.setActivePowerAndSolve(constraintType, relationship, ess, Phase.L2, givenActivePowerL2); +// sut.setActivePowerAndSolve(constraintType, relationship, ess, Phase.L3, givenActivePowerL3); +// sut.setReactivePowerAndSolve(ConstraintType.STATIC, Relationship.EQ, 0); +// sut.applyPower(); +// +// } catch (PowerException e) { +// fail(e.getMessage()); +// } +// } +// +// @Test +// public void testAsymmetricNoRestrictions() { +// int givenActivePowerL1 = 1000; +// int givenActivePowerL2 = 800; +// int givenActivePowerL3 = 1200; +// +// ManagedAsymmetricEssDummy ess = createAsymmetricEss( +// Arrays.asList(givenActivePowerL1, givenActivePowerL2, givenActivePowerL3), Arrays.asList(0, 0, 0), +// DELTA_IN_PERCENT); +// +// sut = new Power(ess); +// try { +// ConstraintType constraintType = ConstraintType.STATIC; +// Relationship relationship = Relationship.EQ; +// +// sut.setActivePowerAndSolve(constraintType, relationship, ess, Phase.L1, givenActivePowerL1); +// sut.setActivePowerAndSolve(constraintType, relationship, ess, Phase.L2, givenActivePowerL2); +// sut.setActivePowerAndSolve(constraintType, relationship, ess, Phase.L3, givenActivePowerL3); +// sut.setReactivePower(ConstraintType.STATIC, Relationship.EQ, 0); +// sut.applyPower(); +// +// } catch (PowerException e) { +// fail(e.getMessage()); +// } +// } +// +// @Test +// public void testApparentPowerSmallerThanThreeTimesActivePower() { +// int maxApparentPower = 3000; +// int givenActivePowerL1 = 2000; +// int givenActivePowerL2 = 5000; +// int givenActivePowerL3 = 6000; +// int givenReactivePowerL1 = 2000; +// int givenReactivePowerL2 = 2000; +// int givenReactivePowerL3 = 2000; +// +// ManagedAsymmetricEssDummy ess0 = new ManagedAsymmetricEssDummy() { +// @Override +// public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, +// int activePowerL3, int reactivePowerL3) { +// assertEquals(givenActivePowerL1, activePowerL1); +// assertEquals(givenActivePowerL2, activePowerL2); +// assertEquals(givenActivePowerL3, activePowerL3); +// +// assertEquals(givenReactivePowerL1, reactivePowerL1); +// assertEquals(givenReactivePowerL2, reactivePowerL2); +// assertEquals(givenReactivePowerL3, reactivePowerL3); +// } +// +// }; +// +// sut = new Power(ess0); +// try { +// sut.setMaxApparentPower(ess0, maxApparentPower); +// +// sut.setActivePowerAndSolve(ConstraintType.STATIC, Relationship.GEQ, ess0, Phase.L1, givenActivePowerL1); +// sut.setActivePowerAndSolve(ConstraintType.STATIC, Relationship.GEQ, ess0, Phase.L2, givenActivePowerL2); +// sut.setActivePowerAndSolve(ConstraintType.STATIC, Relationship.GEQ, ess0, Phase.L3, givenActivePowerL3); +// +// sut.setReactivePowerAndSolve(ConstraintType.STATIC, Relationship.GEQ, ess0, Phase.L1, givenReactivePowerL1); +// sut.setReactivePowerAndSolve(ConstraintType.STATIC, Relationship.GEQ, ess0, Phase.L2, givenReactivePowerL2); +// sut.setReactivePowerAndSolve(ConstraintType.STATIC, Relationship.GEQ, ess0, Phase.L3, givenReactivePowerL3); +// +// sut.applyPower(); +// } catch (PowerException e) { +// fail(e.getMessage()); +// } +// } +// +// public boolean isBetween(double value, double bottomLimit, double upperLimit) { +// return value > bottomLimit && value < upperLimit; +// } +// + void checkValues(int expectedActive, int expectedReactive, int actualActive, int actualReactive, + double deltaPercent) { + double deltaActive = expectedActive * deltaPercent / 100; + double deltaReactive = expectedReactive * deltaPercent / 100; + assertEquals(expectedActive, actualActive, deltaActive); + assertEquals(expectedReactive, actualReactive, deltaReactive); + } + + void checkValues(Map expectedActualValues, double deltaPercent) { + for (Entry entry : expectedActualValues.entrySet()) { + Integer expected = entry.getKey(); + Integer actual = entry.getValue(); + double delta = expected * deltaPercent / 100; + assertEquals(expected, actual, delta); + } + } + + private ManagedSymmetricEssDummy createSymmetricEss(int expectedActivePower, int expectedReactivePower, + double deltaPercent) { + return new ManagedSymmetricEssDummy() { + @Override + public void applyPower(int activePower, int reactivePower) { + checkValues(expectedActivePower, expectedReactivePower, activePower, reactivePower, deltaPercent); + } + }; + } + +// private ManagedAsymmetricEssDummy createAsymmetricEss(List activePower, List reactivePower, +// double deltaPercent) { +// return new ManagedAsymmetricEssDummy() { +// +// @Override +// public void applyPower(int activePowerL1, int reactivePowerL1, int activePowerL2, int reactivePowerL2, +// int activePowerL3, int reactivePowerL3) { +// Map valuesToCheck = new HashMap<>(); +// valuesToCheck.put(activePower.get(0), activePowerL1); +// valuesToCheck.put(activePower.get(1), activePowerL2); +// valuesToCheck.put(activePower.get(2), activePowerL3); +// +// valuesToCheck.put(reactivePower.get(0), reactivePowerL1); +// valuesToCheck.put(reactivePower.get(1), reactivePowerL2); +// valuesToCheck.put(reactivePower.get(2), reactivePowerL3); +// +// checkValues(valuesToCheck, deltaPercent); +// } +// +// }; +// } +// +// @Test +// public void testSetActivePowerConstraintTypeRelationshipInt() { +// sut = new Power(new ManagedSymmetricEssDummy()); +// int activePower = 1000; +// +// int value = activePower; +// Relationship relationship = Relationship.LEQ; +// int[] indices = { 0 }; +// int noOfCoefficients = 2; +// CoefficientOneConstraint expectedConstraint = new CoefficientOneConstraint(noOfCoefficients, indices, +// relationship, value, "Expected Constraint"); +// LinearConstraint[] expected = expectedConstraint.getConstraints(); +// +// ConstraintType constraintType = ConstraintType.STATIC; +// try { +// CoefficientOneConstraint actualConstraint = sut.setActivePowerAndSolve(constraintType, relationship, +// activePower); +// LinearConstraint[] actual = actualConstraint.getConstraints(); +// +// assertEquals(expected.length, actual.length); +// for (int i = 0; i < expected.length; i++) { +// assertEquals(expected[i], actual[i]); +// } +// +// } catch (PowerException e) { +// fail(e.getMessage()); +// } +// } +} diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/api/ManagedAsymmetricEssDummy.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/api/ManagedAsymmetricEssDummy.java new file mode 100644 index 00000000000..95623d74dc4 --- /dev/null +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/api/ManagedAsymmetricEssDummy.java @@ -0,0 +1,99 @@ +package io.openems.edge.ess.api; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.core.power.LinearPower; +import io.openems.edge.ess.power.api.Power; + +public abstract class ManagedAsymmetricEssDummy extends AbstractOpenemsComponent implements ManagedAsymmetricEss { + + private LinearPower power; + + public ManagedAsymmetricEssDummy() { + Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(this, channelId); + } + return null; + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case ACTIVE_POWER: + case REACTIVE_POWER: + case MAX_ACTIVE_POWER: + case ACTIVE_CHARGE_ENERGY: + case ACTIVE_DISCHARGE_ENERGY: + return new IntegerReadChannel(this, channelId); + case GRID_MODE: + return new IntegerReadChannel(this, channelId, SymmetricEss.GridMode.UNDEFINED.ordinal()); + } + return null; + }), Arrays.stream(AsymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case ACTIVE_POWER_L1: + case ACTIVE_POWER_L2: + case ACTIVE_POWER_L3: + case REACTIVE_POWER_L1: + case REACTIVE_POWER_L2: + case REACTIVE_POWER_L3: + return new IntegerReadChannel(this, channelId); + } + return null; + }), Arrays.stream(ManagedSymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER: + case DEBUG_SET_REACTIVE_POWER: + return new IntegerReadChannel(this, channelId); + } + return null; + }), Arrays.stream(ManagedAsymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER_L1: + case DEBUG_SET_ACTIVE_POWER_L2: + case DEBUG_SET_ACTIVE_POWER_L3: + case DEBUG_SET_REACTIVE_POWER_L1: + case DEBUG_SET_REACTIVE_POWER_L2: + case DEBUG_SET_REACTIVE_POWER_L3: + return new IntegerReadChannel(this, channelId); + } + return null; + })).flatMap(channel -> channel).forEach(channel -> this.addChannel(channel)); + } + + @Override + public int getPowerPrecision() { + return 1; + } + + @Override + public String id() { + return "dummy"; + } + + @Override + public String servicePid() { + return "no_service_pid"; + } + + @Override + public boolean isEnabled() { + return true; + } + + public void addToPower(LinearPower power) { + this.power = power; + power.addEss(this); + } + + @Override + public Power getPower() { + return this.power; + } +} diff --git a/io.openems.edge.ess.core/test/io/openems/edge/ess/api/ManagedSymmetricEssDummy.java b/io.openems.edge.ess.core/test/io/openems/edge/ess/api/ManagedSymmetricEssDummy.java new file mode 100644 index 00000000000..bb5abd0bebc --- /dev/null +++ b/io.openems.edge.ess.core/test/io/openems/edge/ess/api/ManagedSymmetricEssDummy.java @@ -0,0 +1,78 @@ +package io.openems.edge.ess.api; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.core.power.LinearPower; +import io.openems.edge.ess.power.api.Power; + +public abstract class ManagedSymmetricEssDummy extends AbstractOpenemsComponent implements ManagedSymmetricEss { + + private LinearPower power = null; + + public ManagedSymmetricEssDummy() { + Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(this, channelId); + } + return null; + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case ACTIVE_POWER: + case REACTIVE_POWER: + case MAX_ACTIVE_POWER: + case ACTIVE_CHARGE_ENERGY: + case ACTIVE_DISCHARGE_ENERGY: + return new IntegerReadChannel(this, channelId); + case GRID_MODE: + return new IntegerReadChannel(this, channelId, SymmetricEss.GridMode.UNDEFINED.ordinal()); + } + return null; + }), Arrays.stream(ManagedSymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER: + case DEBUG_SET_REACTIVE_POWER: + return new IntegerReadChannel(this, channelId); + } + return null; + })).flatMap(channel -> channel).forEach(channel -> this.addChannel(channel)); + } + + @Override + public int getPowerPrecision() { + return 1; + } + + @Override + public String id() { + return "dummy"; + } + + @Override + public String servicePid() { + return "no_service_pid"; + } + + @Override + public boolean isEnabled() { + return true; + } + + public void addToPower(LinearPower power) { + this.power = power; + power.addEss(this); + } + + @Override + public Power getPower() { + return this.power; + } + +} diff --git a/io.openems.edge.ess.fenecon.commercial40/bnd.bnd b/io.openems.edge.ess.fenecon.commercial40/bnd.bnd index 21338e77eff..b072e16cf03 100644 --- a/io.openems.edge.ess.fenecon.commercial40/bnd.bnd +++ b/io.openems.edge.ess.fenecon.commercial40/bnd.bnd @@ -7,7 +7,7 @@ Export-Package: \ io.openems.edge.ess.api,\ io.openems.edge.ess.symmetric.api,\ io.openems.edge.ess.power.symmetric,\ - io.openems.edge.ess.power,\ + io.openems.edge.ess.power.api,\ io.openems.edge.ess.dccharger.api,\ io.openems.edge.ess.fenecon.commercial40,\ io.openems.edge.ess.fenecon.commercial40.charger diff --git a/io.openems.edge.ess.fenecon.commercial40/doc/BYD MODBUS Register List CESS DC.xlsx b/io.openems.edge.ess.fenecon.commercial40/doc/BYD MODBUS Register List CESS DC.xlsx new file mode 100644 index 00000000000..0e877e0bb6e Binary files /dev/null and b/io.openems.edge.ess.fenecon.commercial40/doc/BYD MODBUS Register List CESS DC.xlsx differ diff --git a/io.openems.edge.ess.fenecon.commercial40/doc/Modbus_Register_COMMERCIAL_AC_v1.14.xlsx b/io.openems.edge.ess.fenecon.commercial40/doc/Modbus_Register_COMMERCIAL_AC_v1.14.xlsx new file mode 100644 index 00000000000..d82a7842ea4 Binary files /dev/null and b/io.openems.edge.ess.fenecon.commercial40/doc/Modbus_Register_COMMERCIAL_AC_v1.14.xlsx differ diff --git a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40.java b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40.java index f32d6eb66bc..38a46da9559 100644 --- a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40.java +++ b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/EssFeneconCommercial40.java @@ -2,6 +2,7 @@ import java.time.LocalDateTime; +import org.apache.commons.math3.optim.linear.Relationship; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; @@ -32,27 +33,23 @@ import io.openems.edge.bridge.modbus.api.element.WordOrder; import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; -import io.openems.edge.bridge.modbus.api.task.Priority; import io.openems.edge.common.channel.IntegerWriteChannel; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.channel.doc.Level; import io.openems.edge.common.channel.doc.Unit; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.taskmanager.Priority; import io.openems.edge.common.type.TypeUtils; -import io.openems.edge.ess.api.Ess; -import io.openems.edge.ess.power.symmetric.PGreaterEqualLimitation; -import io.openems.edge.ess.power.symmetric.PSmallerEqualLimitation; -import io.openems.edge.ess.power.symmetric.QGreaterEqualLimitation; -import io.openems.edge.ess.power.symmetric.QSmallerEqualLimitation; -import io.openems.edge.ess.power.symmetric.SMaxLimitation; -import io.openems.edge.ess.power.symmetric.SymmetricPower; -import io.openems.edge.ess.symmetric.api.SymmetricEss; -import io.openems.edge.ess.symmetric.readonly.api.SymmetricEssReadonly; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.CircleConstraint; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.power.api.Pwr; -/** - * Implements the FENECON Commercial 40 energy storage system. - */ @Designate(ocd = Config.class, factory = true) @Component( // name = "Ess.Fenecon.Commercial40", // @@ -61,74 +58,42 @@ property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_CONTROLLERS // ) public class EssFeneconCommercial40 extends AbstractOpenemsModbusComponent - implements SymmetricEss, Ess, OpenemsComponent, EventHandler { + implements ManagedSymmetricEss, SymmetricEss, OpenemsComponent, EventHandler { - private final Logger log = LoggerFactory.getLogger(AbstractOpenemsModbusComponent.class); + private final Logger log = LoggerFactory.getLogger(EssFeneconCommercial40.class); - private final static int UNIT_ID = 100; protected final static int MAX_APPARENT_POWER = 40000; + + private final static int UNIT_ID = 100; private final static int MIN_REACTIVE_POWER = -10000; private final static int MAX_REACTIVE_POWER = 10000; - private final static int POWER_PRECISION = 100; - - private final SymmetricPower power; - private final SMaxLimitation allowedApparentLimit; - private final PGreaterEqualLimitation allowedChargeLimit; - private final PSmallerEqualLimitation allowedDischargeLimit; private String modbusBridgeId; + @Reference + private Power power; + @Reference protected ConfigurationAdmin cm; public EssFeneconCommercial40() { Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); - /* - * Initialize Power - */ - this.power = new SymmetricPower(this, EssFeneconCommercial40.MAX_APPARENT_POWER, - EssFeneconCommercial40.POWER_PRECISION, // - (activePower, reactivePower) -> { - /* - * Apply Active/Reactive power - */ - IntegerWriteChannel setActivePowerChannel = this.channel(ChannelId.SET_ACTIVE_POWER); - IntegerWriteChannel setReactivePowerChannel = this.channel(ChannelId.SET_REACTIVE_POWER); - try { - setActivePowerChannel.setNextWriteValue(activePower); - } catch (OpenemsException e) { - log.error("Unable to set ActivePower: " + e.getMessage()); - } - try { - setReactivePowerChannel.setNextWriteValue(reactivePower); - } catch (OpenemsException e) { - log.error("Unable to set ReactivePower: " + e.getMessage()); - } - }); - // ReactivePower limitations - this.power.addStaticLimitation(new QGreaterEqualLimitation(this.power).setQ(MIN_REACTIVE_POWER)); - this.power.addStaticLimitation(new QSmallerEqualLimitation(this.power).setQ(MAX_REACTIVE_POWER)); - // Allowed Apparent - this.power.addStaticLimitation( // - this.allowedApparentLimit = new SMaxLimitation(this.power).setSMax(0, 0, 0) // - ); - this.channel(ChannelId.ALLOWED_APPARENT).onUpdate(value -> { - this.allowedApparentLimit.setSMax(TypeUtils.getAsType(OpenemsType.INTEGER, value), 0, 0); - }); - // Allowed Charge - this.power.addStaticLimitation( // - this.allowedChargeLimit = new PGreaterEqualLimitation(this.power).setP(0) // - ); - this.channel(ChannelId.ALLOWED_CHARGE).onUpdate(value -> { - this.allowedChargeLimit.setP(TypeUtils.getAsType(OpenemsType.INTEGER, value)); - }); - // Allowed Discharge - this.power.addStaticLimitation( // - this.allowedDischargeLimit = new PSmallerEqualLimitation(this.power).setP(0) // - ); - this.channel(ChannelId.ALLOWED_DISCHARGE).onUpdate(value -> { - this.allowedDischargeLimit.setP(TypeUtils.getAsType(OpenemsType.INTEGER, value)); - }); + } + + @Override + public void applyPower(int activePower, int reactivePower) { + IntegerWriteChannel setActivePowerChannel = this.channel(ChannelId.SET_ACTIVE_POWER); + IntegerWriteChannel setReactivePowerChannel = this.channel(ChannelId.SET_REACTIVE_POWER); + try { + setActivePowerChannel.setNextWriteValue(activePower); + } catch (OpenemsException e) { + log.error("Unable to set ActivePower: " + e.getMessage()); + } + try { + setReactivePowerChannel.setNextWriteValue(reactivePower); + } catch (OpenemsException e) { + log.error("Unable to set ReactivePower: " + e.getMessage()); + } } @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) @@ -141,6 +106,30 @@ void activate(ComponentContext context, Config config) { super.activate(context, config.service_pid(), config.id(), config.enabled(), UNIT_ID, this.cm, "Modbus", config.modbus_id()); this.modbusBridgeId = config.modbus_id(); + + /* + * Initialize Power + */ + // ReactivePower limitations + this.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.REACTIVE, Relationship.GEQ, MIN_REACTIVE_POWER); + this.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.REACTIVE, Relationship.LEQ, MAX_REACTIVE_POWER); + // Allowed Apparent + CircleConstraint allowedApparentConstraint = new CircleConstraint(this, MAX_APPARENT_POWER); + this.channel(ChannelId.ALLOWED_APPARENT).onChange(value -> { + allowedApparentConstraint.setRadius(TypeUtils.getAsType(OpenemsType.INTEGER, value)); + }); + // Allowed Charge + Constraint allowedChargeConstraint = this.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, + Relationship.GEQ, 0); + this.channel(ChannelId.ALLOWED_CHARGE).onChange(value -> { + allowedChargeConstraint.setIntValue(TypeUtils.getAsType(OpenemsType.INTEGER, value)); + }); + // Allowed Discharge + Constraint allowedDischargeConstraint = this.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, + Relationship.LEQ, 0); + this.channel(ChannelId.ALLOWED_DISCHARGE).onChange(value -> { + allowedDischargeConstraint.setIntValue(TypeUtils.getAsType(OpenemsType.INTEGER, value)); + }); } @Deactivate @@ -213,10 +202,10 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { ALLOWED_CHARGE(new Doc().unit(Unit.WATT)), // ALLOWED_DISCHARGE(new Doc().unit(Unit.WATT)), // ALLOWED_APPARENT(new Doc().unit(Unit.VOLT_AMPERE)), // - IPM_TEMPERATURE_L1(new Doc().unit(Unit.DEGREE_CELCIUS)), // - IPM_TEMPERATURE_L2(new Doc().unit(Unit.DEGREE_CELCIUS)), // - IPM_TEMPERATURE_L3(new Doc().unit(Unit.DEGREE_CELCIUS)), // - TRANSFORMER_TEMPERATURE_L2(new Doc().unit(Unit.DEGREE_CELCIUS)), // + IPM_TEMPERATURE_L1(new Doc().unit(Unit.DEGREE_CELSIUS)), // + IPM_TEMPERATURE_L2(new Doc().unit(Unit.DEGREE_CELSIUS)), // + IPM_TEMPERATURE_L3(new Doc().unit(Unit.DEGREE_CELSIUS)), // + TRANSFORMER_TEMPERATURE_L2(new Doc().unit(Unit.DEGREE_CELSIUS)), // SET_WORK_STATE(new Doc() // .option(4, SetWorkState.STOP) // .option(32, SetWorkState.STANDBY) // @@ -408,13 +397,13 @@ protected ModbusProtocol defineModbusProtocol(int unitId) { new DummyRegisterElement(0x0103), // WorkMode: RemoteDispatch m(EssFeneconCommercial40.ChannelId.BATTERY_MAINTENANCE_STATE, new UnsignedWordElement(0x0104)), m(EssFeneconCommercial40.ChannelId.INVERTER_STATE, new UnsignedWordElement(0x0105)), - m(Ess.ChannelId.GRID_MODE, new UnsignedWordElement(0x0106), // + m(SymmetricEss.ChannelId.GRID_MODE, new UnsignedWordElement(0x0106), // new ElementToChannelConverter((value) -> { switch (TypeUtils.getAsType(OpenemsType.INTEGER, value)) { case 1: - return Ess.GridMode.OFF_GRID.ordinal(); + return SymmetricEss.GridMode.OFF_GRID.ordinal(); case 2: - return Ess.GridMode.ON_GRID.ordinal(); + return SymmetricEss.GridMode.ON_GRID.ordinal(); } throw new IllegalArgumentException("Undefined GridMode [" + value + "]"); })), @@ -586,16 +575,16 @@ protected ModbusProtocol defineModbusProtocol(int unitId) { m(EssFeneconCommercial40.ChannelId.BATTERY_POWER, new SignedWordElement(0x0202), ElementToChannelConverter.SCALE_FACTOR_2), // new DummyRegisterElement(0x0203, 0x0207), - m(EssFeneconCommercial40.ChannelId.AC_CHARGE_ENERGY, + m(SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY, new UnsignedDoublewordElement(0x0208).wordOrder(WordOrder.LSWMSW), ElementToChannelConverter.SCALE_FACTOR_2), // - m(EssFeneconCommercial40.ChannelId.AC_DISCHARGE_ENERGY, + m(SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0x020A).wordOrder(WordOrder.LSWMSW), ElementToChannelConverter.SCALE_FACTOR_2), // new DummyRegisterElement(0x020C, 0x020F), // m(EssFeneconCommercial40.ChannelId.GRID_ACTIVE_POWER, new SignedWordElement(0x0210), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SymmetricEssReadonly.ChannelId.REACTIVE_POWER, new SignedWordElement(0x0211), + m(SymmetricEss.ChannelId.REACTIVE_POWER, new SignedWordElement(0x0211), ElementToChannelConverter.SCALE_FACTOR_2), // m(EssFeneconCommercial40.ChannelId.APPARENT_POWER, new UnsignedWordElement(0x0212), ElementToChannelConverter.SCALE_FACTOR_2), // @@ -626,7 +615,7 @@ protected ModbusProtocol defineModbusProtocol(int unitId) { ElementToChannelConverter.SCALE_FACTOR_2), // m(EssFeneconCommercial40.ChannelId.INVERTER_CURRENT_L3, new SignedWordElement(0x0227), ElementToChannelConverter.SCALE_FACTOR_2), // - m(SymmetricEssReadonly.ChannelId.ACTIVE_POWER, new SignedWordElement(0x0228), + m(SymmetricEss.ChannelId.ACTIVE_POWER, new SignedWordElement(0x0228), ElementToChannelConverter.SCALE_FACTOR_2), // new DummyRegisterElement(0x0229, 0x022F), // m(EssFeneconCommercial40.ChannelId.ALLOWED_CHARGE, new SignedWordElement(0x0230), @@ -686,7 +675,7 @@ protected ModbusProtocol defineModbusProtocol(int unitId) { .m(EssFeneconCommercial40.ChannelId.STATE_149, 2) // .build()), // new FC3ReadRegistersTask(0x1402, Priority.HIGH, // - m(Ess.ChannelId.SOC, new UnsignedWordElement(0x1402)))); + m(SymmetricEss.ChannelId.SOC, new UnsignedWordElement(0x1402)))); } @Override @@ -698,11 +687,6 @@ public String debugLog() { + "|" + this.getGridMode().value().asOptionString(); } - @Override - public SymmetricPower getPower() { - return this.power; - } - @Override public void handleEvent(Event event) { if (!this.isEnabled()) { @@ -735,4 +719,15 @@ private void defineWorkState() { } } } + + @Override + public Power getPower() { + return this.power; + } + + @Override + public int getPowerPrecision() { + return 100; // the modbus field for SetActivePower has the unit 0.1 kW + } + } diff --git a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/Utils.java b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/Utils.java index 73bed63e793..3c8c3b476be 100644 --- a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/Utils.java +++ b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/Utils.java @@ -4,15 +4,13 @@ import java.util.stream.Stream; import io.openems.edge.common.channel.AbstractReadChannel; -import io.openems.edge.common.channel.BooleanReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.IntegerWriteChannel; -import io.openems.edge.common.channel.LongReadChannel; import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.ess.api.Ess; -import io.openems.edge.ess.symmetric.api.SymmetricEss; -import io.openems.edge.ess.symmetric.readonly.api.SymmetricEssReadonly; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; public class Utils { public static Stream> initializeChannels(EssFeneconCommercial40 c) { @@ -22,31 +20,24 @@ public static Stream> initializeChannels(EssFen Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; - }), Arrays.stream(Ess.ChannelId.values()).map(channelId -> { + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { switch (channelId) { case SOC: + case ACTIVE_POWER: + case REACTIVE_POWER: + case ACTIVE_CHARGE_ENERGY: + case ACTIVE_DISCHARGE_ENERGY: return new IntegerReadChannel(c, channelId); case MAX_ACTIVE_POWER: return new IntegerReadChannel(c, channelId, EssFeneconCommercial40.MAX_APPARENT_POWER); case GRID_MODE: - return new IntegerReadChannel(c, channelId, Ess.GridMode.UNDEFINED.ordinal()); - } - return null; - }), Arrays.stream(SymmetricEssReadonly.ChannelId.values()).map(channelId -> { - switch (channelId) { - case ACTIVE_POWER: - case CHARGE_ACTIVE_POWER: - case DISCHARGE_ACTIVE_POWER: - case REACTIVE_POWER: - case CHARGE_REACTIVE_POWER: - case DISCHARGE_REACTIVE_POWER: - return new IntegerReadChannel(c, channelId); + return new IntegerReadChannel(c, channelId, SymmetricEss.GridMode.UNDEFINED.ordinal()); } return null; - }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + }), Arrays.stream(ManagedSymmetricEss.ChannelId.values()).map(channelId -> { switch (channelId) { case DEBUG_SET_ACTIVE_POWER: case DEBUG_SET_REACTIVE_POWER: @@ -90,10 +81,9 @@ public static Stream> initializeChannels(EssFen case TRANSFORMER_TEMPERATURE_L2: case BMS_DCDC_WORK_MODE: case BMS_DCDC_WORK_STATE: - return new IntegerReadChannel(c, channelId); case AC_CHARGE_ENERGY: case AC_DISCHARGE_ENERGY: - return new LongReadChannel(c, channelId); + return new IntegerReadChannel(c, channelId); case SET_WORK_STATE: case SET_ACTIVE_POWER: case SET_REACTIVE_POWER: @@ -249,7 +239,7 @@ public static Stream> initializeChannels(EssFen case STATE_147: case STATE_148: case STATE_149: - return new BooleanReadChannel(c, channelId); + return new StateChannel(c, channelId); } return null; }) // diff --git a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/Config.java b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/Config.java index 51f46b336a9..f4e369b5996 100644 --- a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/Config.java +++ b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/Config.java @@ -19,5 +19,8 @@ @AttributeDefinition(name = "FENECON Commercial40 target filter", description = "This is auto-generated by 'FENECON Commercial40-ID'.") String Ess_target() default ""; + @AttributeDefinition(name = "Maximum Ever Actual Power", description = "This is automatically updated.") + int maxActualPower(); + String webconsole_configurationFactory_nameHint() default "ESS FENECON Commercial 40 DC Charger [{id}]"; } \ No newline at end of file diff --git a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/EssDcChargerFeneconCommercial40.java b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/EssDcChargerFeneconCommercial40.java index 49a563c8b0f..5b36db62086 100644 --- a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/EssDcChargerFeneconCommercial40.java +++ b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/EssDcChargerFeneconCommercial40.java @@ -18,17 +18,20 @@ import io.openems.edge.bridge.modbus.api.BridgeModbus; import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; import io.openems.edge.bridge.modbus.api.element.SignedWordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.WordOrder; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; -import io.openems.edge.bridge.modbus.api.task.Priority; import io.openems.edge.common.channel.Channel; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.channel.doc.Unit; import io.openems.edge.common.channel.merger.ChannelMergerSumInteger; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.ess.api.ManagedSymmetricEss; import io.openems.edge.ess.dccharger.api.EssDcCharger; import io.openems.edge.ess.fenecon.commercial40.EssFeneconCommercial40; -import io.openems.edge.ess.symmetric.api.SymmetricEss; /** * Implements the FENECON Commercial 40 Charger @@ -56,7 +59,7 @@ protected void setModbus(BridgeModbus modbus) { } @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) - protected void setEss(SymmetricEss ess) { + protected void setEss(ManagedSymmetricEss ess) { if (ess instanceof EssFeneconCommercial40) { this.ess.set((EssFeneconCommercial40) ess); } @@ -74,9 +77,66 @@ protected void deactivate() { } public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + BMS_DCDC0_OUTPUT_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + BMS_DCDC0_OUTPUT_CURRENT(new Doc().unit(Unit.MILLIAMPERE)), // + BMS_DCDC0_OUTPUT_POWER(new Doc().unit(Unit.WATT)), // + BMS_DCDC0_INPUT_VOLTAGE(new Doc().unit(Unit.MILLIWATT)), // + BMS_DCDC0_INPUT_CURRENT(new Doc().unit(Unit.MILLIWATT)), // + BMS_DCDC0_INPUT_POWER(new Doc().unit(Unit.WATT)), // + BMS_DCDC0_INPUT_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC0_OUTPUT_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC0_REACTOR_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + BMS_DCDC0_IGBT_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + BMS_DCDC0_INPUT_CHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC0_INPUT_DISCHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC0_OUTPUT_CHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC0_OUTPUT_DISCHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + + BMS_DCDC1_OUTPUT_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + BMS_DCDC1_OUTPUT_CURRENT(new Doc().unit(Unit.MILLIAMPERE)), // + BMS_DCDC1_OUTPUT_POWER(new Doc().unit(Unit.WATT)), // + BMS_DCDC1_INPUT_VOLTAGE(new Doc().unit(Unit.MILLIWATT)), // + BMS_DCDC1_INPUT_CURRENT(new Doc().unit(Unit.MILLIWATT)), // + BMS_DCDC1_INPUT_POWER(new Doc().unit(Unit.WATT)), // + BMS_DCDC1_INPUT_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC1_OUTPUT_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC1_REACTOR_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + BMS_DCDC1_IGBT_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + BMS_DCDC1_INPUT_CHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC1_INPUT_DISCHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC1_OUTPUT_CHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + BMS_DCDC1_OUTPUT_DISCHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + + PV_DCDC0_OUTPUT_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + PV_DCDC0_OUTPUT_CURRENT(new Doc().unit(Unit.MILLIAMPERE)), // + PV_DCDC0_OUTPUT_POWER(new Doc().unit(Unit.WATT)), // + PV_DCDC0_INPUT_VOLTAGE(new Doc().unit(Unit.MILLIWATT)), // + PV_DCDC0_INPUT_CURRENT(new Doc().unit(Unit.MILLIWATT)), // PV_DCDC0_INPUT_POWER(new Doc().unit(Unit.WATT)), // - PV_DCDC1_INPUT_POWER(new Doc().unit(Unit.WATT)); + PV_DCDC0_INPUT_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC0_OUTPUT_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC0_REACTOR_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + PV_DCDC0_IGBT_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + PV_DCDC0_INPUT_CHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC0_INPUT_DISCHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC0_OUTPUT_CHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC0_OUTPUT_DISCHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC1_OUTPUT_VOLTAGE(new Doc().unit(Unit.MILLIVOLT)), // + PV_DCDC1_OUTPUT_CURRENT(new Doc().unit(Unit.MILLIAMPERE)), // + PV_DCDC1_OUTPUT_POWER(new Doc().unit(Unit.WATT)), // + PV_DCDC1_INPUT_VOLTAGE(new Doc().unit(Unit.MILLIWATT)), // + PV_DCDC1_INPUT_CURRENT(new Doc().unit(Unit.MILLIWATT)), // + PV_DCDC1_INPUT_POWER(new Doc().unit(Unit.WATT)), // + PV_DCDC1_INPUT_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC1_OUTPUT_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC1_REACTOR_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + PV_DCDC1_IGBT_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + PV_DCDC1_INPUT_CHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC1_INPUT_DISCHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC1_OUTPUT_CHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + PV_DCDC1_OUTPUT_DISCHARGE_ENERGY(new Doc().unit(Unit.WATT_HOURS)), // + ; private final Doc doc; private ChannelId(Doc doc) { @@ -92,12 +152,122 @@ public Doc doc() { @Override protected ModbusProtocol defineModbusProtocol(int unitId) { ModbusProtocol protocol = new ModbusProtocol(unitId, // - new FC3ReadRegistersTask(0xA735, Priority.HIGH, // + new FC3ReadRegistersTask(0xA130, Priority.LOW, // + m(ChannelId.BMS_DCDC0_OUTPUT_VOLTAGE, new SignedWordElement(0xA130), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_OUTPUT_CURRENT, new SignedWordElement(0xA131), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_OUTPUT_POWER, new SignedWordElement(0xA132), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_INPUT_VOLTAGE, new SignedWordElement(0xA133), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_INPUT_CURRENT, new SignedWordElement(0xA134), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_INPUT_POWER, new SignedWordElement(0xA135), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_INPUT_ENERGY, new SignedWordElement(0xA136), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_OUTPUT_ENERGY, new SignedWordElement(0xA137), + ElementToChannelConverter.SCALE_FACTOR_2), // + new DummyRegisterElement(0xA138, 0xA13F), // + m(ChannelId.BMS_DCDC0_REACTOR_TEMPERATURE, new SignedWordElement(0xA140)), // + m(ChannelId.BMS_DCDC0_IGBT_TEMPERATURE, new SignedWordElement(0xA141)), // + new DummyRegisterElement(0xA142, 0xA14F), // + m(ChannelId.BMS_DCDC0_INPUT_CHARGE_ENERGY, new UnsignedDoublewordElement(0xA150).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_INPUT_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0xA152).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_OUTPUT_CHARGE_ENERGY, new UnsignedDoublewordElement(0xA154).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC0_OUTPUT_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0xA156).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2)), // + new FC3ReadRegistersTask(0xA430, Priority.LOW, // + m(ChannelId.BMS_DCDC1_OUTPUT_VOLTAGE, new SignedWordElement(0xA430), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_OUTPUT_CURRENT, new SignedWordElement(0xA431), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_OUTPUT_POWER, new SignedWordElement(0xA432), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_INPUT_VOLTAGE, new SignedWordElement(0xA433), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_INPUT_CURRENT, new SignedWordElement(0xA434), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_INPUT_POWER, new SignedWordElement(0xA435), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_INPUT_ENERGY, new SignedWordElement(0xA436), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_OUTPUT_ENERGY, new SignedWordElement(0xA437), + ElementToChannelConverter.SCALE_FACTOR_2), // + new DummyRegisterElement(0xA438, 0xA43F), // + m(ChannelId.BMS_DCDC1_REACTOR_TEMPERATURE, new SignedWordElement(0xA440)), // + m(ChannelId.BMS_DCDC1_IGBT_TEMPERATURE, new SignedWordElement(0xA441)), // + new DummyRegisterElement(0xA442, 0xA44F), // + m(ChannelId.BMS_DCDC1_INPUT_CHARGE_ENERGY, new UnsignedDoublewordElement(0xA450).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_INPUT_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0xA452).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_OUTPUT_CHARGE_ENERGY, new UnsignedDoublewordElement(0xA454).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.BMS_DCDC1_OUTPUT_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0xA456).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2)), // + new FC3ReadRegistersTask(0xA730, Priority.LOW, // + m(ChannelId.PV_DCDC0_OUTPUT_VOLTAGE, new SignedWordElement(0xA730), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_OUTPUT_CURRENT, new SignedWordElement(0xA731), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_OUTPUT_POWER, new SignedWordElement(0xA732), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_INPUT_VOLTAGE, new SignedWordElement(0xA733), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_INPUT_CURRENT, new SignedWordElement(0xA734), + ElementToChannelConverter.SCALE_FACTOR_2), // m(ChannelId.PV_DCDC0_INPUT_POWER, new SignedWordElement(0xA735), - ElementToChannelConverter.SCALE_FACTOR_2)), - new FC3ReadRegistersTask(0xA735, Priority.HIGH, // - m(ChannelId.PV_DCDC1_INPUT_POWER, new SignedWordElement(0xA735), - ElementToChannelConverter.SCALE_FACTOR_2))); + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_INPUT_ENERGY, new SignedWordElement(0xA736), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_OUTPUT_ENERGY, new SignedWordElement(0xA737), + ElementToChannelConverter.SCALE_FACTOR_2), // + new DummyRegisterElement(0xA738, 0xA73F), // + m(ChannelId.PV_DCDC0_REACTOR_TEMPERATURE, new SignedWordElement(0xA740)), // + m(ChannelId.PV_DCDC0_IGBT_TEMPERATURE, new SignedWordElement(0xA741)), // + new DummyRegisterElement(0xA742, 0xA74F), // + m(ChannelId.PV_DCDC0_INPUT_CHARGE_ENERGY, new UnsignedDoublewordElement(0xA750).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_INPUT_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0xA752).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_OUTPUT_CHARGE_ENERGY, new UnsignedDoublewordElement(0xA754).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC0_OUTPUT_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0xA756).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2)), // + new FC3ReadRegistersTask(0xAA30, Priority.LOW, // + m(ChannelId.PV_DCDC1_OUTPUT_VOLTAGE, new SignedWordElement(0xAA30), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_OUTPUT_CURRENT, new SignedWordElement(0xAA31), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_OUTPUT_POWER, new SignedWordElement(0xAA32), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_INPUT_VOLTAGE, new SignedWordElement(0xAA33), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_INPUT_CURRENT, new SignedWordElement(0xAA34), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_INPUT_POWER, new SignedWordElement(0xAA35), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_INPUT_ENERGY, new SignedWordElement(0xAA36), + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_OUTPUT_ENERGY, new SignedWordElement(0xAA37), + ElementToChannelConverter.SCALE_FACTOR_2), // + new DummyRegisterElement(0xAA38, 0xAA3F), // + m(ChannelId.PV_DCDC1_REACTOR_TEMPERATURE, new SignedWordElement(0xAA40)), // + m(ChannelId.PV_DCDC1_IGBT_TEMPERATURE, new SignedWordElement(0xAA41)), // + new DummyRegisterElement(0xAA42, 0xAA4F), // + m(ChannelId.PV_DCDC1_INPUT_CHARGE_ENERGY, new UnsignedDoublewordElement(0xAA50).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_INPUT_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0xAA52).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_OUTPUT_CHARGE_ENERGY, new UnsignedDoublewordElement(0xAA54).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2), // + m(ChannelId.PV_DCDC1_OUTPUT_DISCHARGE_ENERGY, new UnsignedDoublewordElement(0xAA56).wordOrder(WordOrder.LSWMSW), // + ElementToChannelConverter.SCALE_FACTOR_2))); // /* * Merge PV_DCDC0_INPUT_POWER and PV_DCDC1_INPUT_POWER to ACTUAL_POWER */ @@ -107,37 +277,17 @@ protected ModbusProtocol defineModbusProtocol(int unitId) { this.>channel(ChannelId.PV_DCDC0_INPUT_POWER), // this.>channel(ChannelId.PV_DCDC1_INPUT_POWER) // }); + /* + * Merge PV_DCDC0_OUTPUT_DISCHARGE_ENERGY and PV_DCDC1_OUTPUT_DISCHARGE_ENERGY to + * ACTUAL_ENERGY + */ + new ChannelMergerSumInteger( // + /* target */ this.getActualEnergy(), // + /* sources */ (Channel[]) new Channel[] { // + this.>channel(ChannelId.PV_DCDC0_OUTPUT_DISCHARGE_ENERGY), // + this.>channel(ChannelId.PV_DCDC1_OUTPUT_DISCHARGE_ENERGY) // + }); - // Runnable mergeActualPower = () -> { - // int PV_DCDC0_INPUT_POWER = latestPV_DCDC0_INPUT_POWER.get(); - // int PV_DCDC1_INPUT_POWER = latestPV_DCDC1_INPUT_POWER.get(); - // try { - // this.getActualPower().setNextValue(PV_DCDC0_INPUT_POWER + - // PV_DCDC1_INPUT_POWER); - // } catch (OpenemsException e) { - // logError(log, "Unable to merge ACTUAL_POWER from [" + PV_DCDC0_INPUT_POWER + - // "] and [" - // + PV_DCDC1_INPUT_POWER + "]: " + e.getMessage()); - // } - // }; - // this.>channel(ChannelId.PV_DCDC0_INPUT_POWER).onUpdate(value - // -> { - // if (value != null) { - // latestPV_DCDC0_INPUT_POWER.set(value); - // } else { - // latestPV_DCDC0_INPUT_POWER.set(0); - // } - // mergeActualPower.run(); - // }); - // this.>channel(ChannelId.PV_DCDC1_INPUT_POWER).onUpdate(value - // -> { - // if (value != null) { - // latestPV_DCDC1_INPUT_POWER.set(value); - // } else { - // latestPV_DCDC1_INPUT_POWER.set(0); - // } - // mergeActualPower.run(); - // }); return protocol; } diff --git a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/Utils.java b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/Utils.java index 86f957268f4..486c90a913b 100644 --- a/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/Utils.java +++ b/io.openems.edge.ess.fenecon.commercial40/src/io/openems/edge/ess/fenecon/commercial40/charger/Utils.java @@ -5,7 +5,7 @@ import io.openems.edge.common.channel.AbstractReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.ess.dccharger.api.EssDcCharger; @@ -15,19 +15,75 @@ public static Stream> initializeChannels(EssDcC Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; }), Arrays.stream(EssDcCharger.ChannelId.values()).map(channelId -> { switch (channelId) { case ACTUAL_POWER: + case MAX_ACTUAL_POWER: + case ACTUAL_ENERGY: return new IntegerReadChannel(c, channelId); } return null; }), Arrays.stream(EssDcChargerFeneconCommercial40.ChannelId.values()).map(channelId -> { switch (channelId) { + case BMS_DCDC0_IGBT_TEMPERATURE: + case BMS_DCDC0_INPUT_CURRENT: + case BMS_DCDC0_INPUT_ENERGY: + case BMS_DCDC0_INPUT_POWER: + case BMS_DCDC0_INPUT_VOLTAGE: + case BMS_DCDC0_OUTPUT_CURRENT: + case BMS_DCDC0_OUTPUT_ENERGY: + case BMS_DCDC0_OUTPUT_POWER: + case BMS_DCDC0_OUTPUT_VOLTAGE: + case BMS_DCDC0_REACTOR_TEMPERATURE: + case BMS_DCDC1_IGBT_TEMPERATURE: + case BMS_DCDC1_INPUT_CURRENT: + case BMS_DCDC1_INPUT_ENERGY: + case BMS_DCDC1_INPUT_POWER: + case BMS_DCDC1_INPUT_VOLTAGE: + case BMS_DCDC1_OUTPUT_CURRENT: + case BMS_DCDC1_OUTPUT_ENERGY: + case BMS_DCDC1_OUTPUT_POWER: + case BMS_DCDC1_OUTPUT_VOLTAGE: + case BMS_DCDC1_REACTOR_TEMPERATURE: + case PV_DCDC0_IGBT_TEMPERATURE: + case PV_DCDC0_INPUT_CURRENT: + case PV_DCDC0_INPUT_ENERGY: case PV_DCDC0_INPUT_POWER: + case PV_DCDC0_INPUT_VOLTAGE: + case PV_DCDC0_OUTPUT_CURRENT: + case PV_DCDC0_OUTPUT_ENERGY: + case PV_DCDC0_OUTPUT_POWER: + case PV_DCDC0_OUTPUT_VOLTAGE: + case PV_DCDC0_REACTOR_TEMPERATURE: + case PV_DCDC1_IGBT_TEMPERATURE: + case PV_DCDC1_INPUT_CURRENT: + case PV_DCDC1_INPUT_ENERGY: case PV_DCDC1_INPUT_POWER: + case PV_DCDC1_INPUT_VOLTAGE: + case PV_DCDC1_OUTPUT_CURRENT: + case PV_DCDC1_OUTPUT_ENERGY: + case PV_DCDC1_OUTPUT_POWER: + case PV_DCDC1_OUTPUT_VOLTAGE: + case PV_DCDC1_REACTOR_TEMPERATURE: + case BMS_DCDC0_INPUT_CHARGE_ENERGY: + case BMS_DCDC0_INPUT_DISCHARGE_ENERGY: + case BMS_DCDC0_OUTPUT_CHARGE_ENERGY: + case BMS_DCDC0_OUTPUT_DISCHARGE_ENERGY: + case BMS_DCDC1_INPUT_CHARGE_ENERGY: + case BMS_DCDC1_INPUT_DISCHARGE_ENERGY: + case BMS_DCDC1_OUTPUT_CHARGE_ENERGY: + case BMS_DCDC1_OUTPUT_DISCHARGE_ENERGY: + case PV_DCDC0_INPUT_CHARGE_ENERGY: + case PV_DCDC0_INPUT_DISCHARGE_ENERGY: + case PV_DCDC0_OUTPUT_CHARGE_ENERGY: + case PV_DCDC0_OUTPUT_DISCHARGE_ENERGY: + case PV_DCDC1_INPUT_CHARGE_ENERGY: + case PV_DCDC1_INPUT_DISCHARGE_ENERGY: + case PV_DCDC1_OUTPUT_CHARGE_ENERGY: + case PV_DCDC1_OUTPUT_DISCHARGE_ENERGY: return new IntegerReadChannel(c, channelId); } return null; diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/.classpath b/io.openems.edge.ess.kaco.blueplanet.gridsave50/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/.gitignore b/io.openems.edge.ess.kaco.blueplanet.gridsave50/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/bnd.bnd b/io.openems.edge.ess.kaco.blueplanet.gridsave50/bnd.bnd new file mode 100644 index 00000000000..eb52d3ed87c --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/bnd.bnd @@ -0,0 +1,26 @@ +Bundle-Name: OpenEMS Edge ESS KACO blueplanet gridsave 50.0 TL3 +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.ess.symmetric.readonly.api,\ + io.openems.edge.ess.api,\ + io.openems.edge.ess.symmetric.api,\ + io.openems.edge.ess.power.symmetric,\ + io.openems.edge.ess.power + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.ess.api;version=latest,\ + io.openems.edge.common;version=latest,\ + io.openems.common;version=latest,\ + io.openems.edge.bridge.modbus;version=latest,\ + io.openems.edge.battery.api;version=latest,\ + io.openems.edge.battery.soltaro;version=latest + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 +Private-Package: io.openems.edge.ess.kaco.blueplanet.gridsave50 \ No newline at end of file diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/debug.bndrun b/io.openems.edge.ess.kaco.blueplanet.gridsave50/debug.bndrun new file mode 100644 index 00000000000..a37509ef784 --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/debug.bndrun @@ -0,0 +1,13 @@ +# +# io.openems.edge.ess.kaco.blueplanet50 DEBUG LAUNCH SPECFICATION +# + +-include: ~io.openems.edge.ess.kaco.blueplanet50.bndrun + +-runrequires.debug: \ + ${debug-bundles} + +-runtrace: true + +-runbundles: \ + ${error;Resolve first} diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/doc/APL_BG50.0TL3-S_Setup_process_SW_V5.22_180627_en.pdf b/io.openems.edge.ess.kaco.blueplanet.gridsave50/doc/APL_BG50.0TL3-S_Setup_process_SW_V5.22_180627_en.pdf new file mode 100644 index 00000000000..cca23a0a533 Binary files /dev/null and b/io.openems.edge.ess.kaco.blueplanet.gridsave50/doc/APL_BG50.0TL3-S_Setup_process_SW_V5.22_180627_en.pdf differ diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/doc/SunSpec Information Models - 12041.pdf b/io.openems.edge.ess.kaco.blueplanet.gridsave50/doc/SunSpec Information Models - 12041.pdf new file mode 100644 index 00000000000..1eaeb1e9ff9 Binary files /dev/null and b/io.openems.edge.ess.kaco.blueplanet.gridsave50/doc/SunSpec Information Models - 12041.pdf differ diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/readme.md b/io.openems.edge.ess.kaco.blueplanet.gridsave50/readme.md new file mode 100644 index 00000000000..1cf0610f2cb --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.ess.kaco.blueplanet50 Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Config.java b/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Config.java new file mode 100644 index 00000000000..9d0a4c6a32c --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Config.java @@ -0,0 +1,29 @@ +package io.openems.edge.ess.kaco.blueplanet.gridsave50; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition( // + name = "ESS KACO blueplanet gridsave 50.0 TL3", // + description = "Implements the FENECON Commercial 40 energy storage system.") +@interface Config { + String service_pid(); + + String id() default "ess0"; + + boolean enabled() default true; + + @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.") + String modbus_id(); + + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default ""; + + @AttributeDefinition(name = "Battery-ID", description = "ID of Battery.") + String battery_id(); + + @AttributeDefinition(name = "Battery target filter", description = "This is auto-generated by 'Battery-ID'.") + String Battery_target() default ""; + + String webconsole_configurationFactory_nameHint() default "ESS KACO blueplanet gridsave 50.0 TL3 [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/EssKacoBlueplanetGridsave50.java b/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/EssKacoBlueplanetGridsave50.java new file mode 100644 index 00000000000..f17829cc839 --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/EssKacoBlueplanetGridsave50.java @@ -0,0 +1,652 @@ +package io.openems.edge.ess.kaco.blueplanet.gridsave50; + +import java.util.Optional; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; +import org.osgi.service.metatype.annotations.Designate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.types.OpenemsType; +import io.openems.edge.battery.api.Battery; +import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; +import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; +import io.openems.edge.bridge.modbus.api.element.SignedWordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement; +import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; +import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.IntegerWriteChannel; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.OptionsEnum; +import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.common.type.TypeUtils; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.CircleConstraint; +import io.openems.edge.ess.power.api.Power; + +@Designate(ocd = Config.class, factory = true) +@Component( // + name = "Ess.Kaco.BlueplanetGridsave50", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // +) // +public class EssKacoBlueplanetGridsave50 extends AbstractOpenemsModbusComponent + implements ManagedSymmetricEss, SymmetricEss, OpenemsComponent, EventHandler { + + private final Logger log = LoggerFactory.getLogger(EssKacoBlueplanetGridsave50.class); + + private final static int UNIT_ID = 1; + protected static final int MAX_APPARENT_POWER = 52000; + private CircleConstraint maxApparentPowerConstraint = null; + private int maxApparentPower = 0; + private int maxApparentPowerUnscaled = 0; + private int maxApparentPowerScaleFactor = 0; + + @Reference + private Power power; + + @Reference + protected ConfigurationAdmin cm; + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + private Battery battery; + + public EssKacoBlueplanetGridsave50() { + Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); + } + + private void refreshPower() { + if (maxApparentPower > 0) { + this.maxApparentPowerConstraint.setRadius(maxApparentPower); + } + } + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + @Activate + void activate(ComponentContext context, Config config) { + // update filter for 'battery' + if (OpenemsComponent.updateReferenceFilter(this.cm, config.service_pid(), "battery", config.battery_id())) { + return; + } + + /* + * Initialize Power + */ + // Max Apparent + // TODO adjust apparent power from modbus element + this.maxApparentPowerConstraint = new CircleConstraint(this, MAX_APPARENT_POWER); + + this.channel(ChannelId.W_MAX).onChange(value -> { + // TODO unchecked cast + @SuppressWarnings("unchecked") + Optional valueOpt = (Optional) value.asOptional(); + if (!valueOpt.isPresent()) { + return; + } + maxApparentPowerUnscaled = TypeUtils.getAsType(OpenemsType.INTEGER, value); + maxApparentPower = maxApparentPowerUnscaled * maxApparentPowerScaleFactor; + refreshPower(); + }); + this.channel(ChannelId.W_MAX_SF).onChange(value -> { +// TODO unchecked cast + @SuppressWarnings("unchecked") + Optional valueOpt = (Optional) value.asOptional(); + if (!valueOpt.isPresent()) { + return; + } + maxApparentPowerScaleFactor = TypeUtils.getAsType(OpenemsType.INTEGER, value); + maxApparentPower = maxApparentPowerUnscaled * maxApparentPowerScaleFactor; + refreshPower(); + }); + + super.activate(context, config.service_pid(), config.id(), config.enabled(), UNIT_ID, this.cm, "Modbus", + config.modbus_id()); + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + public enum CurrentState implements OptionsEnum { + OFF(1, "Off"), // directly addressable + STANDBY(8, "Standby"), // directly addressable + GRID_CONNECTED(11, "Grid connected"), // directly addressable + ERROR(7, "Error"), // can be reached from every state, not directly addressable + PRECHARGE(9, "Precharge"), // State when system goes from OFF to STANDBY, not directly addressable + STARTING(3, "Starting"), // State from STANDBY to GRID_CONNECTED, not directly addressable + SHUTTING_DOWN(6, "Shutting down"), // State when system goes from GRID_CONNECTED to STANDBY, not directly + // addressable + NO_ERROR_PENDING(12, "No error pending"), // State when system goes from ERROR to OFF, not directly addressable + THROTTLED(5, "Throttled"); // State that can occur when system is GRID_CONNECTED, not directly addressable + + int value; + String option; + + private CurrentState(int value, String option) { + this.value = value; + this.option = option; + } + + @Override + public int getValue() { + return value; + } + + @Override + public String getOption() { + return option; + } + } + + public enum RequestedState implements OptionsEnum { + OFF(1, "Off"), // directly addressable + STANDBY(8, "Standby"), // directly addressable + GRID_CONNECTED(11, "Grid connected"); // directly addressable + + int value; + String option; + + private RequestedState(int value, String option) { + this.value = value; + this.option = option; + } + + @Override + public int getValue() { + return value; + } + + @Override + public String getOption() { + return option; + } + } + + public enum ErrorCode implements OptionsEnum { + WAITING_FOR_FEED_IN(1, "Self-test: Grid parameters and generator voltage are being checked"), + BATTERY_VOLTAGE_TOO_LOW(2, "Battery Voltage too low! Transition from or to 'Standby'"), + YIELD_COUNTER_FOR_DAILY(4, "Yield counter for daily and annual yields are displayed"), + SELF_TEST_IN_PROGR_CHECK(8, + "Self test in progr. Check the shutdown of the power electronics as well as the shutdown of the grid relay before the charge process."), + TEMPERATURE_IN_UNIT_TOO(10, + "Temperature in unit too high In the event of overheating, the device shuts down. Possible causes: ambient temperature too high, fan covered, device fault."), + POWER_LIMITATION_IF_THE(11, + "Power limitation: If the generator power is too high, the device limits itself to the maximum power (e.g. around noon if the generator capacity is too large). "), + POWADORPROTECT_DISCONNECTION(17, + "Powador-protect disconnection The activated grid and system protection has been tripped."), + RESID_CURRENT_SHUTDOWN(18, + "Resid. current shutdown Residual current was detected. The feed-in was interrupted."), + GENERATOR_INSULATION(19, + "Generator insulation fault Insulation fault Insulation resistance from DC-/DC + to PE too low"), + ACTIVE_RAMP_LIMITATION(20, + "Active ramp limitation The result when the power is increased with a ramp is country-specific."), + VOLTAGE_TRANS_FAULT_CURRENT(30, + "Voltage trans. fault Current and voltage measurement in the device are not plausible."), + SELF_TEST_ERROR_THE_INTERNAL(32, + "Self test error The internal grid separation relay test has failed. Notify your authorised electrician if the fault occurs repeatedly!"), + DC_FEEDIN_ERROR_THE_DC(33, + "DC feed-in error The DC feed-in has exceeded the permitted value. This DC feed-in can be caused in the device by grid conditions and may not necessarily indicate a fault."), + INTERNAL_COMMUNICATION(34, + "Internal communication error A communication error has occurred in the internal data transmission. "), + PROTECTION_SHUTDOWN_SW(35, + "Protection shutdown SW Protective shutdown of the software (AC overvoltage, AC overcurrent, DC link overvoltage, DC overvoltage, DC overtemperature). "), + PROTECTION_SHUTDOWN_HW(36, + "Protection shutdown HW Protective shutdown of the software (AC overvoltage, AC overcurrent, DC link overvoltage, DC overvoltage, DC overtemperature). "), + ERROR_GENERATOR_VOLTAGE(38, "Error: Generator Voltage too high Error: Battery overvoltage"), + LINE_FAILURE_UNDERVOLTAGE_1(41, + "Line failure undervoltage L1 The voltage of a grid phase is too low; the grid cannot be fed into. The phase experiencing failure is displayed."), + LINE_FAILURE_OVERVOLTAGE_1(42, + "Line failure overvoltage L1 The voltage of a grid phase is too low; the grid cannot be fed into. The phase experiencing failure is displayed."), + LINE_FAILURE_UNDERVOLTAGE_2(43, + "Line failure undervoltage L2 The voltage of a grid phase is too low; the grid cannot be fed into. The phase experiencing failure is displayed."), + LINE_FAILURE_OVERVOLTAGE_2(44, + "Line failure overvoltage L2 The voltage of a grid phase is too low; the grid cannot be fed into. The phase experiencing failure is displayed."), + LINE_FAILURE_UNDERVOLTAGE_3(45, + "Line failure undervoltage L3 The voltage of a grid phase is too low; the grid cannot be fed into. The phase experiencing failure is displayed."), + LINE_FAILURE_OVERVOLTAGE_3(46, + "Line failure overvoltage L3 The voltage of a grid phase is too low; the grid cannot be fed into. The phase experiencing failure is displayed."), + GRID_FAILURE_PHASETOPHASE(47, "Grid failure phase-to-phase voltage"), + LINE_FAILURE_UNDERFREQ(48, + "Line failure: underfreq. Grid frequency is too low. This fault may be gridrelated."), + LINE_FAILURE_OVERFREQ(49, "Line failure: overfreq. Grid frequency is too high. This fault may be gridrelated."), + LINE_FAILURE_AVERAGE(50, + "Line failure: average voltage The grid voltage measurement according to EN 50160 has exceeded the maximum permitted limit value. This fault may be grid-related."), + WAITING_FOR_REACTIVATION(57, + "Waiting for reactivation Waiting time of the device following an error. The devices switches on after a countryspecific waiting period."), + CONTROL_BOARD_OVERTEMP(58, + "Control board overtemp. The temperature inside the unit was too high. The device shuts down to avoid hardware damage. "), + SELF_TEST_ERROR_A_FAULT(59, + "Self test error A fault occurred during a self-test. Contact a qualified electrician."), + GENERATOR_VOLTAGE_TOO(60, "Generator voltage too high Battery voltage too high"), + EXTERNAL_LIMIT_X_THE(61, + "External limit x% The grid operator has activated the external PowerControl limit. The inverter limits the power."), + P_F_FREQUENCYDEPENDENT(63, + "P(f)/frequency-dependent power reduction: When certain country settings are activated, the frequency-dependent power reduction is activated."), + OUTPUT_CURRENT_LIMITING(64, + "Output current limiting: The AC current is limited once the specified maximum value has been reached."), + FAULT_AT_POWER_SECTION(67, + "Fault at power section 1 There is a fault in the power section. Contact a qualified electrician."), + FAN_1_ERROR_THE_FAN_IS(70, + "Fan 1 error The fan is malfunctioning. Replace defective fan See Maintenance and troubleshooting chapter."), + STANDALONE_GRID_ERR_STANDALONE(73, "Standalone grid err. Standalone mode was detected."), + EXTERNAL_IDLE_POWER_REQUIREMENT(74, + "External idle power requirement The grid operator limits the feed-in power of the device via the transmitted reactive power factor."), + INSULATION_MEASUREMENT(79, "Insulation measurement PV generator's insulation is being measured"), + INSULATION_MEAS_NOT_POSSIBLE(80, + "Insulation meas. not possible The insulation measurement cannot be performed because the generator voltage is too volatile. - "), + PROTECTION_SHUTDOWN_LINE_1(81, + "Protection shutdown line volt. L1 Overvoltage has been detected on a conductor. An internal protective mechanism has disconnected the device to protect it against damage. In case of repeated occurrence: Contact a qualified electrician."), + PROTECTION_SHUTDOWN_LINE_2(82, + "Protection shutdown line volt. L2 Overvoltage has been detected on a conductor. An internal protective mechanism has disconnected the device to protect it against damage. In case of repeated occurrence: Contact a qualified electrician."), + PROTECTION_SHUTDOWN_LINE_3(83, + "Protection shutdown line volt. L3 Overvoltage has been detected on a conductor. An internal protective mechanism has disconnected the device to protect it against damage. In case of repeated occurrence: Contact a qualified electrician."), + PROTECTION_SHUTDOWN_UNDERVOLT(84, + "Protection shutdown undervolt. DC link A voltage deviation has been found in the DC link. An internal protective mechanism has disconnected the device to protect it against damage. In a TN-C-S grid, the PE must be connected to the device and at the same time the PEN bridge in the device must be removed. In case of repeated occurrence: Contact a qualified electrician."), + PROTECT_SHUTDOWN_OVERVOLT(85, "Protect. shutdown overvolt. DC link"), + PROTECT_SHUTDOWN_DC_LINK(86, "Protect. shutdown DC link asymmetry"), + PROTECT_SHUTDOWN_OVERCURRENT_1(87, "Protect. shutdown overcurrent L1"), + PROTECT_SHUTDOWN_OVERCURRENT_2(88, "Protect. shutdown overcurrent L2"), + PROTECT_SHUTDOWN_OVERCURRENT_3(89, "Protect. shutdown overcurrent L3"), + BUFFER_1_SELF_TEST_ERROR(93, + "Buffer 1 self test error The control board is defective. Please inform your electrician/system manufacturer's service department."), + SELF_TEST_ERROR_BUFFER(94, + "Self test error buffer 2 The control board is defective. Notify authorised electrician / KACO Service!"), + RELAY_1_SELF_TEST_ERROR(95, "Relay 1 self test error The power section is defective. Notify KACO Service"), + RELAY_2_SELF_TEST_ERROR(96, + "Relay 2 self test error The power section is defective. Please inform your electrician/system manufacturer's service department."), + PROTECTION_SHUTDOWN_OVERCURRENT(97, + "Protection shutdown overcurrent HW Too much power has been fed into the grid. Complete disconnection of the device. Please inform your electrician/system manufacturer's service department."), + PROTECT_SHUTDOWN_HW_GATE(98, + "Protect. shutdown HW gate driver An internal protective mechanism has disconnected the device to protect it against damage. Complete disconnection of the device. Please inform your electrician/system manufacturer's service department."), + PROTECT_SHUTDOWN_HW_BUFFER(99, + "Protect. shutdown HW buffer free An internal protective mechanism has disconnected the device to protect it against damage. Complete disconnection of the device. Please inform your electrician/system manufacturer's service department."), + PROTECT_SHUTDOWN_HW_OVERHEATING(100, + "Protect. shutdown HW overheating The device has been switched off because the temperatures in the housing were too high. Check to make sure that the fans are working. Replace fan if necessary."), + PLAUSIBILITY_FAULT_AFI(104, + "Plausibility fault AFI module The unit has shut down because of implausible internal measured values. Please inform your system manufacturer's service department!"), + PLAUSIBILITY_FAULT_RELAY(105, + "Plausibility fault relay The unit has shut down because of implausible internal measured values. Please inform your system manufacturer's service department!"), + PLAUSIBILITY_ERROR_DCDC(106, "Plausibility error DCDC converter "), + CHECK_SURGE_PROTECTION(107, + "Check surge protection device Surge protection device (if present in the device) has tripped and must be reset if appropriate."), + EXTERNAL_COMMUNICATION(196, "External communication error - - "), + SYMMETRY_ERROR_PARALLEL(197, + "Symmetry error parallel connection Circuit currents too high for two or more parallel connected bidirectional feed-in inverters. Synchronise intermediate circuit of the parallel connected devices and synchronise the symmetry."), + BATTERY_DISCONNECTED(198, + "Battery disconnected Connection to the battery disconnected. Check connection. The battery voltage may be outside the parameterised battery limits."), + WAITING_FOR_FAULT_ACKNOWLEDGEMENT(215, + "Waiting for fault acknowledgement Waiting for fault acknowledgement by EMS"), + PRECHARGE_UNIT_FAULT(218, "Precharge unit fault Precharge unit: Group fault for precharge unit"), + READY_FOR_PRECHARGING(219, "Ready for precharging Precharge unit: Ready for precharging"), + PRECHARGE_PRECHARGE_UNIT(220, "Precharge Precharge unit: Precharge process being carried out"), + WAIT_FOR_COOLDOWN_TIME(221, + "Wait for cooldown time Precharge unit: Precharge resistance requires time to cool down"); + + private final int value; + private final String option; + + private ErrorCode(int value, String option) { + this.value = value; + this.option = option; + } + + @Override + public int getValue() { + return value; + } + + @Override + public String getOption() { + return option; + } + } + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + /* + * SUNSPEC_103 + */ + VENDOR_OPERATING_STATE(new Doc().options(ErrorCode.values())), // see error codes in user manual "10.10 + // Troubleshooting" (page 48) + /* + * SUNSPEC_121 + */ + W_MAX(new Doc().unit(Unit.WATT)), // + W_MAX_SF(new Doc().unit(Unit.NONE)), // + /* + * SUNSPEC_64201 + */ + + REQUESTED_STATE(new Doc().options(RequestedState.values())), // + CURRENT_STATE(new Doc().options(CurrentState.values())), // + WATCHDOG(new Doc().unit(Unit.SECONDS)), // + W_SET_PCT(new Doc().unit(Unit.PERCENT)), // + W_SET_PCT_SF(new Doc().unit(Unit.NONE)), // + + /* + * SUNSPEC_64202 + */ + V_SF(new Doc().unit(Unit.NONE)), // + A_SF(new Doc().unit(Unit.NONE)), // + DIS_MIN_V(new Doc().unit(Unit.MILLIVOLT)), // + DIS_MAX_A(new Doc().unit(Unit.MILLIAMPERE)), // +// DIS_CUTOFF_A(new Doc().text("Disconnect if discharge current lower than DisCutoffA")), // TODO scale factor + CHA_MAX_V(new Doc().unit(Unit.MILLIVOLT)), // + CHA_MAX_A(new Doc().unit(Unit.MILLIAMPERE)), // +// CHA_CUTOFF_A(new Doc().text("Disconnect if charge current lower than ChaCuttoffA")), // TODO scale factor + EN_LIMIT(new Doc().text("new battery limits are activated when EnLimit is 1")), // + + /* + * SUNSPEC_64203 + */ + SOC_SF(new Doc().unit(Unit.NONE)), // + SOH_SF(new Doc().unit(Unit.NONE)), // + TEMP_SF(new Doc().unit(Unit.NONE)), // + BAT_SOC_(new Doc().unit(Unit.PERCENT)), // + BAT_SOH(new Doc().unit(Unit.PERCENT)), // + BAT_TEMP(new Doc().unit(Unit.PERCENT)), // + /* + * SUNSPEC_64302 + */ + COMMAND_ID_REQ(new Doc().unit(Unit.NONE)), // + REQ_PARAM_0(new Doc().unit(Unit.NONE)), // + COMMAND_ID_REQ_ENA(new Doc().unit(Unit.NONE)), // + COMMAND_ID_RES(new Doc().unit(Unit.NONE)), // + RETURN_CODE(new Doc().unit(Unit.NONE)), // + ; + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + public Doc doc() { + return this.doc; + } + } + +// private final static int SUNSPEC_1 = 40003 - 1; // According to setup process pdf currently not used... +// private final static int SUNSPEC_103 = 40071 - 1; + private final static int SUNSPEC_121 = 40213 - 1; + private final static int SUNSPEC_64201 = 40823 - 1; + private final static int SUNSPEC_64202 = 40877 - 1; + private final static int SUNSPEC_64203 = 40893 - 1; + private final static int SUNSPEC_64302 = 40931 - 1; + + @Override + protected ModbusProtocol defineModbusProtocol(int unitId) { + return new ModbusProtocol(unitId, // + new FC3ReadRegistersTask(SUNSPEC_121 + 2, Priority.LOW, + m(EssKacoBlueplanetGridsave50.ChannelId.W_MAX, new UnsignedWordElement(SUNSPEC_121 + 2)), + new DummyRegisterElement(SUNSPEC_121 + 3, SUNSPEC_121 + 21), + m(EssKacoBlueplanetGridsave50.ChannelId.W_MAX_SF, new SignedWordElement(SUNSPEC_121 + 22))), + new FC16WriteRegistersTask(SUNSPEC_64201 + 4, + m(EssKacoBlueplanetGridsave50.ChannelId.REQUESTED_STATE, + new UnsignedWordElement(SUNSPEC_64201 + 4))), + new FC3ReadRegistersTask(SUNSPEC_64201 + 5, Priority.LOW, + m(EssKacoBlueplanetGridsave50.ChannelId.CURRENT_STATE, + new UnsignedWordElement(SUNSPEC_64201 + 5))), + new FC16WriteRegistersTask(SUNSPEC_64201 + 8, + m(EssKacoBlueplanetGridsave50.ChannelId.WATCHDOG, new UnsignedWordElement(SUNSPEC_64201 + 8))), + new FC16WriteRegistersTask(SUNSPEC_64201 + 9, + m(EssKacoBlueplanetGridsave50.ChannelId.W_SET_PCT, new SignedWordElement(SUNSPEC_64201 + 9))), + new FC3ReadRegistersTask(SUNSPEC_64201 + 46, Priority.LOW, + m(EssKacoBlueplanetGridsave50.ChannelId.W_SET_PCT_SF, + new SignedWordElement(SUNSPEC_64201 + 46))), + new FC3ReadRegistersTask(SUNSPEC_64202 + 6, Priority.LOW, + m(EssKacoBlueplanetGridsave50.ChannelId.V_SF, new SignedWordElement(SUNSPEC_64202 + 6)), + m(EssKacoBlueplanetGridsave50.ChannelId.A_SF, new SignedWordElement(SUNSPEC_64202 + 7))), + new FC16WriteRegistersTask(SUNSPEC_64202 + 8, + m(EssKacoBlueplanetGridsave50.ChannelId.DIS_MIN_V, new UnsignedWordElement(SUNSPEC_64202 + 8), + ElementToChannelConverter.SCALE_FACTOR_2), + m(EssKacoBlueplanetGridsave50.ChannelId.DIS_MAX_A, new UnsignedWordElement(SUNSPEC_64202 + 9), + ElementToChannelConverter.SCALE_FACTOR_2), + new DummyRegisterElement(SUNSPEC_64202 + 10), + m(EssKacoBlueplanetGridsave50.ChannelId.CHA_MAX_V, new UnsignedWordElement(SUNSPEC_64202 + 11), + ElementToChannelConverter.SCALE_FACTOR_2), + m(EssKacoBlueplanetGridsave50.ChannelId.CHA_MAX_A, new UnsignedWordElement(SUNSPEC_64202 + 12), + ElementToChannelConverter.SCALE_FACTOR_2), + new DummyRegisterElement(SUNSPEC_64202 + 13, SUNSPEC_64202 + 14), + m(EssKacoBlueplanetGridsave50.ChannelId.EN_LIMIT, new UnsignedWordElement(SUNSPEC_64202 + 15))), + new FC3ReadRegistersTask(SUNSPEC_64203 + 5, Priority.LOW, + m(EssKacoBlueplanetGridsave50.ChannelId.SOC_SF, new SignedWordElement(SUNSPEC_64203 + 5)), + m(EssKacoBlueplanetGridsave50.ChannelId.SOH_SF, new SignedWordElement(SUNSPEC_64203 + 6)), + m(EssKacoBlueplanetGridsave50.ChannelId.TEMP_SF, new SignedWordElement(SUNSPEC_64203 + 7))), + new FC16WriteRegistersTask(SUNSPEC_64203 + 16, + m(EssKacoBlueplanetGridsave50.ChannelId.BAT_SOC_, new UnsignedWordElement(SUNSPEC_64203 + 16)), + m(EssKacoBlueplanetGridsave50.ChannelId.BAT_SOH, new UnsignedWordElement(SUNSPEC_64203 + 17)), + m(EssKacoBlueplanetGridsave50.ChannelId.BAT_TEMP, new SignedWordElement(SUNSPEC_64203 + 18))), + new FC16WriteRegistersTask(SUNSPEC_64302 + 12, + m(EssKacoBlueplanetGridsave50.ChannelId.COMMAND_ID_REQ, + new SignedWordElement(SUNSPEC_64302 + 12)), + m(EssKacoBlueplanetGridsave50.ChannelId.REQ_PARAM_0, + new UnsignedDoublewordElement(SUNSPEC_64302 + 13))), + new FC16WriteRegistersTask(SUNSPEC_64302 + 29, + m(EssKacoBlueplanetGridsave50.ChannelId.COMMAND_ID_REQ_ENA, + new UnsignedWordElement(SUNSPEC_64302 + 29))), + new FC3ReadRegistersTask(SUNSPEC_64302 + 30, Priority.LOW, + m(EssKacoBlueplanetGridsave50.ChannelId.COMMAND_ID_RES, + new SignedWordElement(SUNSPEC_64302 + 30)), + m(EssKacoBlueplanetGridsave50.ChannelId.RETURN_CODE, + new SignedWordElement(SUNSPEC_64302 + 31)))); + } + + @Override + public String debugLog() { + return "Current state: " + this.channel(ChannelId.CURRENT_STATE).value().asOptionString() + + ", requested State: " + this.channel(ChannelId.REQUESTED_STATE).value().asOptionString(); + } + + @Override + public Power getPower() { + return this.power; + } + + @Override + public void applyPower(int activePower, int reactivePower) { + if (!isSystemInGridmode()) { // necessary? or should we set these values always? + return; + } + + IntegerWriteChannel disMinVChannel = this.channel(ChannelId.DIS_MIN_V); + IntegerWriteChannel disMaxAChannel = this.channel(ChannelId.DIS_MAX_A); + IntegerWriteChannel chaMaxVChannel = this.channel(ChannelId.CHA_MAX_V); + IntegerWriteChannel chaMaxAChannel = this.channel(ChannelId.CHA_MAX_A); + IntegerWriteChannel enLimitChannel = this.channel(ChannelId.EN_LIMIT); + IntegerWriteChannel wSetPctChannel = this.channel(ChannelId.W_SET_PCT); + IntegerReadChannel wSetPct_SFChannel = this.channel(ChannelId.W_SET_PCT_SF); + + try { + // TODO according to setup manual 64202.DisMinV and 64202.ChaMaxV must not be + // zero + // what happens if battery is null? + + if (battery != null) { + int disMinV = battery.getDischargeMinVoltage().value().orElse(0); // TODO scalefactor!! + int chaMaxV = battery.getChargeMaxVoltage().value().orElse(0); + int disMaxA = battery.getDischargeMaxCurrent().value().orElse(0); + int chaMaxA = battery.getChargeMaxCurrent().value().orElse(0); + + // Currently soltaro battery rack provides values in milliVolt, but from where + // do we know this? + // --> Working with channel ids defined from api, then we need other scale + // factors... + // in case for soltraro this would be -2, TODO + // + + // Set fixed ranges for the first + + int voltageScaleFactor = 10; // + @SuppressWarnings("unchecked") // TODO why is it unsafe? + Optional vSFOpt = (Optional) this.channel(ChannelId.V_SF).value().asOptional(); + if (vSFOpt.isPresent()) { + voltageScaleFactor = (int) (1 / Math.pow(10, vSFOpt.get())); + } + + int currentScaleFactor = 10; // + @SuppressWarnings("unchecked") // TODO why is it unsafe? + Optional aSFOpt = (Optional) this.channel(ChannelId.A_SF).value().asOptional(); + if (aSFOpt.isPresent()) { + currentScaleFactor = (int) (1 / Math.pow(10, aSFOpt.get())); + } + int channelscale = 100; + // TODO + // channels are defined in millivolt/milliampere with scalefactor 2 what do we + // need to write? --> we need to write millivolt/ampere e.g. 696.000 + disMinV = 696 * voltageScaleFactor * channelscale; + chaMaxV = 854 * voltageScaleFactor * channelscale; + disMaxA = 13 * currentScaleFactor * channelscale; + chaMaxA = 13 * currentScaleFactor * channelscale; + + if (disMinV != 0) { + disMinVChannel.setNextWriteValue(disMinV); + } + + if (chaMaxV != 0) { + chaMaxVChannel.setNextWriteValue(chaMaxV); + } + disMaxAChannel.setNextWriteValue(disMaxA); + chaMaxAChannel.setNextWriteValue(chaMaxA); + + enLimitChannel.setNextWriteValue(1); + } + // according to manual active power has to be set in % of maximum active power + // with scale factor see page 10 + // WSetPct = (WSet_Watt * 100) / ( W_Max_unscaled * 10^W_Max_SF * 10^WSetPct_SF + // ) + + Optional wSetPctOpt = wSetPct_SFChannel.value().asOptional(); + if (wSetPctOpt.isPresent()) { + + int scalefactor = wSetPctOpt.get(); + int WSetPct = (int) ((activePower * 100) / (MAX_APPARENT_POWER * Math.pow(10, scalefactor))); + + wSetPctChannel.setNextWriteValue(WSetPct); + } + } catch (OpenemsException e) { + log.error("problem occurred while trying so set active power" + e.getMessage()); + } + + } + + private boolean isSystemInGridmode() { + IntegerReadChannel currentStateChannel = this.channel(ChannelId.CURRENT_STATE); + Optional> currentStateOpt = currentStateChannel.value().asEnumOptional(); + return currentStateOpt.isPresent() && currentStateOpt.get() == CurrentState.GRID_CONNECTED; + } + + private void startGridMode() { + IntegerWriteChannel requestedState = this.channel(ChannelId.REQUESTED_STATE); + try { + requestedState.setNextWriteValue(RequestedState.GRID_CONNECTED.value); + } catch (OpenemsException e) { + // TODO + log.error("problem occurred while trying to start grid mode" + e.getMessage()); + } + } + + private void startSystem() { + IntegerWriteChannel requestedState = this.channel(ChannelId.REQUESTED_STATE); + try { + requestedState.setNextWriteValue(RequestedState.STANDBY.value); + } catch (OpenemsException e) { + // TODO + log.error("problem occurred while trying to start the inverter" + e.getMessage()); + } + } + + private void doErrorHandling() { + // find out the reason what is wrong an react + // for a first try, switch system off, it will be restarted + IntegerWriteChannel requestedState = this.channel(ChannelId.REQUESTED_STATE); + try { + requestedState.setNextWriteValue(RequestedState.OFF.value); + } catch (OpenemsException e) { + // TODO + + log.error("problem occurred while error handling" + e.getMessage()); + } + } + + @Override + public int getPowerPrecision() { + IntegerReadChannel wSetPct_SFChannel = this.channel(ChannelId.W_SET_PCT_SF); + Optional wSetPctOpt = wSetPct_SFChannel.value().asOptional(); + int scalefactor = wSetPctOpt.orElse(0); + return (int) (MAX_APPARENT_POWER * 0.01 * Math.pow(10, scalefactor)); + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: // TODO is this the right event? + handleStateMachine(); + break; + } + } + + private void handleStateMachine() { + IntegerReadChannel currentStateChannel = this.channel(ChannelId.CURRENT_STATE); + Optional> currentStateOpt = currentStateChannel.value().asEnumOptional(); + if (!currentStateOpt.isPresent()) { + return; + } + + CurrentState currentState = (CurrentState) currentStateOpt.get(); + + switch (currentState) { + case OFF: + startSystem(); + break; + + case STANDBY: + startGridMode(); + break; + + case ERROR: + doErrorHandling(); + break; + + case GRID_CONNECTED: + break; + case PRECHARGE: + case NO_ERROR_PENDING: + case SHUTTING_DOWN: + case STARTING: + case THROTTLED: + // Do nothing because these states are only temporarily reached + break; + } + } +} diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Utils.java b/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Utils.java new file mode 100644 index 00000000000..f975894888a --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/src/io/openems/edge/ess/kaco/blueplanet/gridsave50/Utils.java @@ -0,0 +1,83 @@ +package io.openems.edge.ess.kaco.blueplanet.gridsave50; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.AbstractReadChannel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.IntegerWriteChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; + +public class Utils { + public static Stream> initializeChannels(EssKacoBlueplanetGridsave50 ess) { + // Define the channels. Using streams + switch enables Eclipse IDE to tell us if + // we are missing an Enum value. + return Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(ess, channelId); + } + return null; + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case ACTIVE_POWER: + case REACTIVE_POWER: + case ACTIVE_CHARGE_ENERGY: // TODO ACTIVE_CHARGE_ENERGY + case ACTIVE_DISCHARGE_ENERGY: // TODO ACTIVE_DISCHARGE_ENERGY + return new IntegerReadChannel(ess, channelId); + case MAX_ACTIVE_POWER: + return new IntegerReadChannel(ess, channelId, EssKacoBlueplanetGridsave50.MAX_APPARENT_POWER); + case GRID_MODE: + return new IntegerReadChannel(ess, channelId, SymmetricEss.GridMode.UNDEFINED.ordinal()); + } + return null; + }), Arrays.stream(ManagedSymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER: + case DEBUG_SET_REACTIVE_POWER: + return new IntegerReadChannel(ess, channelId); + } + return null; + }), Arrays.stream(EssKacoBlueplanetGridsave50.ChannelId.values()).map(channelId -> { + switch (channelId) { +// case CHA_CUTOFF_A: + case CHA_MAX_A: + case CHA_MAX_V: +// case DIS_CUTOFF_A: + case DIS_MAX_A: + case DIS_MIN_V: + case EN_LIMIT: + case W_SET_PCT: + case REQUESTED_STATE: + case BAT_SOC_: + case BAT_SOH: + case BAT_TEMP: + case COMMAND_ID_REQ: + case REQ_PARAM_0: + case COMMAND_ID_REQ_ENA: + return new IntegerWriteChannel(ess, channelId); + case A_SF: + case V_SF: + case VENDOR_OPERATING_STATE: + case CURRENT_STATE: + case WATCHDOG: + case W_MAX: + case W_MAX_SF: + case W_SET_PCT_SF: + case SOC_SF: + case SOH_SF: + case TEMP_SF: + case COMMAND_ID_RES: + case RETURN_CODE: + return new IntegerReadChannel(ess, channelId); + } + return null; + }) // + ).flatMap(channel -> channel); + } +} diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/test/.gitignore b/io.openems.edge.ess.kaco.blueplanet.gridsave50/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.ess.kaco.blueplanet.gridsave50/test/io/openems/edge/ess/kaco/blueplanet50/ProviderImplTest.java b/io.openems.edge.ess.kaco.blueplanet.gridsave50/test/io/openems/edge/ess/kaco/blueplanet50/ProviderImplTest.java new file mode 100644 index 00000000000..5aae5b9d183 --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet.gridsave50/test/io/openems/edge/ess/kaco/blueplanet50/ProviderImplTest.java @@ -0,0 +1,26 @@ +package io.openems.edge.ess.kaco.blueplanet50; + +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; + +import io.openems.edge.ess.kaco.blueplanet.gridsave50.EssKacoBlueplanetGridsave50; + +/* + * Example JUNit test case + * + */ + +public class ProviderImplTest { + + /* + * Example test method + */ + + @Test + public void simple() { + EssKacoBlueplanetGridsave50 impl = new EssKacoBlueplanetGridsave50(); + assertNotNull(impl); + } + +} diff --git a/io.openems.edge.ess.kaco.blueplanet50/.classpath b/io.openems.edge.ess.kaco.blueplanet50/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.ess.kaco.blueplanet50/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.ess.kostal.piko/.classpath b/io.openems.edge.ess.kostal.piko/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.ess.kostal.piko/.gitignore b/io.openems.edge.ess.kostal.piko/.gitignore new file mode 100644 index 00000000000..e62678f49e9 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.ess.kostal.piko/bnd.bnd b/io.openems.edge.ess.kostal.piko/bnd.bnd new file mode 100644 index 00000000000..fd1de796184 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/bnd.bnd @@ -0,0 +1,24 @@ +Bundle-Name: OpenEMS Edge ESS KOSTAL PIKO +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.ess.symmetric.readonly.api,\ + io.openems.edge.ess.api,\ + io.openems.edge.ess.symmetric.api,\ + io.openems.edge.ess.power.symmetric,\ + io.openems.edge.ess.power.api + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.ess.api;version=latest,\ + io.openems.edge.common;version=latest,\ + io.openems.common;version=latest,\ + com.google.guava + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 +Private-Package: io.openems.edge.ess.kostal.piko \ No newline at end of file diff --git a/io.openems.edge.ess.kostal.piko/debug.bndrun b/io.openems.edge.ess.kostal.piko/debug.bndrun new file mode 100644 index 00000000000..7f4d64df212 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/debug.bndrun @@ -0,0 +1,13 @@ +# +# io.openems.edge.ess.kostal.piko DEBUG LAUNCH SPECFICATION +# + +-include: ~io.openems.edge.ess.kostal.piko.bndrun + +-runrequires.debug: \ + ${debug-bundles} + +-runtrace: true + +-runbundles: \ + ${error;Resolve first} diff --git a/io.openems.edge.ess.kostal.piko/io.openems.edge.ess.kostal.piko.bndrun b/io.openems.edge.ess.kostal.piko/io.openems.edge.ess.kostal.piko.bndrun new file mode 100644 index 00000000000..4ec55432779 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/io.openems.edge.ess.kostal.piko.bndrun @@ -0,0 +1,14 @@ +# +# io.openems.edge.ess.kostal.piko LAUNCH SPECIFICATION +# + + +Bundle-Version: 1.0.0.${tstamp} +Bundle-SymbolicName: io.openems.edge.ess.kostal.piko.launch +JPM-Command: provider + + +-runrequires: \ + osgi.identity;filter:='(osgi.identity=io.openems.edge.ess.kostal.piko.provider)' + +-runbundles: ${error;You must first resolve this bndrun file before you can run it} diff --git a/io.openems.edge.ess.kostal.piko/readme.md b/io.openems.edge.ess.kostal.piko/readme.md new file mode 100644 index 00000000000..edc8e6e9866 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.ess.kostal.piko Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Config.java b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Config.java new file mode 100644 index 00000000000..54fb1859689 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Config.java @@ -0,0 +1,26 @@ +package io.openems.edge.ess.kostal.piko; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition( // + name = "ESS KOSTAL PIKO", // + description = "Implements a KOSTAL PIKO based energy storage system.") +@interface Config { + String service_pid(); + + String id() default "ess0"; + + @AttributeDefinition(name = "IP-Address", description = "The IP address") + String ip(); + + @AttributeDefinition(name = "Unit ID", description = "The Unit ID") + int unitID() default 0xff; + + @AttributeDefinition(name = "Port", description = "The Port") + int port() default 81; + + boolean enabled() default true; + + String webconsole_configurationFactory_nameHint() default "ESS KOSTAL PIKO [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/EssKostalPiko.java b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/EssKostalPiko.java new file mode 100644 index 00000000000..13165f0332e --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/EssKostalPiko.java @@ -0,0 +1,331 @@ +package io.openems.edge.ess.kostal.piko; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.common.taskmanager.TasksManager; +import io.openems.edge.ess.api.AsymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.dccharger.api.EssDcCharger; +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.doc.Unit; + +@Designate(ocd = Config.class, factory = true) +@Component( // + name = "Ess.Kostal.Piko", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE // +) +public class EssKostalPiko extends AbstractOpenemsComponent + implements EssDcCharger, AsymmetricEss, SymmetricEss, OpenemsComponent, EventHandler { + + protected final static int MAX_ACTUAL_POWER = 6600; + protected final static int MAX_APPARENT_POWER = 2300; + private final TasksManager readTasksManager; + private SocketConnection socketConnection = null; + private Worker worker = null; + + public EssKostalPiko() { + Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); + this.readTasksManager = new TasksManager(// + // ONCE + new ReadTask(ChannelId.INVERTER_NAME, Priority.ONCE, FieldType.STRING, 0x01000300), // + new ReadTask(ChannelId.ARTICLE_NUMBER, Priority.ONCE, FieldType.STRING, 0x01000100), // + new ReadTask(ChannelId.INVERTER_SERIAL_NUMBER, Priority.ONCE, FieldType.STRING, 0x01000200), // + new ReadTask(ChannelId.FIRMWARE_VERSION, Priority.ONCE, FieldType.STRING, 0x01000801), // + new ReadTask(ChannelId.HARDWARE_VERSION, Priority.ONCE, FieldType.STRING, 0x01000802), // + new ReadTask(ChannelId.KOMBOARD_VERSION, Priority.ONCE, FieldType.STRING, 0x01000803), // + new ReadTask(ChannelId.PARAMETER_VERSION, Priority.ONCE, FieldType.STRING, 0x01000901), // + new ReadTask(ChannelId.COUNTRY_NAME, Priority.ONCE, FieldType.STRING, 0x01000902), // + new ReadTask(ChannelId.INVERTER_OPERATING_STATUS, Priority.ONCE, FieldType.STRING, 0X08000105), // + new ReadTask(ChannelId.INVERTER_TYPE_NAME, Priority.ONCE, FieldType.STRING, 0x01000D00), // + new ReadTask(ChannelId.NUMBER_OF_STRING, Priority.ONCE, FieldType.INTEGER, 0x01000500), // + new ReadTask(ChannelId.NUMBER_OF_PHASES, Priority.ONCE, FieldType.INTEGER, 0x01000600), // + new ReadTask(ChannelId.POWER_ID, Priority.ONCE, FieldType.INTEGER, 0x01000400), // + new ReadTask(ChannelId.PRESENT_ERROR_EVENT_CODE_1, Priority.ONCE, FieldType.INTEGER, 0x08000300), // + new ReadTask(ChannelId.PRESENT_ERROR_EVENT_CODE_2, Priority.ONCE, FieldType.INTEGER, 0x08000400), // + new ReadTask(ChannelId.FEED_IN_TIME, Priority.ONCE, FieldType.INTEGER, 0x0F000100), // + new ReadTask(ChannelId.INVERTER_STATUS, Priority.ONCE, FieldType.INTEGER, 0x01000B00), // + new ReadTask(ChannelId.BAUDRATE_INDEX_MODBUS_RTU, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000206), // + new ReadTask(ChannelId.BATTERY_TEMPERATURE, Priority.ONCE, FieldType.FLOAT, 0x02000703), // + new ReadTask(ChannelId.ISOLATION_RESISTOR, Priority.ONCE, FieldType.FLOAT, 0x06000100), // + new ReadTask(ChannelId.GRID_FREQUENCY, Priority.ONCE, FieldType.FLOAT, 0x04000600), // + new ReadTask(ChannelId.COSINUS_PHI, Priority.ONCE, FieldType.FLOAT, 0x04000700), // + new ReadTask(ChannelId.SETTING_MANUAL_IP1, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, 0x07000102), // + new ReadTask(ChannelId.SETTING_MANUAL_IP2, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, 0x07000103), // + new ReadTask(ChannelId.SETTING_MANUAL_IP3, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, 0x07000104), // + new ReadTask(ChannelId.SETTING_MANUAL_IP4, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, 0x07000105), // + new ReadTask(ChannelId.SETTING_MANUAL_SUBNET_MASK_1, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000106), // + new ReadTask(ChannelId.SETTING_MANUAL_SUBNET_MASK_2, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000107), // + new ReadTask(ChannelId.SETTING_MANUAL_SUBNET_MASK_3, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000108), // + new ReadTask(ChannelId.SETTING_MANUAL_SUBNET_MASK_4, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000109), // + new ReadTask(ChannelId.SETTING_MANUAL_GATEWAY_1, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x0700010B), // + new ReadTask(ChannelId.SETTING_MANUAL_GATEWAY_2, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x0700010C), // + new ReadTask(ChannelId.SETTING_MANUAL_GATEWAY_3, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x0700010D), // + new ReadTask(ChannelId.SETTING_MANUAL_GATEWAY_4, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x0700010E), // + new ReadTask(ChannelId.SETTING_MANUAL_IP_DNS_FIRST_1, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x0700010F), // + new ReadTask(ChannelId.SETTING_MANUAL_IP_DNS_FIRST_2, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000110), // + new ReadTask(ChannelId.SETTING_MANUAL_IP_DNS_FIRST_3, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000111), // + new ReadTask(ChannelId.SETTING_MANUAL_IP_DNS_FIRST_4, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000112), // + new ReadTask(ChannelId.SETTING_MANUAL_IP_DNS_SECOND_1, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000113), // + new ReadTask(ChannelId.SETTING_MANUAL_IP_DNS_SECOND_2, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000114), // + new ReadTask(ChannelId.SETTING_MANUAL_IP_DNS_SECOND_3, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000115), // + new ReadTask(ChannelId.SETTING_MANUAL_IP_DNS_SECOND_4, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, + 0x07000116), // + new ReadTask(ChannelId.SETTING_AUTO_IP, Priority.ONCE, FieldType.BOOLEAN, 0x07000101), // + new ReadTask(ChannelId.SETTING_MANUAL_EXTERNAL_ROUTER, Priority.ONCE, FieldType.BOOLEAN, 0x0700010A), // + new ReadTask(ChannelId.PRELOAD_MODBUS_RTU, Priority.ONCE, FieldType.BOOLEAN, 0x07000202), // + new ReadTask(ChannelId.TERMINATION_MODBUS_RTU, Priority.ONCE, FieldType.BOOLEAN, 0x07000203), // + new ReadTask(ChannelId.ADDRESS_MODBUS_RTU, Priority.ONCE, FieldType.INTEGER_UNSIGNED_BYTE, 0x07000201), + + // LOW + new ReadTask(ChannelId.FEED_IN_STATUS, Priority.LOW, FieldType.BOOLEAN, 0x01000A00), + new ReadTask(ChannelId.DC_VOLTAGE_STRING_1, Priority.LOW, FieldType.FLOAT, 0x02000302), // + new ReadTask(ChannelId.DC_VOLTAGE_STRING_2, Priority.LOW, FieldType.FLOAT, 0x02000402), // + new ReadTask(ChannelId.DC_VOLTAGE_STRING_3, Priority.LOW, FieldType.FLOAT, 0x02000502), // + + new ReadTask(ChannelId.OVERALL_DC_CURRENT, Priority.LOW, FieldType.FLOAT, 0x02000100), // + new ReadTask(ChannelId.DC_CURRENT_STRING_1, Priority.LOW, FieldType.FLOAT, 0x02000301), // + new ReadTask(ChannelId.DC_CURRENT_STRING_2, Priority.LOW, FieldType.FLOAT, 0x02000401), // + new ReadTask(ChannelId.DC_CURRENT_STRING_3, Priority.LOW, FieldType.FLOAT, 0x02000501), // + + new ReadTask(ChannelId.DC_POWER_STRING_1, Priority.LOW, FieldType.FLOAT, 0x02000303), // + new ReadTask(ChannelId.DC_POWER_STRING_2, Priority.LOW, FieldType.FLOAT, 0x02000403), // + new ReadTask(ChannelId.DC_POWER_STRING_3, Priority.LOW, FieldType.FLOAT, 0x02000503), // + + new ReadTask(ChannelId.BATTERY_CURRENT_DIRECTION, Priority.LOW, FieldType.FLOAT, 0x02000706), // + new ReadTask(ChannelId.AC_CURRENT_L1, Priority.LOW, FieldType.FLOAT, 0x04000201), // + new ReadTask(ChannelId.AC_CURRENT_L2, Priority.LOW, FieldType.FLOAT, 0x04000301), // + new ReadTask(ChannelId.AC_CURRENT_L3, Priority.LOW, FieldType.FLOAT, 0x04000401), // + new ReadTask(ChannelId.POWER_LIMITATION_OF_EVU, Priority.LOW, FieldType.FLOAT, 0x04000500), // + new ReadTask(ChannelId.HOME_CURRENT_L1, Priority.LOW, FieldType.FLOAT, 0x05000401), // + new ReadTask(ChannelId.HOME_CURRENT_L2, Priority.LOW, FieldType.FLOAT, 0x05000501), // + new ReadTask(ChannelId.HOME_CURRENT_L3, Priority.LOW, FieldType.FLOAT, 0x05000601), // + new ReadTask(ChannelId.MAX_RESIDUAL_CURRENT, Priority.LOW, FieldType.FLOAT, 0x06000301), // + new ReadTask(ChannelId.ANALOG_INPUT_CH_1, Priority.LOW, FieldType.FLOAT, 0x0A000101), // + new ReadTask(ChannelId.ANALOG_INPUT_CH_2, Priority.LOW, FieldType.FLOAT, 0x0A000201), // + new ReadTask(ChannelId.ANALOG_INPUT_CH_3, Priority.LOW, FieldType.FLOAT, 0x0A000301), // + new ReadTask(ChannelId.ANALOG_INPUT_CH_4, Priority.LOW, FieldType.FLOAT, 0x0A000401), // + new ReadTask(ChannelId.SELF_CONSUMPTION_RATE_TOTAL, Priority.LOW, FieldType.FLOAT, 0x0F000410), // + new ReadTask(ChannelId.SELF_CONSUMPTION_RATE_DAY, Priority.LOW, FieldType.FLOAT, 0x0F00040E), // + new ReadTask(ChannelId.DEGREE_OF_SELF_SUFFICIENCY_DAY, Priority.LOW, FieldType.FLOAT, 0x0F00040F), // + new ReadTask(ChannelId.DEGREE_OF_SELF_SUFFICIENCY_TOTAL, Priority.LOW, FieldType.FLOAT, 0x0F000411), // + new ReadTask(ChannelId.HOME_POWER_L1, Priority.LOW, FieldType.FLOAT, 0x05000402), // + new ReadTask(ChannelId.HOME_POWER_L2, Priority.LOW, FieldType.FLOAT, 0x05000502), // + new ReadTask(ChannelId.HOME_POWER_L3, Priority.LOW, FieldType.FLOAT, 0x05000602), // + new ReadTask(ChannelId.HOME_CONSUMPTION_GRID, Priority.LOW, FieldType.FLOAT, 0x05000300), // + new ReadTask(ChannelId.HOME_CONSUMPTION_PV, Priority.LOW, FieldType.FLOAT, 0x05000100), // + new ReadTask(ChannelId.HOME_TOTAL_POWER, Priority.LOW, FieldType.FLOAT, 0x05000700), // + new ReadTask(ChannelId.HOME_SELF_CONSUMPTION_TOTAL, Priority.LOW, FieldType.FLOAT, 0x05000800), // + new ReadTask(ChannelId.HOME_CONSUMPTION_L1, Priority.LOW, FieldType.FLOAT, 0x05000403), // + new ReadTask(ChannelId.HOME_CONSUMPTION_L2, Priority.LOW, FieldType.FLOAT, 0x05000503), // + new ReadTask(ChannelId.HOME_CONSUMPTION_L3, Priority.LOW, FieldType.FLOAT, 0x05000603), // + new ReadTask(ChannelId.HOME_CONSUMPTION_TOTAL, Priority.LOW, FieldType.FLOAT, 0x0F000301), // + new ReadTask(ChannelId.HOME_CONSUMPTION_DAY, Priority.LOW, FieldType.FLOAT, 0x0F000302), // + new ReadTask(ChannelId.HOME_CONSUMPTION_BATTERY, Priority.LOW, FieldType.FLOAT, 0x05000200), // + new ReadTask(ChannelId.BATTERY_CURRENT, Priority.LOW, FieldType.FLOAT, 0x02000701), // + new ReadTask(ChannelId.SELF_CONSUMPTION_TOTAL, Priority.LOW, FieldType.FLOAT, 0x0F000401), // + new ReadTask(ChannelId.SELF_CONSUMPTION_DAY, Priority.LOW, FieldType.FLOAT, 0x0F000402), // + new ReadTask(ChannelId.BATTERY_VOLTAGE, Priority.LOW, FieldType.FLOAT, 0x02000702), // + // HIGH + + new ReadTask(EssDcCharger.ChannelId.ACTUAL_POWER, Priority.HIGH, FieldType.FLOAT, 0x02000200), // + // TODO Energy Related with cycles check it again + // new ReadTask(EssDcCharger.ChannelId.ACTUAL_ENERGY, Priority.HIGH, + // FieldType.INTEGER_UNSIGNED_BYTE, 0x02000704),// + + new ReadTask(SymmetricEss.ChannelId.SOC, Priority.HIGH, FieldType.INTEGER, 0x02000705), // + + new ReadTask(AsymmetricEss.ChannelId.ACTIVE_POWER_L1, Priority.HIGH, FieldType.FLOAT, 0x04000203), // + new ReadTask(AsymmetricEss.ChannelId.ACTIVE_POWER_L2, Priority.HIGH, FieldType.FLOAT, 0x04000303), // + new ReadTask(AsymmetricEss.ChannelId.ACTIVE_POWER_L3, Priority.HIGH, FieldType.FLOAT, 0x04000403), // + new ReadTask(SymmetricEss.ChannelId.ACTIVE_POWER, Priority.HIGH, FieldType.FLOAT, 0x04000100), // + + new ReadTask(ChannelId.AC_VOLTAGE_L1, Priority.HIGH, FieldType.FLOAT, 0x04000202), // + new ReadTask(ChannelId.AC_VOLTAGE_L2, Priority.HIGH, FieldType.FLOAT, 0x04000302), // + new ReadTask(ChannelId.AC_VOLTAGE_L3, Priority.HIGH, FieldType.FLOAT, 0x04000402), // + new ReadTask(ChannelId.YIELD_DAY, Priority.HIGH, FieldType.FLOAT, 0x0F000202), // + new ReadTask(ChannelId.YIELD_TOTAL, Priority.HIGH, FieldType.FLOAT, 0x0F000201)// + ); + } + + @Activate + void activate(ComponentContext context, Config config) { + super.activate(context, config.service_pid(), config.id(), config.enabled()); + this.socketConnection = new SocketConnection(config.ip(), config.port(), (byte) config.unitID()); + Protocol protocol = new Protocol(this, socketConnection); + this.worker = new Worker(protocol, this.readTasksManager); + this.worker.activate(config.id()); + } + + @Deactivate + protected void deactivate() { + if (this.worker != null) { + this.worker.deactivate(); + } + if (this.socketConnection != null) { + this.socketConnection.close(); + } + super.deactivate(); + } + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + INVERTER_NAME(new Doc().type(OpenemsType.STRING)), // + ARTICLE_NUMBER(new Doc().type(OpenemsType.STRING)), // + INVERTER_SERIAL_NUMBER(new Doc().type(OpenemsType.STRING)), // + FIRMWARE_VERSION(new Doc().type(OpenemsType.STRING)), // + HARDWARE_VERSION(new Doc().type(OpenemsType.STRING)), // + KOMBOARD_VERSION(new Doc().type(OpenemsType.STRING)), // + PARAMETER_VERSION(new Doc().type(OpenemsType.STRING)), // + COUNTRY_NAME(new Doc().type(OpenemsType.STRING)), // + INVERTER_OPERATING_STATUS(new Doc().type(OpenemsType.STRING)), // + INVERTER_TYPE_NAME(new Doc().type(OpenemsType.STRING)), // + NUMBER_OF_STRING(new Doc().type(OpenemsType.INTEGER)), // + NUMBER_OF_PHASES(new Doc().type(OpenemsType.INTEGER)), // + POWER_ID(new Doc().type(OpenemsType.INTEGER)), // + PRESENT_ERROR_EVENT_CODE_1(new Doc().type(OpenemsType.INTEGER)), // + PRESENT_ERROR_EVENT_CODE_2(new Doc().type(OpenemsType.INTEGER)), // + FEED_IN_TIME(new Doc().type(OpenemsType.INTEGER)), // + INVERTER_STATUS(new Doc().type(OpenemsType.INTEGER)), // + ADDRESS_MODBUS_RTU(new Doc().type(OpenemsType.INTEGER)), // + BAUDRATE_INDEX_MODBUS_RTU(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP1(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP2(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP3(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP4(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_SUBNET_MASK_1(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_SUBNET_MASK_2(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_SUBNET_MASK_3(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_SUBNET_MASK_4(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_GATEWAY_1(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_GATEWAY_2(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_GATEWAY_3(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_GATEWAY_4(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP_DNS_FIRST_1(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP_DNS_FIRST_2(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP_DNS_FIRST_3(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP_DNS_FIRST_4(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP_DNS_SECOND_1(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP_DNS_SECOND_2(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP_DNS_SECOND_3(new Doc().type(OpenemsType.INTEGER)), // + SETTING_MANUAL_IP_DNS_SECOND_4(new Doc().type(OpenemsType.INTEGER)), // + + FEED_IN_STATUS(new Doc().type(OpenemsType.BOOLEAN)), // + SETTING_AUTO_IP(new Doc().type(OpenemsType.BOOLEAN)), // + SETTING_MANUAL_EXTERNAL_ROUTER(new Doc().type(OpenemsType.BOOLEAN)), // + PRELOAD_MODBUS_RTU(new Doc().type(OpenemsType.BOOLEAN)), // + TERMINATION_MODBUS_RTU(new Doc().type(OpenemsType.BOOLEAN)), // + + BATTERY_CURRENT_DIRECTION(new Doc().option(0, "charge").option(1, "discharge").type(OpenemsType.FLOAT)), // + OVERALL_DC_CURRENT(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + OVERALL_DC_POWER(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + DC_CURRENT_STRING_1(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + DC_VOLTAGE_STRING_1(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + DC_POWER_STRING_1(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + DC_CURRENT_STRING_2(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + DC_VOLTAGE_STRING_2(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + DC_POWER_STRING_2(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + DC_CURRENT_STRING_3(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + DC_VOLTAGE_STRING_3(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + DC_POWER_STRING_3(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + BATTERY_CURRENT(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + BATTERY_VOLTAGE(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + BATTERY_TEMPERATURE(new Doc().type(OpenemsType.FLOAT).unit(Unit.DEGREE_CELSIUS)), // + + AC_TOTAL_POWER(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + AC_VOLTAGE_L1(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + AC_VOLTAGE_L2(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + AC_VOLTAGE_L3(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + AC_CURRENT_L1(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + AC_CURRENT_L2(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + AC_CURRENT_L3(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + AC_POWER_L1(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + AC_POWER_L2(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + AC_POWER_L3(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + POWER_LIMITATION_OF_EVU(new Doc().type(OpenemsType.FLOAT).unit(Unit.PERCENT)), // + GRID_FREQUENCY(new Doc().type(OpenemsType.FLOAT).unit(Unit.HERTZ)), // + COSINUS_PHI(new Doc().type(OpenemsType.FLOAT)), // + HOME_CONSUMPTION_PV(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_CONSUMPTION_BATTERY(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_CONSUMPTION_GRID(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_CURRENT_L1(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + HOME_POWER_L1(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_CONSUMPTION_L1(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_CURRENT_L2(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + HOME_POWER_L2(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_CONSUMPTION_L2(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_CURRENT_L3(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + HOME_POWER_L3(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_CONSUMPTION_L3(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_TOTAL_POWER(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + HOME_SELF_CONSUMPTION_TOTAL(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT)), // + ISOLATION_RESISTOR(new Doc().type(OpenemsType.FLOAT).unit(Unit.KILOOHM)), // + MAX_RESIDUAL_CURRENT(new Doc().type(OpenemsType.FLOAT).unit(Unit.AMPERE)), // + ANALOG_INPUT_CH_1(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + ANALOG_INPUT_CH_2(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + ANALOG_INPUT_CH_3(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + ANALOG_INPUT_CH_4(new Doc().type(OpenemsType.FLOAT).unit(Unit.VOLT)), // + YIELD_TOTAL(new Doc().type(OpenemsType.FLOAT).unit(Unit.KILOWATT_HOURS)), // + YIELD_DAY(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT_HOURS)), // + HOME_CONSUMPTION_TOTAL(new Doc().type(OpenemsType.FLOAT).unit(Unit.KILOWATT_HOURS)), // + HOME_CONSUMPTION_DAY(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT_HOURS)), // + SELF_CONSUMPTION_TOTAL(new Doc().type(OpenemsType.FLOAT).unit(Unit.KILOWATT_HOURS)), // + SELF_CONSUMPTION_DAY(new Doc().type(OpenemsType.FLOAT).unit(Unit.WATT_HOURS)), // + SELF_CONSUMPTION_RATE_TOTAL(new Doc().type(OpenemsType.FLOAT).unit(Unit.PERCENT)), // + SELF_CONSUMPTION_RATE_DAY(new Doc().type(OpenemsType.FLOAT).unit(Unit.PERCENT)), // + DEGREE_OF_SELF_SUFFICIENCY_DAY(new Doc().type(OpenemsType.FLOAT)), // + DEGREE_OF_SELF_SUFFICIENCY_TOTAL(new Doc().type(OpenemsType.FLOAT)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + @Override + public Doc doc() { + return this.doc; + } + } + + @Override + public void handleEvent(Event event) { + if (!this.isEnabled()) { + return; + } + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_AFTER_WRITE: + this.worker.triggerNextCycle(); + } + } + +} diff --git a/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/FieldType.java b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/FieldType.java new file mode 100644 index 00000000000..e4a4b689888 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/FieldType.java @@ -0,0 +1,5 @@ +package io.openems.edge.ess.kostal.piko; + +public enum FieldType { + STRING, INTEGER, BOOLEAN, INTEGER_UNSIGNED_BYTE, FLOAT +} diff --git a/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Protocol.java b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Protocol.java new file mode 100644 index 00000000000..759171febf6 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Protocol.java @@ -0,0 +1,181 @@ +package io.openems.edge.ess.kostal.piko; + +import java.lang.reflect.Array; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.edge.common.channel.Channel; + +public class Protocol { + + private final Logger log = LoggerFactory.getLogger(EssKostalPiko.class); + private final EssKostalPiko parent; + private final SocketConnection socketConnection; + + public Protocol(EssKostalPiko parent, SocketConnection socketConnection) { + this.parent = parent; + this.socketConnection = socketConnection; + } + + public void execute(List nextReadTasks) { + for (ReadTask task : nextReadTasks) { + try { + this.socketConnection.open(); + Channel channel = this.parent.channel(task.getChannelId()); + switch (task.getFieldType()) { + case STRING: + channel.setNextValue(getStringValue(task.getAddress())); + break; + case INTEGER: + channel.setNextValue(getIntegerValue(task.getAddress())); + break; + case BOOLEAN: + channel.setNextValue(getBooleanValue(task.getAddress())); + break; + case INTEGER_UNSIGNED_BYTE: + channel.setNextValue(getIntegerFromUnsignedByte(task.getAddress())); + break; + case FLOAT: + channel.setNextValue(getFloatValue(task.getAddress())); + break; + } + } catch (Exception e) { + log.warn("KOSTAL Protocol error. " + e.getClass().getSimpleName() + ": " + e.getMessage()); + } + } + } + + protected boolean getBooleanValue(int address) throws Exception { + byte[] bytes = sendAndReceive(address); + if (bytes[0] == 1) { + return true; + } + return false; + } + + protected int getIntegerFromUnsignedByte(int address) throws Exception { + byte[] bytes = sendAndReceive(address); + return (int) ByteBuffer.wrap(bytes).get() & (0xFF); + } + + protected float getFloatValue(int address) throws Exception { + byte[] bytes = sendAndReceive(address); + return ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getFloat(); + } + + protected int getIntegerValue(int address) throws Exception { + byte[] bytes = sendAndReceive(address); + ByteBuffer b = ByteBuffer.allocate(4).putInt(0).order(ByteOrder.LITTLE_ENDIAN); + b.rewind(); + b.put(bytes); + b.rewind(); + return b.getInt(); + } + + protected String getStringValue(int address) throws Exception { + String stringValue = ""; + byte[] byi = sendAndReceive(address); + for (byte b : byi) { + if (b == 0) { + break; + } + stringValue += (char) b; + } + return stringValue.trim(); + } + + private byte[] addressWithByteBuffer(int address) { + ByteBuffer byteBuffer = ByteBuffer.allocate(4); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + byteBuffer.put((byte) ((address) & (0xff))); + byteBuffer.put((byte) (((address) >> 8) & (0xff))); + byteBuffer.put((byte) (((address) >> 16) & (0xff))); + byteBuffer.put((byte) (((address) >> 24) & (0xff))); + byte[] result = byteBuffer.array(); + return result; + } + + private byte[] sendAndReceive(int address) throws Exception { + + byte[] results = null; + /* + * convert address to byte array + */ + byte[] result = addressWithByteBuffer(address); + + /* + * Calculate Checksum + */ + byte checksum = calculateChecksumFromAddress(result); + /* + * Build Request + */ + byte[] request = new byte[] { 0x62, (byte) this.socketConnection.getUnitID(), 0x03, + (byte) this.socketConnection.getUnitID(), 0x00, (byte) 0xf0, Array.getByte(result, 0), + Array.getByte(result, 1), Array.getByte(result, 2), Array.getByte(result, 3), checksum, 0x00 }; + /* + * Send + */ + this.socketConnection.getOut().write(request); + this.socketConnection.getOut().flush(); + Thread.sleep(100); + /* + * Receive + */ + List datasList = new ArrayList<>(); + while (this.socketConnection.getIn().available() > 0) { + byte data = (byte) this.socketConnection.getIn().read(); + datasList.add(data); + } + if (datasList.isEmpty()) { + throw new Exception("Could not receive any data"); + } + byte[] datas = new byte[datasList.size()]; + for (int i = 0; i < datasList.size(); i++) { + datas[i] = datasList.get(i); + } + /* + * Verify Checksum of Reply + */ + boolean isChecksumOk = verifyChecksumOfReply(datas); + if (!isChecksumOk) { + throw new Exception("Checksum cannot be verified"); + } + /* + * Extract value + */ + results = new byte[datas.length - 7]; + + for (int i = 5; i < datas.length - 2; i++) { + results[i - 5] = datas[i]; + } + /* + * Return value + */ + return results; + } + + private byte calculateChecksumFromAddress(byte[] result) { + byte checksum = 0x00; + byte[] request = new byte[] { 0x62, (byte) this.socketConnection.getUnitID(), 0x03, + (byte) this.socketConnection.getUnitID(), Array.getByte(result, 0), 0x00, (byte) 0xf0, + Array.getByte(result, 1), Array.getByte(result, 2), Array.getByte(result, 3) }; + for (int i = 0; i < request.length; i++) { + checksum -= request[i]; + } + return checksum; + } + + private boolean verifyChecksumOfReply(byte[] data) { + byte checksum = 0x00; + for (int i = 0; i < data.length; i++) { + checksum += data[i]; + } + return checksum == 0x00; + } +} diff --git a/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/ReadTask.java b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/ReadTask.java new file mode 100644 index 00000000000..eefd36fd3fe --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/ReadTask.java @@ -0,0 +1,32 @@ +package io.openems.edge.ess.kostal.piko; + +import io.openems.edge.common.channel.doc.ChannelId; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.common.taskmanager.Task; + +public class ReadTask extends Task { + + private final ChannelId channelId; + private final FieldType fieldType; + private final int address; + + public ReadTask(ChannelId channelId, Priority priority, FieldType fieldType, int address) { + super(priority); + this.channelId = channelId; + this.address = address; + this.fieldType = fieldType; + } + + public ChannelId getChannelId() { + return channelId; + } + + public FieldType getFieldType() { + return fieldType; + } + + public int getAddress() { + return address; + } + +} diff --git a/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/SocketConnection.java b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/SocketConnection.java new file mode 100644 index 00000000000..8e4e5ed6a1a --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/SocketConnection.java @@ -0,0 +1,74 @@ +package io.openems.edge.ess.kostal.piko; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SocketConnection { + + private final Logger log = LoggerFactory.getLogger(SocketConnection.class); + + private final String host; + private final int port; + private final byte unitID; + + private Socket socket = null; + private OutputStream out = null; + private InputStream in = null; + + public SocketConnection(String host, int port, byte unitID) { + this.host = host; + this.port = port; + this.unitID = unitID; + } + + public byte getUnitID() { + return unitID; + } + + public void open() throws IOException { + if (this.socket != null && this.socket.isConnected()) { + return; + } + Socket socket = new Socket(this.host, this.port); + this.out = socket.getOutputStream(); + this.in = socket.getInputStream(); + this.socket = socket; + } + + public void close() { + if (in != null) { + try { + this.in.close(); + } catch (IOException e) { + this.log.error("In Stream Closed: " + e.getMessage()); + } + } + if (out != null) { + try { + this.out.close(); + } catch (IOException e) { + this.log.error("Out Stream Closed" + e.getMessage()); + } + } + if (this.socket != null) { + try { + this.socket.close(); + } catch (IOException e) { + this.log.error("Socket Closed" + e.getMessage()); + } + } + } + + public OutputStream getOut() { + return out; + } + + public InputStream getIn() { + return in; + } +} diff --git a/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Utils.java b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Utils.java new file mode 100644 index 00000000000..0d50a2fdb95 --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Utils.java @@ -0,0 +1,176 @@ +package io.openems.edge.ess.kostal.piko; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.AbstractReadChannel; +import io.openems.edge.common.channel.BooleanReadChannel; +import io.openems.edge.common.channel.FloatReadChannel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.channel.StringReadChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.api.AsymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.dccharger.api.EssDcCharger; + +public class Utils { + public static Stream> initializeChannels(EssKostalPiko c) { + return Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(c, channelId); + } + return null; + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case ACTIVE_POWER: + case REACTIVE_POWER: + case ACTIVE_DISCHARGE_ENERGY: + case ACTIVE_CHARGE_ENERGY: + return new IntegerReadChannel(c, channelId); + case MAX_ACTIVE_POWER: + return new IntegerReadChannel(c, channelId, EssKostalPiko.MAX_APPARENT_POWER); + case GRID_MODE: + return new IntegerReadChannel(c, channelId, SymmetricEss.GridMode.UNDEFINED.ordinal()); + } + return null; + }), Arrays.stream(AsymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case ACTIVE_POWER_L1: + case ACTIVE_POWER_L2: + case ACTIVE_POWER_L3: + case REACTIVE_POWER_L1: + case REACTIVE_POWER_L2: + case REACTIVE_POWER_L3: + return new IntegerReadChannel(c, channelId); + } + return null; + }), Arrays.stream(EssDcCharger.ChannelId.values()).map(channelId -> { + switch (channelId) { + case MAX_ACTUAL_POWER: + return new IntegerReadChannel(c, channelId, EssKostalPiko.MAX_ACTUAL_POWER); + case ACTUAL_POWER: + case ACTUAL_ENERGY: + return new IntegerReadChannel(c, channelId); + } + return null; + }), Arrays.stream(EssKostalPiko.ChannelId.values()).map(channelId -> { + switch (channelId) { + case INVERTER_NAME: + case ARTICLE_NUMBER: + case INVERTER_SERIAL_NUMBER: + case FIRMWARE_VERSION: + case HARDWARE_VERSION: + case KOMBOARD_VERSION: + case PARAMETER_VERSION: + case COUNTRY_NAME: + case INVERTER_OPERATING_STATUS: + case INVERTER_TYPE_NAME: + return new StringReadChannel(c, channelId); + + case NUMBER_OF_STRING: + case NUMBER_OF_PHASES: + case POWER_ID: + case PRESENT_ERROR_EVENT_CODE_1: + case PRESENT_ERROR_EVENT_CODE_2: + case FEED_IN_TIME: + case INVERTER_STATUS: + case ADDRESS_MODBUS_RTU: + case BAUDRATE_INDEX_MODBUS_RTU: + case SETTING_MANUAL_IP1: + case SETTING_MANUAL_IP2: + case SETTING_MANUAL_IP3: + case SETTING_MANUAL_IP4: + case SETTING_MANUAL_SUBNET_MASK_1: + case SETTING_MANUAL_SUBNET_MASK_2: + case SETTING_MANUAL_SUBNET_MASK_3: + case SETTING_MANUAL_SUBNET_MASK_4: + case SETTING_MANUAL_GATEWAY_1: + case SETTING_MANUAL_GATEWAY_2: + case SETTING_MANUAL_GATEWAY_3: + case SETTING_MANUAL_GATEWAY_4: + case SETTING_MANUAL_IP_DNS_FIRST_1: + case SETTING_MANUAL_IP_DNS_FIRST_2: + case SETTING_MANUAL_IP_DNS_FIRST_3: + case SETTING_MANUAL_IP_DNS_FIRST_4: + case SETTING_MANUAL_IP_DNS_SECOND_1: + case SETTING_MANUAL_IP_DNS_SECOND_2: + case SETTING_MANUAL_IP_DNS_SECOND_3: + case SETTING_MANUAL_IP_DNS_SECOND_4: + return new IntegerReadChannel(c, channelId); + + case FEED_IN_STATUS: + case SETTING_AUTO_IP: + case SETTING_MANUAL_EXTERNAL_ROUTER: + case PRELOAD_MODBUS_RTU: + case TERMINATION_MODBUS_RTU: + return new BooleanReadChannel(c, channelId); + + case OVERALL_DC_CURRENT: + case OVERALL_DC_POWER: + case DC_CURRENT_STRING_1: + case DC_VOLTAGE_STRING_1: + case DC_POWER_STRING_1: + case DC_CURRENT_STRING_2: + case DC_VOLTAGE_STRING_2: + case DC_POWER_STRING_2: + case DC_CURRENT_STRING_3: + case DC_VOLTAGE_STRING_3: + case DC_POWER_STRING_3: + case BATTERY_CURRENT: + case BATTERY_VOLTAGE: + case BATTERY_TEMPERATURE: + case BATTERY_CURRENT_DIRECTION: + case AC_TOTAL_POWER: + case AC_CURRENT_L1: + case AC_VOLTAGE_L1: + case AC_POWER_L1: + case AC_CURRENT_L2: + case AC_VOLTAGE_L2: + case AC_POWER_L2: + case AC_CURRENT_L3: + case AC_VOLTAGE_L3: + case AC_POWER_L3: + case POWER_LIMITATION_OF_EVU: + case GRID_FREQUENCY: + case COSINUS_PHI: + case HOME_CONSUMPTION_PV: + case HOME_CONSUMPTION_BATTERY: + case HOME_CONSUMPTION_GRID: + case HOME_CURRENT_L1: + case HOME_POWER_L1: + case HOME_CONSUMPTION_L1: + case HOME_CURRENT_L2: + case HOME_POWER_L2: + case HOME_CONSUMPTION_L2: + case HOME_CURRENT_L3: + case HOME_POWER_L3: + case HOME_CONSUMPTION_L3: + case HOME_TOTAL_POWER: + case HOME_SELF_CONSUMPTION_TOTAL: + case ISOLATION_RESISTOR: + case MAX_RESIDUAL_CURRENT: + case ANALOG_INPUT_CH_1: + case ANALOG_INPUT_CH_2: + case ANALOG_INPUT_CH_3: + case ANALOG_INPUT_CH_4: + case YIELD_TOTAL: + case YIELD_DAY: + case HOME_CONSUMPTION_TOTAL: + case HOME_CONSUMPTION_DAY: + case SELF_CONSUMPTION_TOTAL: + case SELF_CONSUMPTION_DAY: + case SELF_CONSUMPTION_RATE_TOTAL: + case SELF_CONSUMPTION_RATE_DAY: + case DEGREE_OF_SELF_SUFFICIENCY_DAY: + case DEGREE_OF_SELF_SUFFICIENCY_TOTAL: + return new FloatReadChannel(c, channelId); + } + return null; + }) // + ).flatMap(channel -> channel); + } +} diff --git a/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Worker.java b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Worker.java new file mode 100644 index 00000000000..4aa2ab173fb --- /dev/null +++ b/io.openems.edge.ess.kostal.piko/src/io/openems/edge/ess/kostal/piko/Worker.java @@ -0,0 +1,23 @@ +package io.openems.edge.ess.kostal.piko; + +import java.util.List; + +import io.openems.edge.common.taskmanager.TasksManager; +import io.openems.edge.common.worker.AbstractCycleWorker; + +public class Worker extends AbstractCycleWorker { + + private final Protocol protocol; + private final TasksManager readTasksManager; + + public Worker(Protocol protocol, TasksManager readTasksManager) { + this.protocol = protocol; + this.readTasksManager = readTasksManager; + } + + @Override + protected void forever() { + List nextReadTasks = this.readTasksManager.getNextReadTasks(); + this.protocol.execute(nextReadTasks); + } +} diff --git a/io.openems.edge.ess.kostal.piko/test/.gitignore b/io.openems.edge.ess.kostal.piko/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.ess.streetscooter/.classpath b/io.openems.edge.ess.streetscooter/.classpath new file mode 100644 index 00000000000..fa4712b046a --- /dev/null +++ b/io.openems.edge.ess.streetscooter/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.ess.streetscooter/.gitignore b/io.openems.edge.ess.streetscooter/.gitignore new file mode 100644 index 00000000000..36573722b7e --- /dev/null +++ b/io.openems.edge.ess.streetscooter/.gitignore @@ -0,0 +1,2 @@ +/generated/ +/bin_test/ diff --git a/io.openems.edge.ess.streetscooter/bnd.bnd b/io.openems.edge.ess.streetscooter/bnd.bnd new file mode 100644 index 00000000000..513c3f8961d --- /dev/null +++ b/io.openems.edge.ess.streetscooter/bnd.bnd @@ -0,0 +1,25 @@ +Bundle-Name: OpenEMS Edge ESS Streetscooter +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.ess.symmetric.readonly.api,\ + io.openems.edge.ess.api,\ + io.openems.edge.ess.symmetric.api,\ + io.openems.edge.ess.power.symmetric,\ + io.openems.edge.ess.power + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.ess.api;version=latest,\ + io.openems.edge.common;version=latest,\ + io.openems.common;version=latest,\ + io.openems.edge.bridge.modbus;version=latest + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 +-runbundles: org.apache.felix.log;version='[1.0.1,1.0.2)' +Private-Package: io.openems.edge.ess.streetscooter \ No newline at end of file diff --git a/io.openems.edge.ess.streetscooter/readme.md b/io.openems.edge.ess.streetscooter/readme.md new file mode 100644 index 00000000000..271f41263f5 --- /dev/null +++ b/io.openems.edge.ess.streetscooter/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.ess.streetscooter Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/AbstractEssStreetscooter.java b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/AbstractEssStreetscooter.java new file mode 100644 index 00000000000..b8401a33d98 --- /dev/null +++ b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/AbstractEssStreetscooter.java @@ -0,0 +1,354 @@ +package io.openems.edge.ess.streetscooter; + +import org.apache.commons.math3.optim.linear.Relationship; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; +import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.api.element.CoilElement; +import io.openems.edge.bridge.modbus.api.element.FloatDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.WordOrder; +import io.openems.edge.bridge.modbus.api.task.FC16WriteRegistersTask; +import io.openems.edge.bridge.modbus.api.task.FC1ReadCoilsTask; +import io.openems.edge.bridge.modbus.api.task.FC2ReadInputsTask; +import io.openems.edge.bridge.modbus.api.task.FC4ReadInputRegistersTask; +import io.openems.edge.bridge.modbus.api.task.FC5WriteCoilTask; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.common.type.TypeUtils; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.CircleConstraint; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Pwr; + +public abstract class AbstractEssStreetscooter extends AbstractOpenemsModbusComponent + implements ManagedSymmetricEss, SymmetricEss, OpenemsComponent { + + protected static final int UNIT_ID = 100; + + static final int MAX_APPARENT_POWER = 2000; + private static final int POWER_PRECISION = 100; + + public static final int INVERTER_MODE_UNDEFINED = -1; + public static final int INVERTER_MODE_INITIAL = 0; + public static final int INVERTER_MODE_WAIT = 1; + public static final int INVERTER_MODE_START_UP = 2; + public static final int INVERTER_MODE_NORMAL = 3; + public static final int INVERTER_MODE_OFF_GRID = 4; + public static final int INVERTER_MODE_FAULT = 5; + public static final int INVERTER_MODE_PERMANENT_FAULT = 6; + public static final int INVERTER_MODE_UPDATE_MASTER = 7; + public static final int INVERTER_MODE_UPDATE_SLAVE = 8; + + private static final int ICU_RUN_ADDRESS = 4002; + private static final int BATTERY_INFO_START_ADDRESS = 0; + private static final int INVERTER_INFO_START_ADDRESS = 2000; + + private final Logger log = LoggerFactory.getLogger(AbstractOpenemsModbusComponent.class); + + private final PowerHandler powerHandler; + + public AbstractEssStreetscooter() { + Utils.initializeChannels(this).forEach(channel -> this.addChannel((Channel) channel)); + this.powerHandler = new PowerHandler(this, this.log); + } + + protected void activate(ComponentContext context, String servicePid, String id, boolean enabled, int unitId, + ConfigurationAdmin cm, String modbusReference, String modbusId) { + /* + * Initialize Power + */ + // max Apparent + new CircleConstraint(this, MAX_APPARENT_POWER); + // Allowed Charge + Constraint allowedChargeConstraint = this.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, + Relationship.GEQ, 0); + this.channel(ChannelId.BATTERY_BMS_PWR_CHRG_MAX).onChange(value -> { + allowedChargeConstraint.setIntValue(TypeUtils.getAsType(OpenemsType.INTEGER, value)); + }); + // Allowed Discharge + Constraint allowedDischargeConstraint = this.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, + Relationship.LEQ, 0); + this.channel(ChannelId.BATTERY_BMS_PWR_D_CHA_MAX).onChange(value -> { + allowedDischargeConstraint.setIntValue(TypeUtils.getAsType(OpenemsType.INTEGER, value)); + }); + super.activate(id); + } + + @Override + public String debugLog() { + return "SoC:" + this.getSoc().value().asString() + ", mode:" + + this.channel(ChannelId.INVERTER_MODE).value().asOptionString(); + + } + + @Override + protected ModbusProtocol defineModbusProtocol(int unitId) { + int batteryInfoStartAddress = getBatteryInfoStartAddress() + getAdressOffsetForBattery(); + int inverterInfoStartAddress = getInverterInfoStartAddress() + getAdressOffsetForInverter(); + + return new ModbusProtocol(unitId, // + new FC1ReadCoilsTask(getIcuRunAddress(), Priority.HIGH, + m(ChannelId.ICU_RUN, new CoilElement(getIcuRunAddress()))), + new FC5WriteCoilTask(getIcuRunAddress(), m(ChannelId.ICU_RUN, new CoilElement(getIcuRunAddress()))), + new FC1ReadCoilsTask(getIcuEnabledAddress(), Priority.HIGH, + m(ChannelId.ICU_ENABLED, new CoilElement(getIcuEnabledAddress()))), + new FC5WriteCoilTask(getIcuEnabledAddress(), + m(ChannelId.ICU_ENABLED, new CoilElement(getIcuEnabledAddress()))), + new FC4ReadInputRegistersTask(getInverterModeAddress(), Priority.HIGH, + m(ChannelId.INVERTER_MODE, + new FloatDoublewordElement(getInverterModeAddress()).wordOrder(WordOrder.LSWMSW))), + new FC16WriteRegistersTask(getIcuSetPowerAddress(), + m(ChannelId.INVERTER_SET_ACTIVE_POWER, + new FloatDoublewordElement(getIcuSetPowerAddress()).wordOrder(WordOrder.LSWMSW))), + new FC4ReadInputRegistersTask(batteryInfoStartAddress, Priority.HIGH, + m(ChannelId.BATTERY_BMS_ERR, + new FloatDoublewordElement(batteryInfoStartAddress).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_I_ACT, + new FloatDoublewordElement(batteryInfoStartAddress + 2).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_PWR_CHRG_MAX, + new FloatDoublewordElement(batteryInfoStartAddress + 4).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_PWR_D_CHA_MAX, + new FloatDoublewordElement(batteryInfoStartAddress + 6).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_PWR_RGN_MAX, + new FloatDoublewordElement(batteryInfoStartAddress + 8).wordOrder(WordOrder.LSWMSW)), + m(SymmetricEss.ChannelId.SOC, + new FloatDoublewordElement(batteryInfoStartAddress + 10).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_SOH, + new FloatDoublewordElement(batteryInfoStartAddress + 12).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_ST_BAT, + new FloatDoublewordElement(batteryInfoStartAddress + 14).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_T_MAX_PACK, + new FloatDoublewordElement(batteryInfoStartAddress + 16).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_T_MIN_PACK, + new FloatDoublewordElement(batteryInfoStartAddress + 18).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_U_PACK, + new FloatDoublewordElement(batteryInfoStartAddress + 20).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.BATTERY_BMS_WRN, + new FloatDoublewordElement(batteryInfoStartAddress + 22).wordOrder(WordOrder.LSWMSW))), + new FC4ReadInputRegistersTask(inverterInfoStartAddress, Priority.HIGH, + m(ChannelId.INVERTER_ACTIVE_POWER, + new FloatDoublewordElement(inverterInfoStartAddress).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_DC1_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 2).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_DC2_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 4).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_ERROR_MESSAGE_1H, + new FloatDoublewordElement(inverterInfoStartAddress + 6).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_ERROR_MESSAGE_1L, + new FloatDoublewordElement(inverterInfoStartAddress + 8).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_ERROR_MESSAGE_2H, + new FloatDoublewordElement(inverterInfoStartAddress + 10).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_ERROR_MESSAGE_2L, + new FloatDoublewordElement(inverterInfoStartAddress + 12).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_F_AC_1, + new FloatDoublewordElement(inverterInfoStartAddress + 14).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_F_AC_2, + new FloatDoublewordElement(inverterInfoStartAddress + 16).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_F_AC_3, + new FloatDoublewordElement(inverterInfoStartAddress + 18).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_GF1_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 20).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_GF2_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 22).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_GF3_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 24).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_GFCI_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 26).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_GV1_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 28).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_GV2_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 30).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_GV3_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 32).wordOrder(WordOrder.LSWMSW)), + m(SymmetricEss.ChannelId.ACTIVE_POWER, + new FloatDoublewordElement(inverterInfoStartAddress + 34).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_P_AC_1, + new FloatDoublewordElement(inverterInfoStartAddress + 36).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_P_AC_2, + new FloatDoublewordElement(inverterInfoStartAddress + 38).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_P_AC_3, + new FloatDoublewordElement(inverterInfoStartAddress + 40).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_TEMPERATURE, + new FloatDoublewordElement(inverterInfoStartAddress + 42).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_TEMPERATURE_FAULT_VALUE, + new FloatDoublewordElement(inverterInfoStartAddress + 44).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_V_AC_1, + new FloatDoublewordElement(inverterInfoStartAddress + 46).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_V_AC_2, + new FloatDoublewordElement(inverterInfoStartAddress + 48).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_V_AC_3, + new FloatDoublewordElement(inverterInfoStartAddress + 50).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_V_DC_1, + new FloatDoublewordElement(inverterInfoStartAddress + 52).wordOrder(WordOrder.LSWMSW)), + m(ChannelId.INVERTER_V_DC_2, + new FloatDoublewordElement(inverterInfoStartAddress + 54).wordOrder(WordOrder.LSWMSW))), + new FC2ReadInputsTask(getIcuRunstateAddress(), Priority.HIGH, + m(ChannelId.ICU_RUNSTATE, new CoilElement(getIcuRunstateAddress()))), + new FC2ReadInputsTask(getInverterConnectedAddress(), Priority.HIGH, + m(ChannelId.INVERTER_CONNECTED, new CoilElement(getInverterConnectedAddress()))), + new FC2ReadInputsTask(getBatteryConnectedAddress(), Priority.HIGH, + m(ChannelId.BATTERY_CONNECTED, new CoilElement(getBatteryConnectedAddress()))), + new FC2ReadInputsTask(getBatteryOverloadAddress(), Priority.HIGH, + m(ChannelId.BATTERY_OVERLOAD, new CoilElement(getBatteryOverloadAddress())))); + } + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + ICU_RUN(new Doc().unit(Unit.ON_OFF)), // + ICU_ENABLED(new Doc().unit(Unit.ON_OFF)), // + ICU_RUNSTATE(new Doc().unit(Unit.ON_OFF)), // + + BATTERY_BMS_ERR(new Doc().unit(Unit.NONE)), // + BATTERY_BMS_I_ACT(new Doc().unit(Unit.AMPERE)), // + BATTERY_BMS_PWR_CHRG_MAX(new Doc().unit(Unit.WATT)), // + BATTERY_BMS_PWR_D_CHA_MAX(new Doc().unit(Unit.WATT)), // + BATTERY_BMS_PWR_RGN_MAX(new Doc().unit(Unit.WATT)), // + BATTERY_BMS_SOH(new Doc().unit(Unit.PERCENT)), // + BATTERY_BMS_ST_BAT(new Doc().unit(Unit.NONE)), // + BATTERY_BMS_T_MAX_PACK(new Doc().unit(Unit.DEGREE_CELSIUS)), // + BATTERY_BMS_T_MIN_PACK(new Doc().unit(Unit.DEGREE_CELSIUS)), // + BATTERY_BMS_U_PACK(new Doc().unit(Unit.VOLT)), // + BATTERY_BMS_WRN(new Doc().unit(Unit.NONE)), // + BATTERY_CONNECTED(new Doc().unit(Unit.ON_OFF)), // + BATTERY_OVERLOAD(new Doc().unit(Unit.ON_OFF)), // + + INVERTER_MODE(new Doc(). // + option(getInverterModeInitial(), "Initial"). // + option(getInverterModeWait(), "Wait"). // + option(getInverterModeStartUp(), "Start up"). // + option(getInverterModeNormal(), "Normal"). // + option(getInverterModeOffGrid(), "Off grid"). // + option(getInverterModeFault(), "Fault"). // + option(getInverterModePermanentFault(), "Permanent fault"). // + option(getInverterModeUpdateMaster(), "Program update of master controller"). // + option(getInverterModeUpdateSlave(), "Program update of slave controller")), // + INVERTER_SET_ACTIVE_POWER(new Doc().unit(Unit.WATT)), // + INVERTER_ACTIVE_POWER(new Doc().unit(Unit.WATT)), // + INVERTER_DC1_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_DC2_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_ERROR_MESSAGE_1H(new Doc().unit(Unit.NONE)), // + INVERTER_ERROR_MESSAGE_1L(new Doc().unit(Unit.NONE)), // + INVERTER_ERROR_MESSAGE_2H(new Doc().unit(Unit.NONE)), // + INVERTER_ERROR_MESSAGE_2L(new Doc().unit(Unit.NONE)), // + INVERTER_F_AC_1(new Doc().unit(Unit.NONE)), // + INVERTER_F_AC_2(new Doc().unit(Unit.NONE)), // + INVERTER_F_AC_3(new Doc().unit(Unit.NONE)), // + INVERTER_GF1_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_GF2_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_GF3_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_GFCI_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_GV1_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_GV2_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_GV3_FAULT_VALUE(new Doc().unit(Unit.NONE)), // + INVERTER_P_AC(new Doc().unit(Unit.WATT)), // + INVERTER_P_AC_1(new Doc().unit(Unit.WATT)), // + INVERTER_P_AC_2(new Doc().unit(Unit.WATT)), // + INVERTER_P_AC_3(new Doc().unit(Unit.WATT)), // + INVERTER_TEMPERATURE(new Doc().unit(Unit.DEGREE_CELSIUS)), + INVERTER_TEMPERATURE_FAULT_VALUE(new Doc().unit(Unit.DEGREE_CELSIUS)), // + INVERTER_V_AC_1(new Doc().unit(Unit.VOLT)), // + INVERTER_V_AC_2(new Doc().unit(Unit.VOLT)), // + INVERTER_V_AC_3(new Doc().unit(Unit.VOLT)), // + INVERTER_V_DC_1(new Doc().unit(Unit.VOLT)), // + INVERTER_V_DC_2(new Doc().unit(Unit.VOLT)), // + INVERTER_CONNECTED(new Doc().unit(Unit.ON_OFF)), + SYSTEM_STATE_INFORMATION(new Doc().setWritable().unit(Unit.NONE)); + + private final Doc doc; + + @Override + public Doc doc() { + return this.doc; + } + + private ChannelId(Doc doc) { + this.doc = doc; + } + } + + private static int getInverterModeUpdateSlave() { + return INVERTER_MODE_UPDATE_SLAVE; + } + + private static int getInverterModeUpdateMaster() { + return INVERTER_MODE_UPDATE_MASTER; + } + + private static int getInverterModePermanentFault() { + return INVERTER_MODE_PERMANENT_FAULT; + } + + private static int getInverterModeFault() { + return INVERTER_MODE_FAULT; + } + + private static int getInverterModeOffGrid() { + return INVERTER_MODE_OFF_GRID; + } + + private static int getInverterModeNormal() { + return INVERTER_MODE_NORMAL; + } + + private static int getInverterModeStartUp() { + return INVERTER_MODE_START_UP; + } + + private static int getInverterModeWait() { + return INVERTER_MODE_WAIT; + } + + private static int getInverterModeInitial() { + return INVERTER_MODE_INITIAL; + } + + private int getBatteryInfoStartAddress() { + return BATTERY_INFO_START_ADDRESS; + } + + protected abstract int getAdressOffsetForBattery(); + + private int getInverterInfoStartAddress() { + return INVERTER_INFO_START_ADDRESS; + } + + protected abstract int getAdressOffsetForInverter(); + + protected int getIcuRunAddress() { + return ICU_RUN_ADDRESS; + } + + protected abstract int getIcuEnabledAddress(); + + protected abstract int getIcuSetPowerAddress(); + + protected abstract int getBatteryOverloadAddress(); + + protected abstract int getBatteryConnectedAddress(); + + protected abstract int getInverterConnectedAddress(); + + protected abstract int getIcuRunstateAddress(); + + protected abstract int getInverterModeAddress(); + + @Override + public void applyPower(int activePower, int reactivePower) { + this.powerHandler.accept(activePower, reactivePower); + } + + @Override + public int getPowerPrecision() { + return AbstractEssStreetscooter.POWER_PRECISION; + } +} diff --git a/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Config0.java b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Config0.java new file mode 100644 index 00000000000..92921440ce3 --- /dev/null +++ b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Config0.java @@ -0,0 +1,23 @@ +package io.openems.edge.ess.streetscooter; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition( // + name = "ESS Ess0Streetscooter", // + description = "Implements the streetscooter energy storage system.") +@interface Config0 { + String service_pid(); + + String id() default "ess0"; + + boolean enabled() default true; + + @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.") + String modbus_id(); + + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default ""; + + String webconsole_configurationFactory_nameHint() default "ESS Ess0Streetscooter [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Config1.java b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Config1.java new file mode 100644 index 00000000000..8a06147c3e3 --- /dev/null +++ b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Config1.java @@ -0,0 +1,23 @@ +package io.openems.edge.ess.streetscooter; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition( // + name = "ESS Ess1Streetscooter", // + description = "Implements the streetscooter energy storage system.") +@interface Config1 { + String service_pid(); + + String id() default "ess1"; + + boolean enabled() default true; + + @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.") + String modbus_id(); + + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default ""; + + String webconsole_configurationFactory_nameHint() default "ESS Ess1Streetscooter [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Ess0Streetscooter.java b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Ess0Streetscooter.java new file mode 100644 index 00000000000..5e985b913b7 --- /dev/null +++ b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Ess0Streetscooter.java @@ -0,0 +1,108 @@ +package io.openems.edge.ess.streetscooter; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.EventConstants; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.Power; + +@Designate(ocd = Config0.class, factory = true) +@Component(name = "Ess0.Streetscooter", immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE, property = EventConstants.EVENT_TOPIC + + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_CONTROLLERS) +public class Ess0Streetscooter extends AbstractEssStreetscooter implements ManagedSymmetricEss, SymmetricEss, OpenemsComponent { + + private static final int INVERTER_0_MODE_ADDRESS = 2056; + private static final int ICU_0_SET_POWER_ADDRESS = 4000; + private static final int ICU_0_ENABLED_ADDRESS = 4000; + private static final int BATTERY_0_ADDRESS_OFFSET = 0; + private static final int INVERTER_0_ADDRESS_OFFSET = 0; + + private static final int BATTERY_0_OVERLOAD_ADDRESS = 0001; + private static final int BATTERY_0_CONNECTED_ADDRESS = 0000; + private static final int INVERTER_0_CONNECTED_ADDRESS = 2000; + private static final int ICU_0_RUNSTATE_ADDRESS = 4000; + + @Reference + private Power power; + + @Reference + private ConfigurationAdmin cm; + + public Ess0Streetscooter() { + super(); + } + + @Activate + protected void activate(ComponentContext context, Config0 config0) { + super.activate(context, config0.service_pid(), config0.id(), config0.enabled(), UNIT_ID, this.cm, "Modbus", + config0.modbus_id()); + } + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + @Override + protected int getIcuSetPowerAddress() { + return ICU_0_SET_POWER_ADDRESS; + } + + @Override + protected int getInverterModeAddress() { + return INVERTER_0_MODE_ADDRESS; + } + + @Override + protected int getIcuEnabledAddress() { + return ICU_0_ENABLED_ADDRESS; + } + + @Override + protected int getAdressOffsetForBattery() { + return BATTERY_0_ADDRESS_OFFSET; + } + + @Override + protected int getAdressOffsetForInverter() { + return INVERTER_0_ADDRESS_OFFSET; + } + + @Override + protected int getBatteryOverloadAddress() { + return BATTERY_0_OVERLOAD_ADDRESS; + } + + @Override + protected int getBatteryConnectedAddress() { + return BATTERY_0_CONNECTED_ADDRESS; + } + + @Override + protected int getInverterConnectedAddress() { + return INVERTER_0_CONNECTED_ADDRESS; + } + + @Override + protected int getIcuRunstateAddress() { + return ICU_0_RUNSTATE_ADDRESS; + } + + @Override + public Power getPower() { + return this.power; + } +} diff --git a/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Ess1Streetscooter.java b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Ess1Streetscooter.java new file mode 100644 index 00000000000..2b98c03f5fe --- /dev/null +++ b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Ess1Streetscooter.java @@ -0,0 +1,110 @@ +package io.openems.edge.ess.streetscooter; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.event.EventConstants; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.Power; + +@Designate(ocd = Config1.class, factory = true) +@Component(name = "Ess1.Streetscooter", immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE, property = EventConstants.EVENT_TOPIC + + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_CONTROLLERS) +public class Ess1Streetscooter extends AbstractEssStreetscooter + implements ManagedSymmetricEss, SymmetricEss, OpenemsComponent { + + private static final int INVERTER_1_MODE_ADDRESS = 3056; + private static final int ICU1_SET_POWER_ADRESS = 4002; + private static final int ICU_1_ENABLED_ADDRESS = 4001; + + private static final int BATTERY_1_ADDRESS_OFFSET = 1000; + private static final int INVERTER_1_ADDRESS_OFFSET = 1000; + + private static final int BATTERY_1_OVERLOAD_ADDRESS = 1001; + private static final int BATTERY_1_CONNECTED_ADDRESS = 1000; + private static final int INVERTER_1_CONNECTED_ADDRESS = 13000; + private static final int ICU_1_RUNSTATE_ADDRESS = 14001; + + @Reference + private Power power; + + @Reference + private ConfigurationAdmin cm; + + public Ess1Streetscooter() { + super(); + } + + @Activate + protected void activate(ComponentContext context, Config1 config1) { + super.activate(context, config1.service_pid(), config1.id(), config1.enabled(), UNIT_ID, this.cm, "Modbus", + config1.modbus_id()); + } + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + @Override + protected int getIcuSetPowerAddress() { + return ICU1_SET_POWER_ADRESS; + } + + @Override + protected int getInverterModeAddress() { + return INVERTER_1_MODE_ADDRESS; + } + + @Override + protected int getIcuEnabledAddress() { + return ICU_1_ENABLED_ADDRESS; + } + + @Override + protected int getAdressOffsetForBattery() { + return BATTERY_1_ADDRESS_OFFSET; + } + + @Override + protected int getAdressOffsetForInverter() { + return INVERTER_1_ADDRESS_OFFSET; + } + + @Override + protected int getBatteryOverloadAddress() { + return BATTERY_1_OVERLOAD_ADDRESS; + } + + @Override + protected int getBatteryConnectedAddress() { + return BATTERY_1_CONNECTED_ADDRESS; + } + + @Override + protected int getInverterConnectedAddress() { + return INVERTER_1_CONNECTED_ADDRESS; + } + + @Override + protected int getIcuRunstateAddress() { + return ICU_1_RUNSTATE_ADDRESS; + } + + @Override + public Power getPower() { + return this.power; + } +} diff --git a/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/PowerHandler.java b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/PowerHandler.java new file mode 100644 index 00000000000..7e0c864eafb --- /dev/null +++ b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/PowerHandler.java @@ -0,0 +1,140 @@ +package io.openems.edge.ess.streetscooter; + +import java.time.LocalDateTime; +import java.util.function.BiConsumer; + +import org.slf4j.Logger; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.edge.common.channel.BooleanReadChannel; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.IntegerWriteChannel; +import io.openems.edge.common.channel.StringWriteChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.streetscooter.AbstractEssStreetscooter.ChannelId; + +public class PowerHandler implements BiConsumer { + + private static final int MINUTES_TO_WAIT_FOR_2ND_TRY = 30; + private OpenemsComponent parent; + private Logger log; + private LocalDateTime lastRestartAfterFault; + private int attempsToRestart; + + public PowerHandler(OpenemsComponent parent, Logger log) { + this.parent = parent; + this.log = log; + } + + @Override + public void accept(Integer activePower, Integer reactivePower) { + + checkForResettingFault(); + + if (isInverterInFaultMode()) { + doErrorHandling(); + } + + if (isErrorHandling()) { + return; + } + + // System is in normal mode + if (!isRunning()) { + setRunning(); + } + if (isRunning() && !isEnabled()) { + setEnabled(); + } + if (isRunning() && isEnabled() && isInverterInNormalMode()) { + writeActivePower(activePower); + } + } + + private boolean isErrorHandling() { + return lastRestartAfterFault != null; + } + + private void checkForResettingFault() { + if (isInverterInNormalMode() && isWaitingPeriodAfterFaultRestartPassed()) { + lastRestartAfterFault = null; + attempsToRestart = 0; + } + } + + private void doErrorHandling() { + if (lastRestartAfterFault == null && attempsToRestart == 0) { + lastRestartAfterFault = LocalDateTime.now(); + attempsToRestart = 1; + setRunning(); + setEnabled(); + log.info("Try to restart the system for the first time after detecting fault"); + } else { + if (isWaitingPeriodAfterFaultRestartPassed() && attempsToRestart == 1) { + attempsToRestart++; + setRunning(); + setEnabled(); + log.info("Try to restart the system for the second time after detecting fault"); + } else if (isWaitingPeriodAfterFaultRestartPassed() && attempsToRestart > 1) { + // Do nothing, let system in fault mode + StringWriteChannel errorChannel = parent.channel(ChannelId.SYSTEM_STATE_INFORMATION); + errorChannel.setNextValue("System could not be started after waiting period and two start attempts"); + } + } + } + + private void writeActivePower(Integer activePower) { + try { + IntegerWriteChannel setActivePowerChannel = parent.channel(ChannelId.INVERTER_SET_ACTIVE_POWER); + setActivePowerChannel.setNextWriteValue(activePower); + } catch (OpenemsException e) { + log.error("Unable to set ActivePower: " + e.getMessage()); + } + } + + private boolean isInverterInNormalMode() { + IntegerReadChannel inverterModeChannel = parent.channel(ChannelId.INVERTER_MODE); + return inverterModeChannel.value().orElse(AbstractEssStreetscooter.INVERTER_MODE_UNDEFINED).equals(AbstractEssStreetscooter.INVERTER_MODE_NORMAL); + } + + private boolean isInverterInFaultMode() { + IntegerReadChannel inverterModeChannel = parent.channel(ChannelId.INVERTER_MODE); + return inverterModeChannel.value().orElse(AbstractEssStreetscooter.INVERTER_MODE_UNDEFINED).equals(AbstractEssStreetscooter.INVERTER_MODE_FAULT); + } + + private void setEnabled() { + try { + BooleanWriteChannel channel = parent.channel(ChannelId.ICU_ENABLED); + channel.setNextWriteValue(true); + } catch (Exception e) { + log.error("Unable to set icu enabled: " + e.getMessage()); + } + } + + private void setRunning() { + try { + BooleanWriteChannel channel = parent.channel(ChannelId.ICU_RUN); + channel.setNextWriteValue(true); + } catch (Exception e) { + log.error("Unable to set icu run: " + e.getMessage()); + } + } + + private boolean isEnabled() { + BooleanReadChannel icuEnabled = parent.channel(ChannelId.ICU_ENABLED); + boolean value = icuEnabled.value().orElse(false); + return value; + } + + private boolean isRunning() { + BooleanReadChannel icuRunChannel = parent.channel(ChannelId.ICU_RUN); + boolean value = icuRunChannel.value().orElse(false); + return value; + } + + private boolean isWaitingPeriodAfterFaultRestartPassed() { + return lastRestartAfterFault != null + && lastRestartAfterFault.plusMinutes(MINUTES_TO_WAIT_FOR_2ND_TRY).isAfter(LocalDateTime.now()); + } +} diff --git a/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Utils.java b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Utils.java new file mode 100644 index 00000000000..721d7ef95c7 --- /dev/null +++ b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/Utils.java @@ -0,0 +1,107 @@ +package io.openems.edge.ess.streetscooter; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.BooleanReadChannel; +import io.openems.edge.common.channel.BooleanWriteChannel; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.IntegerWriteChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.channel.StringWriteChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; + +public class Utils { + static Stream> initializeChannels(AbstractEssStreetscooter c) { + return Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(c, channelId); + } + return null; + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case ACTIVE_POWER: + case REACTIVE_POWER: + case ACTIVE_CHARGE_ENERGY: // TODO ACTIVE_CHARGE_ENERGY + case ACTIVE_DISCHARGE_ENERGY: // TODO ACTIVE_DISCHARGE_ENERGY + return new IntegerReadChannel(c, channelId); + case MAX_ACTIVE_POWER: + return new IntegerReadChannel(c, channelId, AbstractEssStreetscooter.MAX_APPARENT_POWER); + case GRID_MODE: + return new IntegerReadChannel(c, channelId, SymmetricEss.GridMode.UNDEFINED.ordinal()); + } + return null; + }), Arrays.stream(ManagedSymmetricEss.ChannelId.values()).map(channelId -> { + switch (channelId) { + case DEBUG_SET_ACTIVE_POWER: + case DEBUG_SET_REACTIVE_POWER: + return new IntegerReadChannel(c, channelId); + } + return null; + }), Arrays.stream(AbstractEssStreetscooter.ChannelId.values()).map(channelId -> { + switch (channelId) { + case INVERTER_MODE: + case BATTERY_BMS_I_ACT: + case BATTERY_BMS_ERR: + case BATTERY_BMS_PWR_CHRG_MAX: + case BATTERY_BMS_PWR_D_CHA_MAX: + case BATTERY_BMS_PWR_RGN_MAX: + case BATTERY_BMS_SOH: + case BATTERY_BMS_ST_BAT: + case BATTERY_BMS_T_MAX_PACK: + case BATTERY_BMS_T_MIN_PACK: + case BATTERY_BMS_U_PACK: + case BATTERY_BMS_WRN: + case INVERTER_ACTIVE_POWER: + case INVERTER_DC1_FAULT_VALUE: + case INVERTER_DC2_FAULT_VALUE: + case INVERTER_ERROR_MESSAGE_1H: + case INVERTER_ERROR_MESSAGE_1L: + case INVERTER_ERROR_MESSAGE_2H: + case INVERTER_ERROR_MESSAGE_2L: + case INVERTER_F_AC_1: + case INVERTER_F_AC_2: + case INVERTER_F_AC_3: + case INVERTER_GF1_FAULT_VALUE: + case INVERTER_GF2_FAULT_VALUE: + case INVERTER_GF3_FAULT_VALUE: + case INVERTER_GFCI_FAULT_VALUE: + case INVERTER_GV1_FAULT_VALUE: + case INVERTER_GV2_FAULT_VALUE: + case INVERTER_GV3_FAULT_VALUE: + case INVERTER_P_AC: + case INVERTER_P_AC_1: + case INVERTER_P_AC_2: + case INVERTER_P_AC_3: + case INVERTER_TEMPERATURE: + case INVERTER_TEMPERATURE_FAULT_VALUE: + case INVERTER_V_AC_1: + case INVERTER_V_AC_2: + case INVERTER_V_AC_3: + case INVERTER_V_DC_1: + case INVERTER_V_DC_2: + return new IntegerReadChannel(c, channelId); + case INVERTER_SET_ACTIVE_POWER: + return new IntegerWriteChannel(c, channelId); + case ICU_RUN: + case ICU_ENABLED: + return new BooleanWriteChannel(c, channelId); + case BATTERY_CONNECTED: + case BATTERY_OVERLOAD: + case ICU_RUNSTATE: + case INVERTER_CONNECTED: + return new BooleanReadChannel(c, channelId); + case SYSTEM_STATE_INFORMATION: + return new StringWriteChannel(c, channelId); + } + return null; + }) // + ).flatMap(channel -> channel); + } +} diff --git a/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/package-info.java b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/package-info.java new file mode 100644 index 00000000000..449751c8272 --- /dev/null +++ b/io.openems.edge.ess.streetscooter/src/io/openems/edge/ess/streetscooter/package-info.java @@ -0,0 +1,2 @@ +package io.openems.edge.ess.streetscooter; + diff --git a/io.openems.edge.ess.streetscooter/test/.gitignore b/io.openems.edge.ess.streetscooter/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java index 293a8ffbbe5..b98786f88aa 100644 --- a/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java +++ b/io.openems.edge.evcs.api/src/io/openems/edge/evcs/api/Evcs.java @@ -22,7 +22,7 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { *
          • Unit: W *
          */ - SET_CHARGE_POWER(new Doc().isWritable().type(OpenemsType.INTEGER).unit(Unit.WATT)), + SET_CHARGE_POWER(new Doc().setWritable().type(OpenemsType.INTEGER).unit(Unit.WATT)), /** * Set Display Text * @@ -32,7 +32,7 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { *
        • Type: String *
        */ - SET_DISPLAY_TEXT(new Doc().isWritable().type(OpenemsType.STRING)); + SET_DISPLAY_TEXT(new Doc().setWritable().type(OpenemsType.STRING)); // TODO add debug channel for set charge power diff --git a/io.openems.edge.evcs.keba.kecontact/doc/KeContact_P20_P30_UDP_ProgrGuide_en.pdf b/io.openems.edge.evcs.keba.kecontact/doc/KeContact_P20_P30_UDP_ProgrGuide_en.pdf new file mode 100644 index 00000000000..15600106055 Binary files /dev/null and b/io.openems.edge.evcs.keba.kecontact/doc/KeContact_P20_P30_UDP_ProgrGuide_en.pdf differ diff --git a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/ReadWorker.java b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/ReadWorker.java index 23f65575494..7623a575bc7 100644 --- a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/ReadWorker.java +++ b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/ReadWorker.java @@ -22,12 +22,12 @@ public ReadWorker(KebaKeContact parent) { } @Override - protected void activate(String name) { + public void activate(String name) { super.activate(name); } @Override - protected void deactivate() { + public void deactivate() { super.deactivate(); } diff --git a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/Utils.java b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/Utils.java index 466ca9a491c..f1f49ed5a24 100644 --- a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/Utils.java +++ b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/Utils.java @@ -8,7 +8,7 @@ import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.channel.IntegerReadChannel; import io.openems.edge.common.channel.IntegerWriteChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.channel.StringReadChannel; import io.openems.edge.common.channel.StringWriteChannel; import io.openems.edge.common.component.OpenemsComponent; @@ -20,7 +20,7 @@ public static Stream> initializeChannels(KebaKe Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; }), Arrays.stream(Evcs.ChannelId.values()).map(channelId -> { diff --git a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/core/KebaKeContactCoreImpl.java b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/core/KebaKeContactCoreImpl.java index bcafaa51a43..b1e88d4d651 100644 --- a/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/core/KebaKeContactCoreImpl.java +++ b/io.openems.edge.evcs.keba.kecontact/src/io/openems/edge/evcs/keba/kecontact/core/KebaKeContactCoreImpl.java @@ -16,7 +16,7 @@ import org.slf4j.LoggerFactory; import io.openems.common.exceptions.OpenemsException; -import io.openems.edge.common.worker.AbstractWorker; +import io.openems.edge.common.worker.AbstractImmediateWorker; import io.openems.edge.evcs.keba.kecontact.KebaKeContact; @Component( // @@ -46,7 +46,7 @@ public void onReceive(BiConsumer callback) { this.onReceiveCallbacks.add(callback); } - private class ReceiveWorker extends AbstractWorker { + private class ReceiveWorker extends AbstractImmediateWorker { private final DatagramSocket socket; @@ -60,13 +60,13 @@ private ReceiveWorker(int port) throws OpenemsException { } @Override - protected void activate(String name) { + public void activate(String name) { super.activate(name); log.info("Started Evcs.Keba.KeContact.Core listener on port [" + KebaKeContact.UDP_PORT + "]"); } @Override - protected void deactivate() { + public void deactivate() { super.deactivate(); log.info("Stopped Evcs.Keba.KeContact.Core listener on port [" + KebaKeContact.UDP_PORT + "]"); } @@ -90,12 +90,6 @@ protected void forever() { // call callbacks onReceiveCallbacks.forEach(consumer -> consumer.accept(ip, message)); } - - @Override - protected int getCycleTime() { - // do not wait between to consecutive calls of forever() - return 0; - } } } diff --git a/io.openems.edge.evcs.keba.kecontact/test/.gitignore b/io.openems.edge.evcs.keba.kecontact/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/KmtronicRelayOutput.java b/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/KmtronicRelayOutput.java index 482517f64dc..385a9086d63 100644 --- a/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/KmtronicRelayOutput.java +++ b/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/KmtronicRelayOutput.java @@ -21,12 +21,12 @@ import io.openems.edge.bridge.modbus.api.element.CoilElement; import io.openems.edge.bridge.modbus.api.task.FC1ReadCoilsTask; import io.openems.edge.bridge.modbus.api.task.FC5WriteCoilTask; -import io.openems.edge.bridge.modbus.api.task.Priority; import io.openems.edge.common.channel.BooleanWriteChannel; import io.openems.edge.common.channel.WriteChannel; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.channel.doc.Unit; import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.taskmanager.Priority; import io.openems.edge.io.api.DigitalOutput; @Designate(ocd = Config.class, factory = true) @@ -290,7 +290,8 @@ protected void setModbus(BridgeModbus modbus) { public KmtronicRelayOutput() { Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); - this.digitalOutputChannels = new BooleanWriteChannel[] { this.channel(KmtronicRelayOutput.ChannelId.RELAY_1), // + this.digitalOutputChannels = new BooleanWriteChannel[] { // + this.channel(KmtronicRelayOutput.ChannelId.RELAY_1), // this.channel(KmtronicRelayOutput.ChannelId.RELAY_2), // this.channel(KmtronicRelayOutput.ChannelId.RELAY_3), // this.channel(KmtronicRelayOutput.ChannelId.RELAY_4), // diff --git a/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/Utils.java b/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/Utils.java index d7c891e1f36..9ff1ae165fe 100644 --- a/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/Utils.java +++ b/io.openems.edge.io.kmtronic/src/io/openems/edge/io/kmtronic/Utils.java @@ -6,7 +6,7 @@ import io.openems.edge.common.channel.AbstractReadChannel; import io.openems.edge.common.channel.BooleanReadChannel; import io.openems.edge.common.channel.BooleanWriteChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; public class Utils { @@ -15,7 +15,7 @@ public static Stream> initializeChannels(Kmtron Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; }) diff --git a/io.openems.edge.io.kmtronic/test/.gitignore b/io.openems.edge.io.kmtronic/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.meter.api/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.meter.api/.settings/org.eclipse.core.resources.prefs index f99c74f4ea0..5689e9f7c6d 100644 --- a/io.openems.edge.meter.api/.settings/org.eclipse.core.resources.prefs +++ b/io.openems.edge.meter.api/.settings/org.eclipse.core.resources.prefs @@ -1,7 +1,5 @@ eclipse.preferences.version=1 -encoding//src/io/openems/edge/meter/api/Meter.java=UTF-8 encoding//src/io/openems/edge/meter/api/package-info.java=UTF-8 -encoding//src/io/openems/edge/meter/symmetric/api/package-info.java=UTF-8 encoding//test/.gitignore=UTF-8 encoding/bnd.bnd=UTF-8 encoding/readme.md=UTF-8 diff --git a/io.openems.edge.meter.api/bnd.bnd b/io.openems.edge.meter.api/bnd.bnd index e71d35f2705..2cad7c66929 100644 --- a/io.openems.edge.meter.api/bnd.bnd +++ b/io.openems.edge.meter.api/bnd.bnd @@ -2,10 +2,7 @@ Bundle-Name: OpenEMS Edge Meter Api Bundle-Vendor: FENECON GmbH Bundle-License: https://opensource.org/licenses/EPL-2.0 Bundle-Version: 1.0.0.${tstamp} -Export-Package: \ - io.openems.edge.meter.api,\ - io.openems.edge.meter.symmetric.api,\ - io.openems.edge.meter.asymmetric.api +Export-Package: io.openems.edge.meter.api Require-Capability: \ compile-only diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/AsymmetricMeter.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/AsymmetricMeter.java new file mode 100644 index 00000000000..de849d6622b --- /dev/null +++ b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/AsymmetricMeter.java @@ -0,0 +1,248 @@ +package io.openems.edge.meter.api; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.common.channel.Channel; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Unit; + +/** + * Represents an Asymmetric Meter. + * + * - Negative ActivePowerL1/L2/L3 and ConsumptionActivePowerL1/L2/L3 represent + * Consumption, i.e. power that is 'leaving the system', e.g. feed-to-grid + * + * - Positive ActivePowerL1/L2/L3 and ProductionActivePowerL1/L2/L3 represent + * Production, i.e. power that is 'entering the system', e.g. buy-from-grid + * + */ +public interface AsymmetricMeter extends SymmetricMeter { + + public final static String POWER_DOC_TEXT = "Negative values for Consumption; positive for Production"; + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + /** + * Active Power L1 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Consumption (power that is 'leaving the + * system', e.g. feed-to-grid); positive for Production (power that is 'entering + * the system') + *
        + */ + ACTIVE_POWER_L1(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT) // + .text(POWER_DOC_TEXT)), // + /** + * Active Power L2 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Consumption (power that is 'leaving the + * system', e.g. feed-to-grid); positive for Production (power that is 'entering + * the system') + *
        + */ + ACTIVE_POWER_L2(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT) // + .text(POWER_DOC_TEXT)), // + /** + * Active Power L3 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: W + *
        • Range: negative values for Consumption (power that is 'leaving the + * system', e.g. feed-to-grid); positive for Production (power that is 'entering + * the system') + *
        + */ + ACTIVE_POWER_L3(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT) // + .text(POWER_DOC_TEXT)), // + /** + * Reactive Power L1 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Consumption (power that is 'leaving the + * system', e.g. feed-to-grid); positive for Production (power that is 'entering + * the system') + *
        + */ + REACTIVE_POWER_L1(new Doc().type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // + .text(POWER_DOC_TEXT)), // + /** + * Reactive Power L2 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Consumption (power that is 'leaving the + * system', e.g. feed-to-grid); positive for Production (power that is 'entering + * the system') + *
        + */ + REACTIVE_POWER_L2(new Doc().type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // + .text(POWER_DOC_TEXT)), // + /** + * Reactive Power L3 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: var + *
        • Range: negative values for Consumption (power that is 'leaving the + * system', e.g. feed-to-grid); positive for Production (power that is 'entering + * the system') + *
        + */ + REACTIVE_POWER_L3(new Doc().type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // + .text(POWER_DOC_TEXT)), // + /** + * Voltage L1 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: mV + *
        + */ + VOLTAGE_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)), // + /** + * Voltage L2 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: mV + *
        + */ + VOLTAGE_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)), // + /** + * Voltage L3 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: mV + *
        + */ + VOLTAGE_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)), // + /** + * Current L1 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: mA + *
        + */ + CURRENT_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE)), // + /** + * Current L2 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: mA + *
        + */ + CURRENT_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE)), // + /** + * Current L3 + * + *
          + *
        • Interface: Meter Asymmetric + *
        • Type: Integer + *
        • Unit: mA + *
        + */ + CURRENT_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE)); // + + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + public Doc doc() { + return this.doc; + } + } + + /** + * Gets the Active Power for L1 in [W]. Negative values for Consumption; + * positive for Production + * + * @return + */ + default Channel getActivePowerL1() { + return this.channel(ChannelId.ACTIVE_POWER_L1); + } + + /** + * Gets the Active Power for L2 in [W]. Negative values for Consumption; + * positive for Production + * + * @return + */ + default Channel getActivePowerL2() { + return this.channel(ChannelId.ACTIVE_POWER_L2); + } + + /** + * Gets the Active Power for L3 in [W]. Negative values for Consumption; + * positive for Production + * + * @return + */ + default Channel getActivePowerL3() { + return this.channel(ChannelId.ACTIVE_POWER_L3); + } + + /** + * Gets the Reactive Power for L1 in [var]. Negative values for Consumption; + * positive for Production. + * + * @return + */ + default Channel getReactivePowerL1() { + return this.channel(ChannelId.REACTIVE_POWER_L1); + } + + /** + * Gets the Reactive Power for L2 in [var]. Negative values for Consumption; + * positive for Production. + * + * @return + */ + default Channel getReactivePowerL2() { + return this.channel(ChannelId.REACTIVE_POWER_L2); + } + + /** + * Gets the Reactive Power for L3 in [var]. Negative values for Consumption; + * positive for Production. + * + * @return + */ + default Channel getReactivePowerL3() { + return this.channel(ChannelId.REACTIVE_POWER_L3); + } + +} diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/Meter.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/Meter.java deleted file mode 100644 index 99de72906fc..00000000000 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/Meter.java +++ /dev/null @@ -1,38 +0,0 @@ -package io.openems.edge.meter.api; - -import org.osgi.annotation.versioning.ProviderType; - -import io.openems.common.types.OpenemsType; -import io.openems.edge.common.channel.doc.Doc; -import io.openems.edge.common.channel.doc.Unit; -import io.openems.edge.common.component.OpenemsComponent; - -@ProviderType -public interface Meter extends OpenemsComponent { - - public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { - /** - * Frequency [mHz] - */ - FREQUENCY(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIHERTZ)) // - - ; - private final Doc doc; - - private ChannelId(Doc doc) { - this.doc = doc; - } - - public Doc doc() { - return this.doc; - } - } - - /** - * Gets the type of this Meter - * - * @return - */ - MeterType getMeterType(); - -} diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/MeterType.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/MeterType.java index e658aa55535..5d861ce7a5a 100644 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/api/MeterType.java +++ b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/MeterType.java @@ -14,6 +14,12 @@ public enum MeterType { * producer like a photovoltaics installation */ PRODUCTION, + /** + * Defines a Production+Consumption-Meter, i.e. a meter that is measuring + * something that is an electric producer and consumer at the same time, like a + * non-controlled, external energy storage system. + */ + PRODUCTION_AND_CONSUMPTION, /** * Defines a Consumption-Meter that is metered, i.e. a meter that is measuring * an electric consumer like a heating-element or electric car. diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/symmetric/api/SymmetricMeter.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SymmetricMeter.java similarity index 64% rename from io.openems.edge.meter.api/src/io/openems/edge/meter/symmetric/api/SymmetricMeter.java rename to io.openems.edge.meter.api/src/io/openems/edge/meter/api/SymmetricMeter.java index 54654275df3..f294f00fb51 100644 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/symmetric/api/SymmetricMeter.java +++ b/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SymmetricMeter.java @@ -1,4 +1,4 @@ -package io.openems.edge.meter.symmetric.api; +package io.openems.edge.meter.api; import org.osgi.service.cm.ConfigurationAdmin; @@ -9,8 +9,6 @@ import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.channel.doc.Unit; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.common.converter.StaticConverters; -import io.openems.edge.meter.api.Meter; /** * Represents a Symmetric Meter. @@ -24,36 +22,22 @@ * @author stefan.feilmeier * */ -public interface SymmetricMeter extends Meter { +public interface SymmetricMeter extends OpenemsComponent { public final static String POWER_DOC_TEXT = "Negative values for Consumption; positive for Production"; public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { /** - * Consumption Active Power + * Frequency * *
          *
        • Interface: Meter Symmetric *
        • Type: Integer - *
        • Unit: W + *
        • Unit: mHz *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from negative - * ACTIVE_POWER *
        */ - CONSUMPTION_ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Production Active Power - * - *
          - *
        • Interface: Meter Symmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: only positive values, derived from ACTIVE_POWER - *
        • Implementation Note: value is automatically derived from ACTIVE_POWER - *
        - */ - PRODUCTION_ACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // + FREQUENCY(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIHERTZ)), // /** * Minimum Ever Active Power * @@ -96,11 +80,6 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { .text(POWER_DOC_TEXT) // .onInit(channel -> { channel.onSetNextValue(value -> { - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.PRODUCTION_ACTIVE_POWER).setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CONSUMPTION_ACTIVE_POWER).setNextValue(chargeValue); /* * Fill Min/Max Active Power channels */ @@ -132,55 +111,44 @@ public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { }); })), // /** - * Consumption Reactive Power + * Reactive Power * *
          *
        • Interface: Meter Symmetric *
        • Type: Integer *
        • Unit: var - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from negative - * REACTIVE_POWER + *
        • Range: negative values for Consumption (power that is 'leaving the + * system', e.g. feed-to-grid); positive for Production (power that is 'entering + * the system') *
        */ - CONSUMPTION_REACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // + REACTIVE_POWER(new Doc().type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE_REACTIVE) // + .text(POWER_DOC_TEXT)), // /** - * Production Reactive Power + * Active Production Energy * *
          - *
        • Interface: Meter Symmetric + *
        • Interface: Ess Symmetric *
        • Type: Integer - *
        • Unit: var - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from REACTIVE_POWER + *
        • Unit: Wh *
        */ - PRODUCTION_REACTIVE_POWER(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // + ACTIVE_PRODUCTION_ENERGY(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT_HOURS)), /** - * Reactive Power + * Active Consumption Energy * *
          - *
        • Interface: Meter Symmetric + *
        • Interface: Ess Symmetric *
        • Type: Integer - *
        • Unit: var - *
        • Range: negative values for Consumption (power that is 'leaving the - * system', e.g. feed-to-grid); positive for Production (power that is 'entering - * the system') + *
        • Unit: Wh *
        */ - REACTIVE_POWER(new Doc().type(OpenemsType.INTEGER) // - .unit(Unit.VOLT_AMPERE_REACTIVE) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.PRODUCTION_REACTIVE_POWER) - .setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CONSUMPTION_REACTIVE_POWER).setNextValue(chargeValue); - }); - })), + ACTIVE_CONSUMPTION_ENERGY(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.WATT_HOURS)), /** * Voltage * @@ -214,33 +182,20 @@ public Doc doc() { } /** - * Gets the Active Power in [W]. Negative values for Consumption; positive for - * Production - * - * @return - */ - default Channel getActivePower() { - return this.channel(ChannelId.ACTIVE_POWER); - } - - /** - * Gets the Consumption Active Power in [W]. This is derived from negative - * 'getActivePower()' values; 0 for positive. + * Gets the type of this Meter * * @return */ - default Channel getConsumptionActivePower() { - return this.channel(ChannelId.CONSUMPTION_ACTIVE_POWER); - } + MeterType getMeterType(); /** - * Gets the Production Active Power in [W]. This is derived from positive - * 'getActivePower()' values; 0 for negative. + * Gets the Active Power in [W]. Negative values for Consumption; positive for + * Production * * @return */ - default Channel getProductionActivePower() { - return this.channel(ChannelId.PRODUCTION_ACTIVE_POWER); + default Channel getActivePower() { + return this.channel(ChannelId.ACTIVE_POWER); } /** @@ -254,23 +209,22 @@ default Channel getReactivePower() { } /** - * Gets the Consumption Reactive Power in [var]. This is derived from negative - * 'getReactivePower()' values; 0 for positive. + * Gets the Production Active Energy in [Wh]. This relates to positive + * ACTIVE_POWER. * * @return */ - default Channel getConsumptionReactivePower() { - return this.channel(ChannelId.CONSUMPTION_REACTIVE_POWER); + default Channel getActiveProductionEnergy() { + return this.channel(ChannelId.ACTIVE_PRODUCTION_ENERGY); } /** - * Gets the Production Reactive Power in [var]. This is derived from positive - * 'getReactivePower()' values; 0 for negative. + * Gets the Consumption Active Energy in [Wh]. This relates to negative ACTIVE_POWER. * * @return */ - default Channel getProductionReactivePower() { - return this.channel(ChannelId.PRODUCTION_REACTIVE_POWER); + default Channel getActiveConsumptionEnergy() { + return this.channel(ChannelId.ACTIVE_CONSUMPTION_ENERGY); } /** @@ -308,12 +262,12 @@ default void _initializeMinMaxActivePower(ConfigurationAdmin cm, String serviceP this.getMinActivePower().setNextValue(minActivePowerConfig); this.getMaxActivePower().setNextValue(maxActivePowerConfig); - this.getMinActivePower().onUpdate(value -> { + this.getMinActivePower().onChange(value -> { if (value.get() != minActivePowerConfig) { OpenemsComponent.updateConfigurationProperty(cm, servicePid, "minActivePower", value.get()); } }); - this.getMaxActivePower().onUpdate(value -> { + this.getMaxActivePower().onChange(value -> { if (value.get() != maxActivePowerConfig) { OpenemsComponent.updateConfigurationProperty(cm, servicePid, "maxActivePower", value.get()); } diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/asymmetric/api/AsymmetricMeter.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/asymmetric/api/AsymmetricMeter.java deleted file mode 100644 index 4efdc8fda76..00000000000 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/asymmetric/api/AsymmetricMeter.java +++ /dev/null @@ -1,586 +0,0 @@ -package io.openems.edge.meter.asymmetric.api; - -import io.openems.common.types.OpenemsType; -import io.openems.edge.common.channel.Channel; -import io.openems.edge.common.channel.doc.Doc; -import io.openems.edge.common.channel.doc.Unit; -import io.openems.edge.common.converter.StaticConverters; -import io.openems.edge.meter.api.Meter; - -/** - * Represents an Asymmetric Meter. - * - * - Negative ActivePowerL1/L2/L3 and ConsumptionActivePowerL1/L2/L3 represent - * Consumption, i.e. power that is 'leaving the system', e.g. feed-to-grid - * - * - Positive ActivePowerL1/L2/L3 and ProductionActivePowerL1/L2/L3 represent - * Production, i.e. power that is 'entering the system', e.g. buy-from-grid - * - */ -public interface AsymmetricMeter extends Meter { - - public final static String POWER_DOC_TEXT = "Negative values for Consumption; positive for Production"; - - public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { - /** - * Consumption Active Power L1 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from negative - * ACTIVE_POWER_L1 - *
        - */ - CONSUMPTION_ACTIVE_POWER_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Consumption Active Power L2 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from negative - * ACTIVE_POWER_L2 - *
        - */ - CONSUMPTION_ACTIVE_POWER_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Consumption Active Power L3 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from negative - * ACTIVE_POWER_L3 - *
        - */ - CONSUMPTION_ACTIVE_POWER_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Production Active Power L1 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from ACTIVE_POWER_L1 - *
        - */ - PRODUCTION_ACTIVE_POWER_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Production Active Power L2 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from ACTIVE_POWER_L2 - *
        - */ - PRODUCTION_ACTIVE_POWER_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Production Active Power L3 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from ACTIVE_POWER_L3 - *
        - */ - PRODUCTION_ACTIVE_POWER_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.WATT)), // - /** - * Active Power L1 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: negative values for Consumption (power that is 'leaving the - * system', e.g. feed-to-grid); positive for Production (power that is 'entering - * the system') - *
        - */ - ACTIVE_POWER_L1(new Doc() // - .type(OpenemsType.INTEGER) // - .unit(Unit.WATT) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.PRODUCTION_ACTIVE_POWER_L1) - .setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CONSUMPTION_ACTIVE_POWER_L1).setNextValue(chargeValue); - }); - })), // - /** - * Active Power L2 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: negative values for Consumption (power that is 'leaving the - * system', e.g. feed-to-grid); positive for Production (power that is 'entering - * the system') - *
        - */ - ACTIVE_POWER_L2(new Doc() // - .type(OpenemsType.INTEGER) // - .unit(Unit.WATT) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.PRODUCTION_ACTIVE_POWER_L2) - .setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CONSUMPTION_ACTIVE_POWER_L2).setNextValue(chargeValue); - }); - })), // - /** - * Active Power L3 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: W - *
        • Range: negative values for Consumption (power that is 'leaving the - * system', e.g. feed-to-grid); positive for Production (power that is 'entering - * the system') - *
        - */ - ACTIVE_POWER_L3(new Doc() // - .type(OpenemsType.INTEGER) // - .unit(Unit.WATT) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.PRODUCTION_ACTIVE_POWER_L3) - .setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CONSUMPTION_ACTIVE_POWER_L3).setNextValue(chargeValue); - }); - })), // - /** - * Consumption Reactive Power L1 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from negative - * REACTIVE_POWER_L1 - *
        - */ - CONSUMPTION_REACTIVE_POWER_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - /** - * Consumption Reactive Power L2 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from negative - * REACTIVE_POWER_L2 - *
        - */ - CONSUMPTION_REACTIVE_POWER_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - /** - * Consumption Reactive Power L3 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from negative - * REACTIVE_POWER_L3 - *
        - */ - CONSUMPTION_REACTIVE_POWER_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - /** - * Production Reactive Power L1 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from - * REACTIVE_POWER_L1 - *
        - */ - PRODUCTION_REACTIVE_POWER_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - /** - * Production Reactive Power L2 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from - * REACTIVE_POWER_L2 - *
        - */ - PRODUCTION_REACTIVE_POWER_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - /** - * Production Reactive Power L3 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: only positive values - *
        • Implementation Note: value is automatically derived from - * REACTIVE_POWER_L3 - *
        - */ - PRODUCTION_REACTIVE_POWER_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.VOLT_AMPERE_REACTIVE)), // - /** - * Reactive Power L1 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: negative values for Consumption (power that is 'leaving the - * system', e.g. feed-to-grid); positive for Production (power that is 'entering - * the system') - *
        - */ - REACTIVE_POWER_L1(new Doc().type(OpenemsType.INTEGER) // - .unit(Unit.VOLT_AMPERE_REACTIVE) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.PRODUCTION_REACTIVE_POWER_L1) - .setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CONSUMPTION_REACTIVE_POWER_L1) - .setNextValue(chargeValue); - }); - })), - /** - * Reactive Power L2 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: negative values for Consumption (power that is 'leaving the - * system', e.g. feed-to-grid); positive for Production (power that is 'entering - * the system') - *
        - */ - REACTIVE_POWER_L2(new Doc().type(OpenemsType.INTEGER) // - .unit(Unit.VOLT_AMPERE_REACTIVE) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.PRODUCTION_REACTIVE_POWER_L2) - .setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CONSUMPTION_REACTIVE_POWER_L2) - .setNextValue(chargeValue); - }); - })), - /** - * Reactive Power L3 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: var - *
        • Range: negative values for Consumption (power that is 'leaving the - * system', e.g. feed-to-grid); positive for Production (power that is 'entering - * the system') - *
        - */ - REACTIVE_POWER_L3(new Doc().type(OpenemsType.INTEGER) // - .unit(Unit.VOLT_AMPERE_REACTIVE) // - .text(POWER_DOC_TEXT) // - .onInit(channel -> { - channel.onSetNextValue(value -> { - Object dischargeValue = StaticConverters.KEEP_POSITIVE.apply(value.get()); - channel.getComponent().channel(ChannelId.PRODUCTION_REACTIVE_POWER_L3) - .setNextValue(dischargeValue); - Object chargeValue = StaticConverters.INVERT.andThen(StaticConverters.KEEP_POSITIVE) - .apply(value.get()); - channel.getComponent().channel(ChannelId.CONSUMPTION_REACTIVE_POWER_L3) - .setNextValue(chargeValue); - }); - })), - /** - * Voltage L1 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: mV - *
        - */ - VOLTAGE_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)), // - /** - * Voltage L2 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: mV - *
        - */ - VOLTAGE_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)), // - /** - * Voltage L3 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: mV - *
        - */ - VOLTAGE_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIVOLT)), // - /** - * Current L1 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: mA - *
        - */ - CURRENT_L1(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE)), // - /** - * Current L2 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: mA - *
        - */ - CURRENT_L2(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE)), // - /** - * Current L3 - * - *
          - *
        • Interface: Meter Asymmetric - *
        • Type: Integer - *
        • Unit: mA - *
        - */ - CURRENT_L3(new Doc().type(OpenemsType.INTEGER).unit(Unit.MILLIAMPERE)); // - - private final Doc doc; - - private ChannelId(Doc doc) { - this.doc = doc; - } - - public Doc doc() { - return this.doc; - } - } - - /** - * Gets the Active Power for L1 in [W]. Negative values for Consumption; - * positive for Production - * - * @return - */ - default Channel getActivePowerL1() { - return this.channel(ChannelId.ACTIVE_POWER_L1); - } - - /** - * Gets the Active Power for L2 in [W]. Negative values for Consumption; - * positive for Production - * - * @return - */ - default Channel getActivePowerL2() { - return this.channel(ChannelId.ACTIVE_POWER_L2); - } - - /** - * Gets the Active Power for L3 in [W]. Negative values for Consumption; - * positive for Production - * - * @return - */ - default Channel getActivePowerL3() { - return this.channel(ChannelId.ACTIVE_POWER_L3); - } - - /** - * Gets the Consumption Active Power for L1 in [W]. This is derived from - * negative 'getActivePowerL1()' values; 0 for positive. - * - * @return - */ - default Channel getConsumptionActivePowerL1() { - return this.channel(ChannelId.CONSUMPTION_ACTIVE_POWER_L1); - } - - /** - * Gets the Consumption Active Power for L2 in [W]. This is derived from - * negative 'getActivePowerL2()' values; 0 for positive. - * - * @return - */ - default Channel getConsumptionActivePowerL2() { - return this.channel(ChannelId.CONSUMPTION_ACTIVE_POWER_L2); - } - - /** - * Gets the Consumption Active Power for L3 in [W]. This is derived from - * negative 'getActivePowerL3()' values; 0 for positive. - * - * @return - */ - default Channel getConsumptionActivePowerL3() { - return this.channel(ChannelId.CONSUMPTION_ACTIVE_POWER_L3); - } - - /** - * Gets the Production Active Power for L1 in [W]. This is derived from positive - * 'getActivePowerL1()' values; 0 for negative. - * - * @return - */ - default Channel getProductionActivePowerL1() { - return this.channel(ChannelId.PRODUCTION_ACTIVE_POWER_L1); - } - - /** - * Gets the Production Active Power for L2 in [W]. This is derived from positive - * 'getActivePowerL2()' values; 0 for negative. - * - * @return - */ - default Channel getProductionActivePowerL2() { - return this.channel(ChannelId.PRODUCTION_ACTIVE_POWER_L2); - } - - /** - * Gets the Production Active Power for L3 in [W]. This is derived from positive - * 'getActivePowerL3()' values; 0 for negative. - * - * @return - */ - default Channel getProductionActivePowerL3() { - return this.channel(ChannelId.PRODUCTION_ACTIVE_POWER_L3); - } - - /** - * Gets the Reactive Power for L1 in [var]. Negative values for Consumption; - * positive for Production. - * - * @return - */ - default Channel getReactivePowerL1() { - return this.channel(ChannelId.REACTIVE_POWER_L1); - } - - /** - * Gets the Reactive Power for L2 in [var]. Negative values for Consumption; - * positive for Production. - * - * @return - */ - default Channel getReactivePowerL2() { - return this.channel(ChannelId.REACTIVE_POWER_L2); - } - - /** - * Gets the Reactive Power for L3 in [var]. Negative values for Consumption; - * positive for Production. - * - * @return - */ - default Channel getReactivePowerL3() { - return this.channel(ChannelId.REACTIVE_POWER_L3); - } - - /** - * Gets the Consumption Reactive Power for L1 in [var]. This is derived from - * negative 'getReactivePowerL2()' values; 0 for positive. - * - * @return - */ - default Channel getConsumptionReactivePowerL1() { - return this.channel(ChannelId.CONSUMPTION_REACTIVE_POWER_L1); - } - - /** - * Gets the Consumption Reactive Power for L2 in [var]. This is derived from - * negative 'getReactivePowerL2()' values; 0 for positive. - * - * @return - */ - default Channel getConsumptionReactivePowerL2() { - return this.channel(ChannelId.CONSUMPTION_REACTIVE_POWER_L2); - } - - /** - * Gets the Consumption Reactive Power for L3 in [var]. This is derived from - * negative 'getReactivePowerL3()' values; 0 for positive. - * - * @return - */ - default Channel getConsumptionReactivePowerL3() { - return this.channel(ChannelId.CONSUMPTION_REACTIVE_POWER_L3); - } - - /** - * Gets the Production Reactive Power for L1 in [var]. This is derived from - * positive 'getReactivePowerL1()' values; 0 for negative. - * - * @return - */ - default Channel getProductionReactivePowerL1() { - return this.channel(ChannelId.PRODUCTION_REACTIVE_POWER_L1); - } - - /** - * Gets the Production Reactive Power for L2 in [var]. This is derived from - * positive 'getReactivePowerL2()' values; 0 for negative. - * - * @return - */ - default Channel getProductionReactivePowerL2() { - return this.channel(ChannelId.PRODUCTION_REACTIVE_POWER_L2); - } - - /** - * Gets the Production Reactive Power for L3 in [var]. This is derived from - * positive 'getReactivePowerL3()' values; 0 for negative. - * - * @return - */ - default Channel getProductionReactivePowerL3() { - return this.channel(ChannelId.PRODUCTION_REACTIVE_POWER_L3); - } - -} diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/asymmetric/api/package-info.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/asymmetric/api/package-info.java deleted file mode 100644 index 3336a34e198..00000000000 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/asymmetric/api/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -@org.osgi.annotation.versioning.Version("1.0.0") -package io.openems.edge.meter.asymmetric.api; diff --git a/io.openems.edge.meter.api/src/io/openems/edge/meter/symmetric/api/package-info.java b/io.openems.edge.meter.api/src/io/openems/edge/meter/symmetric/api/package-info.java deleted file mode 100644 index 51b3170e6c7..00000000000 --- a/io.openems.edge.meter.api/src/io/openems/edge/meter/symmetric/api/package-info.java +++ /dev/null @@ -1,2 +0,0 @@ -@org.osgi.annotation.versioning.Version("1.0.0") -package io.openems.edge.meter.symmetric.api; diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/.classpath b/io.openems.edge.meter.carlo.gavazzi.em300/.classpath new file mode 100644 index 00000000000..26009f42341 --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/.gitignore b/io.openems.edge.meter.carlo.gavazzi.em300/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/bnd.bnd b/io.openems.edge.meter.carlo.gavazzi.em300/bnd.bnd new file mode 100644 index 00000000000..51a706e3d9c --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/bnd.bnd @@ -0,0 +1,22 @@ +Bundle-Name: OpenEMS Edge Meter Carlo Gavazzi EM300 +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} +Export-Package: \ + io.openems.edge.meter.api,\ + io.openems.edge.meter.asymmetric.api,\ + io.openems.edge.meter.symmetric.api +Private-Package: io.openems.edge.meter.carlo.gavazzi.em300 + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.edge.meter.api;version=latest,\ + io.openems.edge.bridge.modbus;version=latest,\ + io.openems.edge.common;version=latest,\ + io.openems.common;version=latest + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/debug.bndrun b/io.openems.edge.meter.carlo.gavazzi.em300/debug.bndrun new file mode 100644 index 00000000000..ee95af65b05 --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/debug.bndrun @@ -0,0 +1,13 @@ +# +# io.openems.edge.meter.carlo.gavazzi.em300 DEBUG LAUNCH SPECFICATION +# + +-include: ~io.openems.edge.meter.carlo.gavazzi.em300.bndrun + +-runrequires.debug: \ + ${debug-bundles} + +-runtrace: true + +-runbundles: \ + ${error;Resolve first} diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/doc/EM341-Modbus.pdf b/io.openems.edge.meter.carlo.gavazzi.em300/doc/EM341-Modbus.pdf new file mode 100644 index 00000000000..51f716ced29 Binary files /dev/null and b/io.openems.edge.meter.carlo.gavazzi.em300/doc/EM341-Modbus.pdf differ diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/io.openems.edge.meter.carlo.gavazzi.em300.bndrun b/io.openems.edge.meter.carlo.gavazzi.em300/io.openems.edge.meter.carlo.gavazzi.em300.bndrun new file mode 100644 index 00000000000..2e017a716c0 --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/io.openems.edge.meter.carlo.gavazzi.em300.bndrun @@ -0,0 +1,14 @@ +# +# io.openems.edge.meter.carlo.gavazzi.em300 LAUNCH SPECIFICATION +# + + +Bundle-Version: 1.0.0.${tstamp} +Bundle-SymbolicName: io.openems.edge.meter.carlo.gavazzi.em300.launch +JPM-Command: provider + + +-runrequires: \ + osgi.identity;filter:='(osgi.identity=io.openems.edge.meter.carlo.gavazzi.em300.provider)' + +-runbundles: ${error;You must first resolve this bndrun file before you can run it} diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/readme.md b/io.openems.edge.meter.carlo.gavazzi.em300/readme.md new file mode 100644 index 00000000000..13725411c7d --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/readme.md @@ -0,0 +1,8 @@ +# io.openems.edge.meter.carlo.gavazzi.em300 Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/Config.java b/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/Config.java new file mode 100644 index 00000000000..b9336c1d23c --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/Config.java @@ -0,0 +1,37 @@ +package io.openems.edge.meter.carlo.gavazzi.em300; + +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +import io.openems.edge.meter.api.MeterType; + +@ObjectClassDefinition( // + name = "Meter Carlo Gavazzi EM300", // + description = "Implements the Carlo Gavazzi EM300-series meter.") +@interface Config { + String service_pid(); + + String id() default "meter0"; + + boolean enabled() default true; + + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.PRODUCTION; + + @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.") + String modbus_id(); + + @AttributeDefinition(name = "Modbus Unit-ID", description = "The Unit-ID of the Modbus device.") + int modbusUnitId(); + + @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") + String Modbus_target() default ""; + + @AttributeDefinition(name = "Minimum Ever Active Power", description = "This is automatically updated.") + int minActivePower(); + + @AttributeDefinition(name = "Maximum Ever Active Power", description = "This is automatically updated.") + int maxActivePower(); + + String webconsole_configurationFactory_nameHint() default "Meter Carlo Gavazzi EM300 [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300.java b/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300.java new file mode 100644 index 00000000000..f2c5f0eb4ad --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/MeterCarloGavazziEm300.java @@ -0,0 +1,202 @@ +package io.openems.edge.meter.carlo.gavazzi.em300; + +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.common.types.OpenemsType; +import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent; +import io.openems.edge.bridge.modbus.api.BridgeModbus; +import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; +import io.openems.edge.bridge.modbus.api.ModbusProtocol; +import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; +import io.openems.edge.bridge.modbus.api.element.SignedDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.SignedWordElement; +import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; +import io.openems.edge.bridge.modbus.api.element.WordOrder; +import io.openems.edge.bridge.modbus.api.task.FC4ReadInputRegistersTask; +import io.openems.edge.common.channel.doc.Doc; +import io.openems.edge.common.channel.doc.Unit; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.meter.api.AsymmetricMeter; +import io.openems.edge.meter.api.MeterType; +import io.openems.edge.meter.api.SymmetricMeter; + +@Designate(ocd = Config.class, factory = true) +@Component(name = "Meter.CarloGavazzi.EM300", immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE) +public class MeterCarloGavazziEm300 extends AbstractOpenemsModbusComponent + implements SymmetricMeter, AsymmetricMeter, OpenemsComponent { + + private MeterType meterType = MeterType.PRODUCTION; + + @Reference + protected ConfigurationAdmin cm; + + public MeterCarloGavazziEm300() { + Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); + } + + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) + protected void setModbus(BridgeModbus modbus) { + super.setModbus(modbus); + } + + @Activate + void activate(ComponentContext context, Config config) { + this.meterType = config.type(); + + super.activate(context, config.service_pid(), config.id(), config.enabled(), config.modbusUnitId(), this.cm, + "Modbus", config.modbus_id()); + + // Initialize Min/MaxActivePower channels + this._initializeMinMaxActivePower(this.cm, config.service_pid(), config.minActivePower(), + config.maxActivePower()); + } + + @Deactivate + protected void deactivate() { + super.deactivate(); + } + + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + APPARENT_POWER_L1(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE)), // + APPARENT_POWER_L2(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE)), // + APPARENT_POWER_L3(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE)), // + APPARENT_POWER(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.VOLT_AMPERE)), // + FREQUENCY(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.MILLIHERTZ)), // + ACTIVE_ENERGY_POSITIVE(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS)), // + REACTIVE_ENERGY_POSITIVE(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS)), // + ACTIVE_ENERGY_NEGATIVE(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS)), // + REACTIVE_ENERGY_NEGATIVE(new Doc() // + .type(OpenemsType.INTEGER) // + .unit(Unit.KILOWATT_HOURS)), // + ; + private final Doc doc; + + private ChannelId(Doc doc) { + this.doc = doc; + } + + public Doc doc() { + return this.doc; + } + } + + @Override + public MeterType getMeterType() { + return this.meterType; + } + + @Override + protected ModbusProtocol defineModbusProtocol(int unitId) { + final int OFFSET = 300000 + 1; + /** + * See Modbus definition PDF-file in doc directory and + * https://www.galoz.co.il/wp-content/uploads/2014/11/EM341-Modbus.pdf + */ + return new ModbusProtocol(unitId, // + new FC4ReadInputRegistersTask(300001 - OFFSET, Priority.LOW, // + m(AsymmetricMeter.ChannelId.VOLTAGE_L1, + new SignedDoublewordElement(300001 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_2), + m(AsymmetricMeter.ChannelId.VOLTAGE_L2, + new SignedDoublewordElement(300003 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_2), + m(AsymmetricMeter.ChannelId.VOLTAGE_L3, + new SignedDoublewordElement(300005 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_2)), + new FC4ReadInputRegistersTask(300013 - OFFSET, Priority.HIGH, // + m(AsymmetricMeter.ChannelId.CURRENT_L1, + new SignedDoublewordElement(300013 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_2), + m(AsymmetricMeter.ChannelId.CURRENT_L2, + new SignedDoublewordElement(300015 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_2), + m(AsymmetricMeter.ChannelId.CURRENT_L3, + new SignedDoublewordElement(300017 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_2), + m(AsymmetricMeter.ChannelId.ACTIVE_POWER_L1, + new SignedDoublewordElement(300019 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(AsymmetricMeter.ChannelId.ACTIVE_POWER_L2, + new SignedDoublewordElement(300021 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(AsymmetricMeter.ChannelId.ACTIVE_POWER_L3, + new SignedDoublewordElement(300023 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(MeterCarloGavazziEm300.ChannelId.APPARENT_POWER_L1, + new SignedDoublewordElement(300025 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(MeterCarloGavazziEm300.ChannelId.APPARENT_POWER_L2, + new SignedDoublewordElement(300027 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(MeterCarloGavazziEm300.ChannelId.APPARENT_POWER_L3, + new SignedDoublewordElement(300028 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(AsymmetricMeter.ChannelId.REACTIVE_POWER_L1, + new SignedDoublewordElement(300031 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(AsymmetricMeter.ChannelId.REACTIVE_POWER_L2, + new SignedDoublewordElement(300033 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(AsymmetricMeter.ChannelId.REACTIVE_POWER_L3, + new SignedDoublewordElement(300035 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + new DummyRegisterElement(300037 - OFFSET, 300040 - OFFSET), // + m(SymmetricMeter.ChannelId.ACTIVE_POWER, + new SignedDoublewordElement(300041 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(MeterCarloGavazziEm300.ChannelId.APPARENT_POWER, + new SignedDoublewordElement(300043 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), + m(SymmetricMeter.ChannelId.REACTIVE_POWER, + new SignedDoublewordElement(300045 - OFFSET).wordOrder(WordOrder.LSWMSW), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1)), + new FC4ReadInputRegistersTask(300052 - OFFSET, Priority.LOW, // + m(MeterCarloGavazziEm300.ChannelId.FREQUENCY, new SignedWordElement(300052 - OFFSET), + ElementToChannelConverter.SCALE_FACTOR_2), + m(MeterCarloGavazziEm300.ChannelId.ACTIVE_ENERGY_POSITIVE, + new UnsignedDoublewordElement(300053 - OFFSET), + ElementToChannelConverter.SCALE_FACTOR_1), + m(MeterCarloGavazziEm300.ChannelId.REACTIVE_ENERGY_POSITIVE, + new UnsignedDoublewordElement(300055 - OFFSET), + ElementToChannelConverter.SCALE_FACTOR_1)), + new FC4ReadInputRegistersTask(300079 - OFFSET, Priority.LOW, // + m(MeterCarloGavazziEm300.ChannelId.ACTIVE_ENERGY_NEGATIVE, + new UnsignedDoublewordElement(300079 - OFFSET), + ElementToChannelConverter.SCALE_FACTOR_1), + m(MeterCarloGavazziEm300.ChannelId.REACTIVE_ENERGY_NEGATIVE, + new UnsignedDoublewordElement(300081 - OFFSET), + ElementToChannelConverter.SCALE_FACTOR_1))); + } + + @Override + public String debugLog() { + return "L:" + this.getActivePower().value().asString(); + } +} diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/Utils.java b/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/Utils.java new file mode 100644 index 00000000000..3ac591be469 --- /dev/null +++ b/io.openems.edge.meter.carlo.gavazzi.em300/src/io/openems/edge/meter/carlo/gavazzi/em300/Utils.java @@ -0,0 +1,71 @@ +package io.openems.edge.meter.carlo.gavazzi.em300; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.common.channel.AbstractReadChannel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.meter.api.AsymmetricMeter; +import io.openems.edge.meter.api.SymmetricMeter; + +public class Utils { + public static Stream> initializeChannels(MeterCarloGavazziEm300 c) { + return Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(c, channelId); + } + return null; + }), Arrays.stream(SymmetricMeter.ChannelId.values()).map(channelId -> { + switch (channelId) { + case FREQUENCY: + case ACTIVE_POWER: + case MAX_ACTIVE_POWER: + case MIN_ACTIVE_POWER: + case REACTIVE_POWER: + case CURRENT: + case VOLTAGE: + case ACTIVE_CONSUMPTION_ENERGY: // TODO ACTIVE_CONSUMPTION_ENERGY + case ACTIVE_PRODUCTION_ENERGY: // TODO ACTIVE_PRODUCTION_ENERGY + return new IntegerReadChannel(c, channelId); + } + return null; + }), Arrays.stream(AsymmetricMeter.ChannelId.values()).map(channelId -> { + switch (channelId) { + case ACTIVE_POWER_L1: + case ACTIVE_POWER_L2: + case ACTIVE_POWER_L3: + case REACTIVE_POWER_L1: + case REACTIVE_POWER_L2: + case REACTIVE_POWER_L3: + case CURRENT_L1: + case CURRENT_L2: + case CURRENT_L3: + case VOLTAGE_L1: + case VOLTAGE_L2: + case VOLTAGE_L3: + return new IntegerReadChannel(c, channelId); + } + return null; + }), Arrays.stream(MeterCarloGavazziEm300.ChannelId.values()).map(channelId -> { + switch (channelId) { + case APPARENT_POWER: + case ACTIVE_ENERGY_NEGATIVE: + case ACTIVE_ENERGY_POSITIVE: + case APPARENT_POWER_L1: + case APPARENT_POWER_L2: + case APPARENT_POWER_L3: + case FREQUENCY: + case REACTIVE_ENERGY_NEGATIVE: + case REACTIVE_ENERGY_POSITIVE: + return new IntegerReadChannel(c, channelId); + } + return null; + }) + // + ).flatMap(channel -> channel); + } +} diff --git a/io.openems.edge.meter.carlo.gavazzi.em300/test/.gitignore b/io.openems.edge.meter.carlo.gavazzi.em300/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.meter.janitza.umg96rme/doc/Janitza-Manual-UMG96RM-Modbus-adress-list-and-formulary-en.pdf b/io.openems.edge.meter.janitza.umg96rme/doc/Janitza-Manual-UMG96RM-Modbus-adress-list-and-formulary-en.pdf new file mode 100644 index 00000000000..3e8d7465b82 Binary files /dev/null and b/io.openems.edge.meter.janitza.umg96rme/doc/Janitza-Manual-UMG96RM-Modbus-adress-list-and-formulary-en.pdf differ diff --git a/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/Config.java b/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/Config.java index 4bf8ea0cc13..140ad0f6096 100644 --- a/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/Config.java +++ b/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/Config.java @@ -3,6 +3,8 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.edge.meter.api.MeterType; + @ObjectClassDefinition( // name = "Meter Janitza UMG 96RM-E", // description = "Implements the Janitza UMG 96RM-E power analyser.") @@ -13,12 +15,15 @@ boolean enabled() default true; - @AttributeDefinition(name = "Meter-Type", description = "Grid, Production (=default), Consumption") - String type() default "production"; + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.PRODUCTION; @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.") String modbus_id(); + @AttributeDefinition(name = "Modbus Unit-ID", description = "The Unit-ID of the Modbus device. Defaults to '1' for Modbus/TCP.") + int modbusUnitId() default 1; + @AttributeDefinition(name = "Minimum Ever Active Power", description = "This is automatically updated.") int minActivePower(); diff --git a/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rme.java b/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rme.java index 99555a2e20a..86ea9a46867 100644 --- a/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rme.java +++ b/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/MeterJanitzaUmg96rme.java @@ -19,13 +19,12 @@ import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement; import io.openems.edge.bridge.modbus.api.element.FloatDoublewordElement; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; -import io.openems.edge.bridge.modbus.api.task.Priority; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.meter.api.Meter; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.meter.api.AsymmetricMeter; import io.openems.edge.meter.api.MeterType; -import io.openems.edge.meter.asymmetric.api.AsymmetricMeter; -import io.openems.edge.meter.symmetric.api.SymmetricMeter; +import io.openems.edge.meter.api.SymmetricMeter; /** * Implements the Janitza UMG 96RM-E power analyser @@ -40,8 +39,6 @@ public class MeterJanitzaUmg96rme extends AbstractOpenemsModbusComponent implements SymmetricMeter, AsymmetricMeter, OpenemsComponent { - private final static int UNIT_ID = 1; - private MeterType meterType = MeterType.PRODUCTION; @Reference @@ -58,14 +55,9 @@ protected void setModbus(BridgeModbus modbus) { @Activate void activate(ComponentContext context, Config config) { - // get Meter Type: - try { - this.meterType = MeterType.valueOf(config.type().toUpperCase()); - } catch (IllegalArgumentException e) { - this.meterType = MeterType.PRODUCTION; // default - } + this.meterType = config.type(); - super.activate(context, config.service_pid(), config.id(), config.enabled(), UNIT_ID, this.cm, "Modbus", + super.activate(context, config.service_pid(), config.id(), config.enabled(), config.modbusUnitId(), this.cm, "Modbus", config.modbus_id()); // Initialize Min/MaxActivePower channels @@ -104,7 +96,7 @@ protected ModbusProtocol defineModbusProtocol(int unitId) { */ return new ModbusProtocol(unitId, // new FC3ReadRegistersTask(800, Priority.HIGH, // - m(Meter.ChannelId.FREQUENCY, new FloatDoublewordElement(800), + m(SymmetricMeter.ChannelId.FREQUENCY, new FloatDoublewordElement(800), ElementToChannelConverter.SCALE_FACTOR_3), new DummyRegisterElement(802, 807), // cm(new FloatDoublewordElement(808)) // diff --git a/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/Utils.java b/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/Utils.java index 14c732f8339..573e089ebad 100644 --- a/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/Utils.java +++ b/io.openems.edge.meter.janitza.umg96rme/src/io/openems/edge/meter/janitza/umg96rme/Utils.java @@ -5,11 +5,10 @@ import io.openems.edge.common.channel.AbstractReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.meter.api.Meter; -import io.openems.edge.meter.asymmetric.api.AsymmetricMeter; -import io.openems.edge.meter.symmetric.api.SymmetricMeter; +import io.openems.edge.meter.api.AsymmetricMeter; +import io.openems.edge.meter.api.SymmetricMeter; public class Utils { public static Stream> initializeChannels(MeterJanitzaUmg96rme c) { @@ -17,27 +16,20 @@ public static Stream> initializeChannels(MeterJ Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); - } - return null; - }), Arrays.stream(Meter.ChannelId.values()).map(channelId -> { - switch (channelId) { - case FREQUENCY: - return new IntegerReadChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; }), Arrays.stream(SymmetricMeter.ChannelId.values()).map(channelId -> { switch (channelId) { + case FREQUENCY: case ACTIVE_POWER: case MAX_ACTIVE_POWER: case MIN_ACTIVE_POWER: case REACTIVE_POWER: - case CONSUMPTION_ACTIVE_POWER: - case CONSUMPTION_REACTIVE_POWER: - case PRODUCTION_ACTIVE_POWER: - case PRODUCTION_REACTIVE_POWER: case CURRENT: case VOLTAGE: + case ACTIVE_PRODUCTION_ENERGY: // TODO ACTIVE_PRODUCTION_ENERGY + case ACTIVE_CONSUMPTION_ENERGY: // TODO ACTIVE_CONSUMPTION_ENERGY return new IntegerReadChannel(c, channelId); } return null; @@ -46,18 +38,6 @@ public static Stream> initializeChannels(MeterJ case ACTIVE_POWER_L1: case ACTIVE_POWER_L2: case ACTIVE_POWER_L3: - case CONSUMPTION_ACTIVE_POWER_L1: - case CONSUMPTION_ACTIVE_POWER_L2: - case CONSUMPTION_ACTIVE_POWER_L3: - case CONSUMPTION_REACTIVE_POWER_L1: - case CONSUMPTION_REACTIVE_POWER_L2: - case CONSUMPTION_REACTIVE_POWER_L3: - case PRODUCTION_ACTIVE_POWER_L1: - case PRODUCTION_ACTIVE_POWER_L2: - case PRODUCTION_ACTIVE_POWER_L3: - case PRODUCTION_REACTIVE_POWER_L1: - case PRODUCTION_REACTIVE_POWER_L2: - case PRODUCTION_REACTIVE_POWER_L3: case REACTIVE_POWER_L1: case REACTIVE_POWER_L2: case REACTIVE_POWER_L3: diff --git a/io.openems.edge.meter.janitza.umg96rme/test/.gitignore b/io.openems.edge.meter.janitza.umg96rme/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.meter.socomec.dirisa14/doc/MODBUS tables of Diris_A14.html b/io.openems.edge.meter.socomec.dirisa14/doc/MODBUS tables of Diris_A14.html new file mode 100644 index 00000000000..352975ea864 --- /dev/null +++ b/io.openems.edge.meter.socomec.dirisa14/doc/MODBUS tables of Diris_A14.html @@ -0,0 +1,3901 @@ + + + + + + MODBUS tables of Diris_A14 + + + + +
        +
        +
        logosocomec.png
        +
        +

        General


        Identification


        + + + + + + + + + + + + + + + + + + + +
        +

        Product identification


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        500000xC350Info66NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        500000xC3504"SOCO"-STRING_16
        500040xC3541Product order ID (Countis:100, Protection:200, Atys:300, Diris:400)-U16
        500050xC3551Product ID (EX: 1000 ATS3)-U16
        500060xC3561JBUS Table Version (EX: 101 Version 1.01)-U16
        500070xC3571Product software version (EX: 100 Version 1.00)-U16
        500080xC3581Serial_AA_SS-U16_HEX
        500090xC3591Serial_SST_L-U16_HEX
        500100xC35A1Serial_order-U16
        500110xC35B2Serial_Reserve-U32
        500130xC35D4See "Code table" tab for more details-U64_HEX
        500170xC3611Customization data loaded (True/False)-U8
        500180xC3621Product version (Major)-U16
        500190xC3631Product version (Minor)-U16
        500200xC3641Product version (Revision)-U16
        500210xC3651Product version (Build)-U16
        500220xC3663Product build date-DATETIME_3
        500250xC3691Software technical base version (Major)-U16
        500260xC36A1Software technical base version (Minor)-U16
        500270xC36B1Software technical base version (Revision)-U16
        500280xC36C1Customization version (Major)-U16
        500290xC36D1Customization version (Minor)-U16
        500300xC36E4Product VLO (EX : "880100")-STRING_NORM
        500340xC3724Customization VLO (EX : "880700")-STRING_NORM
        500380xC3764Software technical base VLO (EX : "880600")-STRING_NORM
        500420xC37A8Vendor name (EX : "SOCOMEC")-STRING_NORM
        500500xC3828Product name (EX : "DIRIS A40R")-STRING_NORM
        500580xC38A8Extended name-STRING_NORM

        + + + + + + + + + + + + + + + + + + + +
        +

        Communication board informations


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        389120x9800Info11NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        389120x98001Communication Board version (Major)-U16
        389130x98011Communication Board version (Minor)-U16
        389140x98021Communication Board version (Revision)-U16
        389150x98031Communication Board version (Build)-U16
        389160x98043Communication Board build date-DATETIME_3
        389190x98074Communication Board VLO (EX : "880100")-STRING_NORM


        Common settings


        + + + + + + + + + + + + + + + + + + + +
        +

        Network Setting


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        573440xE000Settings12NONEREAD | WRITE | WRITE_MANYREAD | WRITE | WRITE_MANY

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        573440xE0001Network Type :
        0 : 1BL
        1 : 2BL
        2 : 3BL
        3 : 3NBL
        4 : 4BL
        5 : 4NBL
        -U8
        573450xE0011Current Transformer secondary :
        1 : 1 A
        5 : 5 A
        AU8
        573460xE0021Current Transformer primaryAU16
        573470xE0031Reserved - -
        573480xE0041Reserved - -
        573490xE0051Reserved - -
        573500xE0061Reserved - -
        573510xE0071Reserved - -
        573520xE0082Reserved - -
        573540xE00A1Reserved - -
        573550xE00B1Synchronisation Top for P+ : time in seconds (60s, 300s, 480s, 600s, 900s, 1200s, 1800s, 3600s)sU16

        + + + + + + + + + + + + + + + + + + + +
        +

        Hour/Date setting ( Write 6 words in one time Function 16)


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        576000xE100Settings6NONEREAD | WRITE | WRITE_MANYREAD | WRITE | WRITE_MANY

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        576000xE1001Day-U8
        576010xE1011Month-U8
        576020xE1021Year-U16
        576030xE1031Hour-U8
        576040xE1041Minute-U8
        576050xE1051Second-U8


        Actions


        + + + + + + + + + + + + + + + + + + + +
        +

        Action system


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        578560xE200Commands1NONEREAD | WRITEREAD | WRITE

        + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        578560xE2001Action :
        0xA1 : Product Configuration storage
        0xB2 : Produit reset
        -U8_HEX



        Application


        Measurement


        Common


        + + + + + + + + + + + + + + + + + + + +
        +

        Metrology Affected by current and voltage transformers


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        505120xC550Info62NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        505120xC5502Reserved - -
        505140xC5522Phase to Phase Voltage: U12V / 100U32
        505160xC5542Phase to Phase Voltage: U23V / 100U32
        505180xC5562Phase to Phase Voltage: U31V / 100U32
        505200xC5582Simple voltage : V1V / 100U32
        505220xC55A2Simple voltage : V2V / 100U32
        505240xC55C2Simple voltage : V3V / 100U32
        505260xC55E2Frequency : FHz / 100U32
        505280xC5602Current : I1A / 1000U32
        505300xC5622Current : I2A / 1000U32
        505320xC5642Current : I3A / 1000U32
        505340xC5662Neutral Current : InA / 1000U32
        505360xC5682? Active Power +/- : PW / 0.1S32
        505380xC56A2? Reactive Power +/- : Qvar / 0.1S32
        505400xC56C2? Apparent Power : SVA / 0.1U32
        505420xC56E2? Power Factor : -: leading et + : lagging : PF- / 1000S32
        505440xC5702Active Power phase 1 +/- : P1W / 0.1S32
        505460xC5722Active Power phase 2 +/- : P2W / 0.1S32
        505480xC5742Active Power phase 3 +/- : P3W / 0.1S32
        505500xC5762Reactive Power phase 1 +/- : Q1var / 0.1S32
        505520xC5782Reactive Power phase 2 +/- : Q2var / 0.1S32
        505540xC57A2Reactive Power phase 3 +/- : Q3var / 0.1S32
        505560xC57C2Apparent Power phase 1 : S1VA / 0.1U32
        505580xC57E2Apparent Power phase 2 : S2VA / 0.1U32
        505600xC5802Apparent Power phase 3 : S3VA / 0.1U32
        505620xC5822Power Factor phase 1 -: leading and + : lagging : PF1- / 1000S32
        505640xC5842Power Factor phase 2 -: leading and + : lagging : PF2- / 1000S32
        505660xC5862Power Factor phase 3 -: leading and + : lagging : PF3- / 1000S32
        505680xC5882Reserved - -
        505700xC58A2Reserved - -
        505720xC58C2Reserved - -

        + + + + + + + + + + + + + + + + + + + +
        +

        Energies


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        507680xC650Info65NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        507680xC6502Reserved - -
        507700xC6522Total Positive Active Energy (no resetable) : Ea+Wh / 0.001U32
        507720xC6542Total Positive Reactive Energy (no resetable) : Er +varh / 0.001U32
        507740xC6562Reserved - -
        507760xC6582Total Negative Active Energy (no resetable) : Ea-Wh / 0.001U32
        507780xC65A2Total Negative Reactive Energy (no resetable) : Er -varh / 0.001U32
        507800xC65C2Partial Positive Active Energy: Ea+Wh / 0.001U32
        507820xC65E2Partial Positive Reactive Energy: Er +varh / 0.001U32
        507840xC6602Reserved - -
        507860xC6622Partial Negative Active Energy : Ea-Wh / 0.001U32
        507880xC6642Partial Negative Reactive Energy : Er -varh / 0.001U32
        507900xC6662Reserved - -
        507920xC6682Reserved - -
        507940xC66A2Reserved - -
        507960xC66C2Reserved - -
        507980xC66E2Reserved - -
        508000xC6702Reserved - -
        508020xC6722Reserved - -
        508040xC6742Reserved - -
        508060xC6762Reserved - -
        508080xC6782Reserved - -
        508100xC67A2Reserved - -
        508120xC67C2Reserved - -
        508140xC67E2Reserved - -
        508160xC6802Reserved - -
        508180xC6822Reserved - -
        508200xC6842Reserved - -
        508220xC6862Reserved - -
        508240xC6882Reserved - -
        508260xC68A2Last date for Record average P/Q/S in second since 01/01/2000sU32
        508280xC68C1Last average (P+)WU16
        508290xC68D1Reserved - -
        508300xC68E1Reserved - -
        508310xC68F1Reserved - -
        508320xC6901Reserved - -

        + + + + + + + + + + + + + + + + + + + +
        +

        Energies in Unit/100


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        509440xC700Info65NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        509440xC7002Reserved - -
        509460xC7022Total Positive Active Energy (no resetable) : Ea+Wh / 0.1U32
        509480xC7042Total Positive Reactive Energy (no resetable) : Er +varh / 0.1U32
        509500xC7062Reserved - -
        509520xC7082Total Negative Active Energy (no resetable) : Ea-Wh / 0.1U32
        509540xC70A2Total Negative Reactive Energy (no resetable) : Er -varh / 0.1U32
        509560xC70C2Partial Positive Active Energy: Ea+Wh / 0.1U32
        509580xC70E2Partial Positive Reactive Energy: Er +varh / 0.1U32
        509600xC7102Reserved - -
        509620xC7122Partial Negative Active Energy : Ea-Wh / 0.1U32
        509640xC7142Partial Negative Reactive Energy : Er -varh / 0.1U32
        509660xC7162Reserved - -
        509680xC7182Reserved - -
        509700xC71A2Reserved - -
        509720xC71C2Reserved - -
        509740xC71E2Reserved - -
        509760xC7202Reserved - -
        509780xC7222Reserved - -
        509800xC7242Reserved - -
        509820xC7262Reserved - -
        509840xC7282Reserved - -
        509860xC72A2Reserved - -
        509880xC72C2Reserved - -
        509900xC72E2Reserved - -
        509920xC7302Reserved - -
        509940xC7322Reserved - -
        509960xC7342Reserved - -
        509980xC7362Reserved - -
        510000xC7382Reserved - -
        510020xC73A2Last date for Record average P/Q/S in second since 01/01/2000sU32
        510040xC73C1Last average (P+)WU16
        510050xC73D1Reserved - -
        510060xC73E1Reserved - -
        510070xC73F1Reserved - -
        510080xC7401Reserved - -

        + + + + + + + + + + + + + + + + + + + +
        +

        Energies per tariff


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        508480xC6A0Info50NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        508480xC6A010 >: Tariff number <: 8-U8
        508490xC6A11Tariff number in progress ( 1 to 8 )-U8
        508500xC6A22Positive Active Energies 1Wh / 100U32
        508520xC6A42Positive Active Energies 2h / 100U32
        508540xC6A62Positive Active Energies 3h / 100U32
        508560xC6A82Positive Active Energies 4h / 100U32
        508580xC6AA2Reserved - -
        508600xC6AC2Reserved - -
        508620xC6AE2Reserved - -
        508640xC6B02Reserved - -
        508660xC6B22Positive Reactive Enegies 1varh / 100U32
        508680xC6B42Positive Reactive Enegies 2h / 100U32
        508700xC6B62Positive Reactive Enegies 3h / 100U32
        508720xC6B82Positive Reactive Enegies 4h / 100U32
        508740xC6BA2Reserved - -
        508760xC6BC2Reserved - -
        508780xC6BE2Reserved - -
        508800xC6C02Reserved - -
        508820xC6C22Reserved - -
        508840xC6C42Reserved - -
        508860xC6C62Reserved - -
        508880xC6C82Reserved - -
        508900xC6CA2Reserved - -
        508920xC6CC2Reserved - -
        508940xC6CE2Reserved - -
        508960xC6D02Reserved - -

        + + + + + + + + + + + + + + + + + + + +
        +

        Energies per tariff in Unit/100


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        512000xC800Info50NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        512000xC80010 >: Tariff number <: 8-U8
        512010xC8011Tariff number in progress ( 1 to 8 )-U8
        512020xC8022Positive Active Energies 1Wh / 0.1U32
        512040xC8042Positive Active Energies 2Wh / 0.1U32
        512060xC8062Positive Active Energies 3Wh / 0.1U32
        512080xC8082Positive Active Energies 4Wh / 0.1U32
        512100xC80A2Positive Active Energies 5h / 100U32
        512120xC80C2Positive Active Energies 6h / 100U32
        512140xC80E2Positive Active Energies 7h / 100U32
        512160xC8102Positive Active Energies 8h / 100U32
        512180xC8122Positive Reactive Enegies 1varh / 0.1U32
        512200xC8142Positive Reactive Enegies 2varh / 0.1U32
        512220xC8162Positive Reactive Enegies 3varh / 0.1U32
        512240xC8182Positive Reactive Enegies 4varh / 0.1U32
        512260xC81A2Positive Reactive Enegies 5h / 100U32
        512280xC81C2Positive Reactive Enegies 6h / 100U32
        512300xC81E2Positive Reactive Enegies 7h / 100U32
        512320xC8202Positive Reactive Enegies 8h / 100U32
        512340xC8222Reserved - -
        512360xC8242Reserved - -
        512380xC8262Reserved - -
        512400xC8282Reserved - -
        512420xC82A2Reserved - -
        512440xC82C2Reserved - -
        512460xC82E2Reserved - -
        512480xC8302Reserved - -

        + + + + + + + + + + + + + + + + + + + +
        +

        Metrology No Affected by current and voltage transformers


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        512800xC850Info35NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        512800xC8501Reserved - -
        512810xC8511Phase to Phase Voltage: U12V / 100U16
        512820xC8521Phase to Phase Voltage: U23V / 100U16
        512830xC8531Phase to Phase Voltage: U31V / 100U16
        512840xC8541Simple voltage : V1V / 100U16
        512850xC8551Simple voltage : V2V / 100U16
        512860xC8561Simple voltage : V3V / 100U16
        512870xC8571Frequency : FHz / 100U16
        512880xC8581Current : I1A / 1000U16
        512890xC8591Current : I2A / 1000U16
        512900xC85A1Current : I3A / 1000U16
        512910xC85B1Neutral Current : InA / 1000U16
        512920xC85C1? active Power +/- : PW / 0.1S16
        512930xC85D1? reactive Power +/- : Qvar / 0.1S16
        512940xC85E1? apparent power : SVA / 0.1U16
        512950xC85F1? power factor : -: leading and + : lagging : PF- / 1000S16
        512960xC8601Active Power phase 1 +/- : P1W / 0.1S16
        512970xC8611Active Power phase 2 +/- : P2W / 0.1S16
        512980xC8621Active Power phase 3 +/- : P3W / 0.1S16
        512990xC8631Reactive Power phase 1 +/- : Q1var / 0.1S16
        513000xC8641Reactive Power phase 2 +/- : Q2var / 0.1S16
        513010xC8651Reactive Power phase 3 +/- : Q3var / 0.1S16
        513020xC8661Apparent power phase 1 : S1VA / 0.1U16
        513030xC8671Apparent power phase 2 : S2VA / 0.1U16
        513040xC8681Apparent power phase 3 : S3VA / 0.1U16
        513050xC8691Power Factor phase 1 -: leading and + : lagging : PF1- / 1000S16
        513060xC86A1Power Factor phase 2 -: leading and + : lagging : PF2- / 1000S16
        513070xC86B1Power Factor phase 3 -: leading and + : lagging : PF3- / 1000S16
        513080xC86C1Reserved - -
        513090xC86D1Reserved - -
        513100xC86E1Reserved - -
        513110xC86F1Total Positive Active Energy (no resetable) : Ea+Wh / 1E-06U16
        513120xC8701Total Positive Reactive Energy (no resetable) : Er +varh / 1E-06U16
        513130xC8711Total Negative Active Energy (no resetable) : Ea-Wh / 1E-06U16
        513140xC8721Total Negative Reactive Energy (no resetable) : Er -varh / 1E-06U16


        Specific


        + + + + + + + + + + + + + + + + + + + +
        +

        Table Overflow


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        368640x9000Info11NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        368640x90002Value of the meter overflow (10Wh) : 999 999 999Wh / 0.1U32
        368660x90021Nb Overflow Total Ea +-U16
        368670x90031Nb Overflow Total Er +-U16
        368680x90041Nb Overflow Total Ea --U16
        368690x90051Nb Overflow Total Er --U16
        368700x90061Reserved - -
        368710x90071Nb Overflow Total Ea T1-U16
        368720x90081Nb Overflow Total Ea T2-U16
        368730x90091Nb Overflow Total Ea T3-U16
        368740x900A1Nb Overflow Total Ea T4-U8

        + + + + + + + + + + + + + + + + + + + +
        +

        Temporal Active Index


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        368960x9020Info24NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        368960x90202Ea + for day n-1Wh / 0.001U32
        368980x90222Reserved - -
        369000x90242Ea + for day nWh / 0.001U32
        369020x90262Reserved - -
        369040x90282Ea + for Week n-1Wh / 0.001U32
        369060x902A2Reserved - -
        369080x902C2Ea + for Week nWh / 0.001U32
        369100x902E2Reserved - -
        369120x90302Ea + for Month n-1Wh / 0.001U32
        369140x90322Reserved - -
        369160x90342Ea + for Month nWh / 0.001U32
        369180x90362Reserved - -

        + + + + + + + + + + + + + + + + + + + +
        +

        Temporal Active Index in Unit/100


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        369280x9040Info24NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        369280x90402Ea + for day n-1Wh / 0.1U32
        369300x90422Reserved - -
        369320x90442Ea + for day nWh / 0.1U32
        369340x90462Reserved - -
        369360x90482Ea + for Week n-1Wh / 0.1U32
        369380x904A2Reserved - -
        369400x904C2Ea + for Week nWh / 0.1U32
        369420x904E2Reserved - -
        369440x90502Ea + for Month n-1Wh / 0.1U32
        369460x90522Reserved - -
        369480x90542Ea + for Month nWh / 0.1U32
        369500x90562Reserved - -

        + + + + + + + + + + + + + + + + + + + +
        +

        Energies (Full scale)


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        373760x9200Info43NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        373760x92004Total Positive Active Energy (no resetable) : Ea+Wh / 0.001U64
        373800x92044Total Positive Reactive Energy (no resetable) : Er +varh / 0.001U64
        373840x92084Reserved - -
        373880x920C4Total Negative Active Energy (no resetable) : Ea-Wh / 0.001U64
        373920x92104Total Negative Reactive Energy (no resetable) : Er -varh / 0.001U64
        373960x92144Partial Positive Active Energy: Ea+Wh / 0.001U64
        374000x92184Partial Positive Reactive Energy: Er +varh / 0.001U64
        374040x921C4Reserved - -
        374080x92204Partial Negative Active Energy : Ea-Wh / 0.001U64
        374120x92244Partial Negative Reactive Energy : Er -varh / 0.001U64
        374160x92282Last date for Record average P in second since 01/01/2000sU32
        374180x922A1Last average P+WU16

        + + + + + + + + + + + + + + + + + + + +
        +

        Energies per tariff (Full scale)


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        376320x9300Info34NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        376320x930010 > Tariff number <= 4-U8
        376330x93011Tariff number in progress (1 to 4)-U8
        376340x93024Total Positive Active Energie Tariff 1Wh / 0.001U64
        376380x93064Total Positive Active Energie Tariff 2Wh / 0.001U64
        376420x930A4Total Positive Active Energie Tariff 3Wh / 0.001U64
        376460x930E4Total Positive Active Energie Tariff 4Wh / 0.001U64
        376500x93124Partial Positive Active Energie Tariff 1Wh / 0.001U64
        376540x93164Partial Positive Active Energie Tariff 2Wh / 0.001U64
        376580x931A4Partial Positive Active Energie Tariff 3Wh / 0.001U64
        376620x931E4Partial Positive Active Energie Tariff 4Wh / 0.001U64

        + + + + + + + + + + + + + + + + + + + +
        +

        Energies in Unit/100 (Full scale)


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        378880x9400Info43NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        378880x94004Total Positive Active Energy (no resetable) : Ea+Wh / 0.1U64
        378920x94044Total Positive Reactive Energy (no resetable) : Er +varh / 0.1U64
        378960x94084Reserved - -
        379000x940C4Total Negative Active Energy (no resetable) : Ea-Wh / 0.1U64
        379040x94104Total Negative Reactive Energy (no resetable) : Er -varh / 0.1U64
        379080x94144Partial Positive Active Energy: Ea+Wh / 0.1U64
        379120x94184Partial Positive Reactive Energy: Er +varh / 0.1U64
        379160x941C4Reserved - -
        379200x94204Partial Negative Active Energy : Ea-Wh / 0.1U64
        379240x94244Partial Negative Reactive Energy : Er -varh / 0.1U64
        379280x94282Last date for Record average P in second since 01/01/2000sU32
        379300x942A1Last average P+WU16

        + + + + + + + + + + + + + + + + + + + +
        +

        Energies per tariff in Unit/100 (Full scale)


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        381440x9500Info34NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        381440x950010 > Tariff number <= 4-U8
        381450x95011Tariff number in progress (1 to 4)-U8
        381460x95024Total Positive Active Energie Tariff 1Wh / 0.1U64
        381500x95064Total Positive Active Energie Tariff 2Wh / 0.1U64
        381540x950A4Total Positive Active Energie Tariff 3Wh / 0.1U64
        381580x950E4Total Positive Active Energie Tariff 4Wh / 0.1U64
        381620x95124Partial Positive Active Energie Tariff 1Wh / 0.1U64
        381660x95164Partial Positive Active Energie Tariff 2Wh / 0.1U64
        381700x951A4Partial Positive Active Energie Tariff 3Wh / 0.1U64
        381740x951E4Partial Positive Active Energie Tariff 4Wh / 0.1U64

        + + + + + + + + + + + + + + + + + + + +
        +

        Maximum Values


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        371200x9100Info20NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        371200x91002Maximum I1A / 1000U32
        371220x91022Maximum I2A / 1000U32
        371240x91042Maximum I3A / 1000U32
        371260x91062Maximum InA / 1000U32
        371280x91082Maximum P+W / 1000U32
        371300x910A2Maximum P-W / 1000U32
        371320x910C2Maximum Q+var / 1000U32
        371340x910E2Maximum Q-var / 1000U32
        371360x91102Maximum SVA / 1000U32
        371380x91121Maximum cos(phi)+- / 1000U16
        371390x91131Maximum cos(phi)-- / 1000U16


        Settings


        + + + + + + + + + + + + + + + + + + + +
        +

        Set Tariff


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        386560x9700Commands1NONEWRITEWRITE

        + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        386560x97001Set Tariff (1 to 4)-U8


        Actions


        + + + + + + + + + + + + + + + + + + + +
        +

        Partial reset


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        405120x9E40Commands1NONEWRITEWRITE

        + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        405120x9E401Reset Partial (mix values is possible):
        0x0001 : Tariff 1 positive active energy (Ea+)
        0x0002 : Tariff 2 positive active energy (Ea+)
        0x0004 : Tariff 3 positive active energy (Ea+)
        0x0008 : Tariff 4 positive active energy (Ea+)
        0x0010 : Negative active energy (Ea-)
        0x0020 : Positive reactive energy (Er+)
        0x0040 : Negative reactive energy (Er-)
        0x000F : All partial energies per tariff
        0xFFFF : All partial energies
        -U16_HEX

        + + + + + + + + + + + + + + + + + + + +
        +

        Maximum reset


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        405130x9E41Commands1NONEWRITEWRITE

        + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        405130x9E411Reset Max (mix values is possible):
        0x0001 : Max of phase 1 current (I1)
        0x0002 : Max of phase 2 current (I2)
        0x0004 : Max of phase 3 current (I3)
        0x0008 : Max of phase N current (IN)
        0x0010 : Max of positive active power (P+)
        0x0020 : Max of negative active power (P-)
        0x0040 : Max of positive reactive power (Q+)
        0x0080 : Max of positive reactive power (Q-)
        0x0100 : Max of apparent power (S)
        0x0200 : Max of positive cos(phi)
        0x0400 : Max of negative cos(phi)
        0xFFFF : All max
        -U16_HEX



        Monitoring


        Quality


        + + + + + + + + + + + + + + + + + + + +
        +

        Quality Values


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        384000x9600Info22NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        384000x96002THD Value for I1% / 100U32
        384020x96022THD Value for I2% / 100U32
        384040x96042THD Value for I3% / 100U32
        384060x96062THD Value for V1% / 100U32
        384080x96082THD Value for V2% / 100U32
        384100x960A2THD Value for V3% / 100U32
        384120x960C2THD Value for U12% / 100U32
        384140x960E2THD Value for U23% / 100U32
        384160x96102THD Value for U31% / 100U32
        384180x96121cos(phi) L1- / 1000S16
        384190x96131cos(phi) L2- / 1000S16
        384200x96141cos(phi) L3- / 1000S16
        384210x96151cos(phi) Total- / 1000S16


        Load Curve


        +

        Load curve P+

        + +
        + + + + + + + + + + + + + + + + + + +
        +

        Command

        +
        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        614400xF000Command1NONEWRITE_MANYWRITE_MANY
        +
        + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        614400xF0001Action
        0x0001 : Reset read pointer
        0xFFFE : Get next data
        -U16_HEX
        +
        + + + + + + + + + + + + + + + + + + +
        +

        Header

        +
        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        614560xF010Header6NONEREADREAD
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        614560xF0101Record count ( Maximum 29 )-U8
        614570xF0111Record size : 4 see below the data record descriptionWU8
        614580xF0121Integration periodminU16
        614590xF0131Physical Unit : 0
        0 : W
        1 : W
        2 : var
        3 : var
        4 : VA
        5 : None
        6 : J
        7 : Pulse
        8 : m3
        9 : Nm3
        20 : kW
        22 : kVAr
        24 : kVA
        26 : kJ
        27 : kilo-Pulse
        -U8
        614600xF0141Numerator Rate-U16
        614610xF0151Denominator Rate-U16
        +
        + + + + + + + + + + + + + + + + + + +
        +

        Data

        +
        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        614620xF016Data4NONEREADREAD
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        614620xF0162DatesDATETIME
        614640xF0181Full/incomplete period
        0 : full integration period
        1 : incomplete integration period
        -U8
        614650xF0191Value without CT*VT rate-U16




        Industrialization


        + + + + + + + + + + + + + + + + + + + +
        +

        Indus Mode and MID status


        Dec start addressHex start addressTypeSizeLock levelLocked fctsUnlocked fcts
        405440x9E60Info2NONEREADREAD

        + + + + + + + + + + + + + + + + + + + + + + + + +
        Dec addressHex addressWords countDescriptionUnitData type
        405440x9E601Indus Mode (0: indus mode disabled, 1: indus mode enabled)-U8
        405450x9E611MID status (0: non-MID product, 1: MID product-U8


        + + \ No newline at end of file diff --git a/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/Config.java b/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/Config.java index 18adb33329f..6afe4e54751 100644 --- a/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/Config.java +++ b/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/Config.java @@ -3,6 +3,8 @@ import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import io.openems.edge.meter.api.MeterType; + @ObjectClassDefinition( // name = "Meter SOCOMEC Diris A14", // description = "Implements the SOCOMEC Diris A14 meter.") @@ -13,8 +15,8 @@ boolean enabled() default true; - @AttributeDefinition(name = "Meter-Type", description = "Grid, Production (=default), Consumption") - String type() default "production"; + @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") + MeterType type() default MeterType.PRODUCTION; @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus brige.") String modbus_id(); diff --git a/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/MeterSocomecDirisA14.java b/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/MeterSocomecDirisA14.java index 21c186973d5..70661c92f3c 100644 --- a/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/MeterSocomecDirisA14.java +++ b/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/MeterSocomecDirisA14.java @@ -20,13 +20,12 @@ import io.openems.edge.bridge.modbus.api.element.SignedDoublewordElement; import io.openems.edge.bridge.modbus.api.element.UnsignedDoublewordElement; import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask; -import io.openems.edge.bridge.modbus.api.task.Priority; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.meter.api.Meter; +import io.openems.edge.common.taskmanager.Priority; +import io.openems.edge.meter.api.AsymmetricMeter; import io.openems.edge.meter.api.MeterType; -import io.openems.edge.meter.asymmetric.api.AsymmetricMeter; -import io.openems.edge.meter.symmetric.api.SymmetricMeter; +import io.openems.edge.meter.api.SymmetricMeter; /** * Implements the SOCOMEC Diris A14 meter @@ -34,7 +33,7 @@ @Designate(ocd = Config.class, factory = true) @Component(name = "Meter.SOCOMEC.DirisA14", immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE) public class MeterSocomecDirisA14 extends AbstractOpenemsModbusComponent - implements SymmetricMeter, AsymmetricMeter, Meter, OpenemsComponent { + implements SymmetricMeter, AsymmetricMeter, OpenemsComponent { private MeterType meterType = MeterType.PRODUCTION; @@ -52,12 +51,7 @@ protected void setModbus(BridgeModbus modbus) { @Activate void activate(ComponentContext context, Config config) { - // get Meter Type: - try { - this.meterType = MeterType.valueOf(config.type().toUpperCase()); - } catch (IllegalArgumentException e) { - this.meterType = MeterType.PRODUCTION; // default - } + this.meterType = config.type(); super.activate(context, config.service_pid(), config.id(), config.enabled(), config.modbusUnitId(), this.cm, "Modbus", config.modbus_id()); @@ -102,7 +96,7 @@ protected ModbusProtocol defineModbusProtocol(int unitId) { ElementToChannelConverter.SCALE_FACTOR_1), m(AsymmetricMeter.ChannelId.VOLTAGE_L3, new UnsignedDoublewordElement(0xc55C), ElementToChannelConverter.SCALE_FACTOR_1), - m(Meter.ChannelId.FREQUENCY, new UnsignedDoublewordElement(0xc55E), + m(SymmetricMeter.ChannelId.FREQUENCY, new UnsignedDoublewordElement(0xc55E), ElementToChannelConverter.SCALE_FACTOR_1), m(AsymmetricMeter.ChannelId.CURRENT_L1, new UnsignedDoublewordElement(0xc560)), m(AsymmetricMeter.ChannelId.CURRENT_L2, new UnsignedDoublewordElement(0xc562)), @@ -126,6 +120,12 @@ protected ModbusProtocol defineModbusProtocol(int unitId) { ElementToChannelConverter.SCALE_FACTOR_1), m(AsymmetricMeter.ChannelId.REACTIVE_POWER_L3, new UnsignedDoublewordElement(0xc57A), ElementToChannelConverter.SCALE_FACTOR_1) // + ), new FC3ReadRegistersTask(0xC702, Priority.LOW, // + m(SymmetricMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, new UnsignedDoublewordElement(0xC702), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // + new DummyRegisterElement(0xC704, 0xC707), // PRODUCTION_REACTIVE_ENERGY + m(SymmetricMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY, new UnsignedDoublewordElement(0xC708), + ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // )); } diff --git a/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/Utils.java b/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/Utils.java index bade7be6d16..56da4f22930 100644 --- a/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/Utils.java +++ b/io.openems.edge.meter.socomec.dirisa14/src/io/openems/edge/meter/socomec/dirisa14/Utils.java @@ -5,11 +5,10 @@ import io.openems.edge.common.channel.AbstractReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.meter.api.Meter; -import io.openems.edge.meter.asymmetric.api.AsymmetricMeter; -import io.openems.edge.meter.symmetric.api.SymmetricMeter; +import io.openems.edge.meter.api.AsymmetricMeter; +import io.openems.edge.meter.api.SymmetricMeter; public class Utils { public static Stream> initializeChannels(MeterSocomecDirisA14 c) { @@ -17,27 +16,20 @@ public static Stream> initializeChannels(MeterS Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); - } - return null; - }), Arrays.stream(Meter.ChannelId.values()).map(channelId -> { - switch (channelId) { - case FREQUENCY: - return new IntegerReadChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; }), Arrays.stream(SymmetricMeter.ChannelId.values()).map(channelId -> { switch (channelId) { + case FREQUENCY: case ACTIVE_POWER: case MAX_ACTIVE_POWER: case MIN_ACTIVE_POWER: case REACTIVE_POWER: - case CONSUMPTION_ACTIVE_POWER: - case CONSUMPTION_REACTIVE_POWER: - case PRODUCTION_ACTIVE_POWER: - case PRODUCTION_REACTIVE_POWER: case CURRENT: case VOLTAGE: + case ACTIVE_CONSUMPTION_ENERGY: + case ACTIVE_PRODUCTION_ENERGY: return new IntegerReadChannel(c, channelId); } return null; @@ -46,18 +38,6 @@ public static Stream> initializeChannels(MeterS case ACTIVE_POWER_L1: case ACTIVE_POWER_L2: case ACTIVE_POWER_L3: - case CONSUMPTION_ACTIVE_POWER_L1: - case CONSUMPTION_ACTIVE_POWER_L2: - case CONSUMPTION_ACTIVE_POWER_L3: - case CONSUMPTION_REACTIVE_POWER_L1: - case CONSUMPTION_REACTIVE_POWER_L2: - case CONSUMPTION_REACTIVE_POWER_L3: - case PRODUCTION_ACTIVE_POWER_L1: - case PRODUCTION_ACTIVE_POWER_L2: - case PRODUCTION_ACTIVE_POWER_L3: - case PRODUCTION_REACTIVE_POWER_L1: - case PRODUCTION_REACTIVE_POWER_L2: - case PRODUCTION_REACTIVE_POWER_L3: case REACTIVE_POWER_L1: case REACTIVE_POWER_L2: case REACTIVE_POWER_L3: diff --git a/io.openems.edge.meter.socomec.dirisa14/test/.gitignore b/io.openems.edge.meter.socomec.dirisa14/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.scheduler.allalphabetically/test/.gitignore b/io.openems.edge.scheduler.allalphabetically/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.scheduler.fixedorder/test/.gitignore b/io.openems.edge.scheduler.fixedorder/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.simulator/bnd.bnd b/io.openems.edge.simulator/bnd.bnd index c4558d7a64f..e331f14dc08 100644 --- a/io.openems.edge.simulator/bnd.bnd +++ b/io.openems.edge.simulator/bnd.bnd @@ -10,6 +10,15 @@ Private-Package: \ io.openems.edge.simulator.ess,\ io.openems.edge.simulator.ess.symmetric.reacting +Export-Package: io.openems.edge.ess.api,\ + io.openems.edge.ess.symmetric.api,\ + io.openems.edge.ess.symmetric.readonly.api,\ + io.openems.edge.ess.dccharger.api,\ + io.openems.edge.ess.asymmetric.api,\ + io.openems.edge.ess.power.api,\ + io.openems.edge.battery.api,\ + io.openems.edge.simulator.battery + -includeresource: {readme.md} -buildpath: \ @@ -18,8 +27,10 @@ Private-Package: \ io.openems.common;version=latest,\ io.openems.edge.common;version=latest,\ io.openems.edge.ess.api;version=latest,\ - com.google.guava + com.google.guava,\ + io.openems.edge.battery.api;version=latest -testpath: \ osgi.enroute.junit.wrapper;version=4.12, \ osgi.enroute.hamcrest.wrapper;version=1.3 +-runbundles: org.apache.felix.log;version='[1.0.1,1.0.2)' diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/BatteryDummy.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/BatteryDummy.java new file mode 100644 index 00000000000..276ee28eeb6 --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/BatteryDummy.java @@ -0,0 +1,58 @@ +package io.openems.edge.simulator.battery; + +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.ConfigurationPolicy; +import org.osgi.service.event.Event; +import org.osgi.service.event.EventConstants; +import org.osgi.service.event.EventHandler; +import org.osgi.service.metatype.annotations.Designate; + +import io.openems.edge.battery.api.Battery; +import io.openems.edge.common.component.AbstractOpenemsComponent; +import io.openems.edge.common.component.OpenemsComponent; +import io.openems.edge.common.event.EdgeEventConstants; + +@Designate(ocd = Config.class, factory = true) +@Component( // + name = "Bms.Simulated", // + immediate = true, // + configurationPolicy = ConfigurationPolicy.REQUIRE, // + property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE // +) +public class BatteryDummy extends AbstractOpenemsComponent implements Battery, OpenemsComponent, EventHandler { + + private int capacity_kWh; + + public BatteryDummy() { + Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); + } + + @Activate + void activate(ComponentContext context, Config config) { + super.activate(context, config.service_pid(), config.id(), config.enabled()); + this.capacity_kWh = config.capacity_kWh(); + } + + @Override + public void handleEvent(Event event) { + switch (event.getTopic()) { + case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE: + this.updateChannels(); + break; + } + } + + private void updateChannels() { + this.getChargeMaxCurrent(); + this.getChargeMaxVoltage(); + this.getDischargeMaxCurrent(); + this.getDischargeMinVoltage(); + this.getGridMode(); + this.getMaxCapacity().setNextValue(capacity_kWh);; + this.getSoc().setNextValue(50);; + this.getState(); + } + +} diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/Config.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/Config.java new file mode 100644 index 00000000000..83d160a1c32 --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/Config.java @@ -0,0 +1,18 @@ +package io.openems.edge.simulator.battery; + +import org.osgi.service.metatype.annotations.ObjectClassDefinition; + +@ObjectClassDefinition( // + name = "BMS Simulated", // + description = "Implements a simulated battery management system") +@interface Config { + String service_pid(); + + String id() default "bms0"; + + boolean enabled() default true; + + int capacity_kWh() default 10; + + String webconsole_configurationFactory_nameHint() default "BMS Simulated [{id}]"; +} \ No newline at end of file diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/Utils.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/Utils.java new file mode 100644 index 00000000000..da4b5ccc28e --- /dev/null +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/battery/Utils.java @@ -0,0 +1,38 @@ +package io.openems.edge.simulator.battery; + +import java.util.Arrays; +import java.util.stream.Stream; + +import io.openems.edge.battery.api.Battery; +import io.openems.edge.common.channel.AbstractReadChannel; +import io.openems.edge.common.channel.IntegerReadChannel; +import io.openems.edge.common.channel.StateCollectorChannel; +import io.openems.edge.common.component.OpenemsComponent; + +public class Utils { + public static Stream> initializeChannels(BatteryDummy s) { + // Define the channels. Using streams + switch enables Eclipse IDE to tell us if + // we are missing an Enum value. + return Stream.of( // + Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { + switch (channelId) { + case STATE: + return new StateCollectorChannel(s, channelId); + } + return null; + }), Arrays.stream(Battery.ChannelId.values()).map(channelId -> { + switch (channelId) { + case SOC: + case MAX_CAPACITY: + case GRID_MODE: + case CHARGE_MAX_CURRENT: + case CHARGE_MAX_VOLTAGE: + case DISCHARGE_MAX_CURRENT: + case DISCHARGE_MIN_VOLTAGE: + return new IntegerReadChannel(s, channelId); + } + return null; + }) + ).flatMap(channel -> channel); + } +} diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/ess/EssUtils.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/ess/EssUtils.java index 77f7d07230e..f56fea31a92 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/ess/EssUtils.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/ess/EssUtils.java @@ -5,12 +5,12 @@ import io.openems.edge.common.channel.AbstractReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.ess.api.Ess; -import io.openems.edge.ess.api.Ess.GridMode; -import io.openems.edge.ess.symmetric.api.SymmetricEss; -import io.openems.edge.ess.symmetric.readonly.api.SymmetricEssReadonly; +import io.openems.edge.ess.api.ManagedAsymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.api.SymmetricEss.GridMode; public class EssUtils { public static Stream> initializeChannels(OpenemsComponent c) { @@ -18,33 +18,37 @@ public static Stream> initializeChannels(Openem Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; - }), Arrays.stream(Ess.ChannelId.values()).map(channelId -> { + }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { switch (channelId) { case SOC: case MAX_ACTIVE_POWER: + case ACTIVE_POWER: + case REACTIVE_POWER: + case ACTIVE_CHARGE_ENERGY: + case ACTIVE_DISCHARGE_ENERGY: return new IntegerReadChannel(c, channelId); case GRID_MODE: return new IntegerReadChannel(c, channelId, GridMode.ON_GRID); } return null; - }), Arrays.stream(SymmetricEssReadonly.ChannelId.values()).map(channelId -> { + }), Arrays.stream(ManagedSymmetricEss.ChannelId.values()).map(channelId -> { switch (channelId) { - case ACTIVE_POWER: - case CHARGE_ACTIVE_POWER: - case CHARGE_REACTIVE_POWER: - case DISCHARGE_ACTIVE_POWER: - case DISCHARGE_REACTIVE_POWER: - case REACTIVE_POWER: + case DEBUG_SET_ACTIVE_POWER: + case DEBUG_SET_REACTIVE_POWER: return new IntegerReadChannel(c, channelId, 0); } return null; - }), Arrays.stream(SymmetricEss.ChannelId.values()).map(channelId -> { + }), Arrays.stream(ManagedAsymmetricEss.ChannelId.values()).map(channelId -> { switch (channelId) { - case DEBUG_SET_ACTIVE_POWER: - case DEBUG_SET_REACTIVE_POWER: + case DEBUG_SET_ACTIVE_POWER_L1: + case DEBUG_SET_REACTIVE_POWER_L1: + case DEBUG_SET_ACTIVE_POWER_L2: + case DEBUG_SET_REACTIVE_POWER_L2: + case DEBUG_SET_ACTIVE_POWER_L3: + case DEBUG_SET_REACTIVE_POWER_L3: return new IntegerReadChannel(c, channelId); } return null; diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/ess/symmetric/reacting/EssSymmetric.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/ess/symmetric/reacting/EssSymmetric.java index 129b62b32b7..bd3e4431103 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/ess/symmetric/reacting/EssSymmetric.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/ess/symmetric/reacting/EssSymmetric.java @@ -2,6 +2,7 @@ import java.io.IOException; +import org.apache.commons.math3.optim.linear.Relationship; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -20,11 +21,14 @@ import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.ess.api.Ess; -import io.openems.edge.ess.power.symmetric.PGreaterEqualLimitation; -import io.openems.edge.ess.power.symmetric.PSmallerEqualLimitation; -import io.openems.edge.ess.power.symmetric.SymmetricPower; -import io.openems.edge.ess.symmetric.api.SymmetricEss; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.ess.api.SymmetricEss; +import io.openems.edge.ess.power.api.CircleConstraint; +import io.openems.edge.ess.power.api.Constraint; +import io.openems.edge.ess.power.api.ConstraintType; +import io.openems.edge.ess.power.api.Phase; +import io.openems.edge.ess.power.api.Power; +import io.openems.edge.ess.power.api.Pwr; import io.openems.edge.simulator.datasource.api.SimulatorDatasource; import io.openems.edge.simulator.ess.EssUtils; @@ -33,21 +37,26 @@ immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE, // property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_CONTROLLERS) public class EssSymmetric extends AbstractOpenemsComponent - implements SymmetricEss, Ess, OpenemsComponent, EventHandler { + implements ManagedSymmetricEss, SymmetricEss, OpenemsComponent, EventHandler { - // private final Logger log = LoggerFactory.getLogger(EssSymmetric.class); - - private final static int POWER_PRECISION = 1; - - private SymmetricPower power = null; - private PGreaterEqualLimitation allowedChargeLimit; - private PSmallerEqualLimitation allowedDischargeLimit; + private Constraint allowedChargeConstraint; + private Constraint allowedDischargeConstraint; /** * Current state of charge */ private float soc = 0; + /** + * Total configured capacity in Wh + */ + private int capacity = 0; + + /** + * Configured max Apparent Power in VA + */ + private int maxApparentPower = 0; + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { ; private final Doc doc; @@ -61,6 +70,9 @@ public Doc doc() { } } + @Reference + private Power power; + @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY) protected SimulatorDatasource datasource; @@ -69,63 +81,20 @@ void activate(ComponentContext context, Config config) throws IOException { super.activate(context, config.service_pid(), config.id(), config.enabled()); this.getSoc().setNextValue(config.initialSoc()); this.soc = config.initialSoc(); + this.capacity = config.capacity(); + this.maxApparentPower = config.maxApparentPower(); this.getMaxActivePower().setNextValue(config.maxApparentPower()); /* * Initialize Power */ - this.power = new SymmetricPower(this, config.maxApparentPower(), EssSymmetric.POWER_PRECISION, // - (activePower, reactivePower) -> { - /* - * calculate State of charge - */ - float watthours = (float) activePower * this.datasource.getTimeDelta() / 3600; - float socChange = watthours / config.capacity(); - this.soc -= socChange; - if (this.soc > 100) { - this.soc = 100; - } else if (this.soc < 0) { - this.soc = 0; - } - this.getSoc().setNextValue(this.soc); - /* - * Apply Active/Reactive power to simulated channels - */ - if (soc == 0 && activePower > 0) { - activePower = 0; - } - if (soc == 100 && activePower < 0) { - activePower = 0; - } - this.getActivePower().setNextValue(activePower); - if (soc == 0 && reactivePower > 0) { - reactivePower = 0; - } - if (soc == 100 && reactivePower < 0) { - reactivePower = 0; - } - this.getReactivePower().setNextValue(reactivePower); - /* - * Set AllowedCharge / Discharge based on SoC - */ - if (this.soc == 100) { - this.allowedChargeLimit.setP(0); - } else { - this.allowedChargeLimit.setP(config.maxApparentPower() * -1); - } - if (this.soc == 0) { - this.allowedDischargeLimit.setP(0); - } else { - this.allowedDischargeLimit.setP(config.maxApparentPower()); - } - }); + // Max Apparent Power + new CircleConstraint(this, this.maxApparentPower); // Allowed Charge - this.power.addStaticLimitation( // - this.allowedChargeLimit = new PGreaterEqualLimitation(this.power) // - ); + this.allowedChargeConstraint = this.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, + Relationship.GEQ, 0 /* initial zero; is set later */); // Allowed Discharge - this.power.addStaticLimitation( // - this.allowedDischargeLimit = new PSmallerEqualLimitation(this.power) // - ); + this.allowedDischargeConstraint = this.addPowerConstraint(ConstraintType.STATIC, Phase.ALL, Pwr.ACTIVE, + Relationship.LEQ, 0 /* initial zero; is set later */); } @Deactivate @@ -158,7 +127,58 @@ public String debugLog() { } @Override - public SymmetricPower getPower() { + public Power getPower() { return this.power; } + + @Override + public void applyPower(int activePower, int reactivePower) { + /* + * calculate State of charge + */ + float watthours = (float) activePower * this.datasource.getTimeDelta() / 3600; + float socChange = watthours / this.capacity; + this.soc -= socChange; + if (this.soc > 100) { + this.soc = 100; + } else if (this.soc < 0) { + this.soc = 0; + } + this.getSoc().setNextValue(this.soc); + /* + * Apply Active/Reactive power to simulated channels + */ + if (soc == 0 && activePower > 0) { + activePower = 0; + } + if (soc == 100 && activePower < 0) { + activePower = 0; + } + this.getActivePower().setNextValue(activePower); + if (soc == 0 && reactivePower > 0) { + reactivePower = 0; + } + if (soc == 100 && reactivePower < 0) { + reactivePower = 0; + } + this.getReactivePower().setNextValue(reactivePower); + /* + * Set AllowedCharge / Discharge based on SoC + */ + if (this.soc == 100) { + this.allowedChargeConstraint.setIntValue(0); + } else { + this.allowedChargeConstraint.setIntValue(this.maxApparentPower * -1); + } + if (this.soc == 0) { + this.allowedDischargeConstraint.setIntValue(0); + } else { + this.allowedDischargeConstraint.setIntValue(this.maxApparentPower); + } + } + + @Override + public int getPowerPrecision() { + return 1; + } } diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/MeterUtils.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/MeterUtils.java index c1af7ac866c..cd2a5990533 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/MeterUtils.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/MeterUtils.java @@ -5,11 +5,10 @@ import io.openems.edge.common.channel.AbstractReadChannel; import io.openems.edge.common.channel.IntegerReadChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; -import io.openems.edge.meter.api.Meter; -import io.openems.edge.meter.asymmetric.api.AsymmetricMeter; -import io.openems.edge.meter.symmetric.api.SymmetricMeter; +import io.openems.edge.meter.api.AsymmetricMeter; +import io.openems.edge.meter.api.SymmetricMeter; import io.openems.edge.simulator.meter.grid.acting.GridMeter; public class MeterUtils { @@ -18,27 +17,20 @@ public static Stream> initializeChannels(Openem Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); - } - return null; - }), Arrays.stream(Meter.ChannelId.values()).map(channelId -> { - switch (channelId) { - case FREQUENCY: - return new IntegerReadChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; }), Arrays.stream(SymmetricMeter.ChannelId.values()).map(channelId -> { switch (channelId) { + case FREQUENCY: case ACTIVE_POWER: case MAX_ACTIVE_POWER: case MIN_ACTIVE_POWER: case REACTIVE_POWER: - case CONSUMPTION_ACTIVE_POWER: - case CONSUMPTION_REACTIVE_POWER: - case PRODUCTION_ACTIVE_POWER: - case PRODUCTION_REACTIVE_POWER: case CURRENT: case VOLTAGE: + case ACTIVE_PRODUCTION_ENERGY: + case ACTIVE_CONSUMPTION_ENERGY: return new IntegerReadChannel(c, channelId); } return null; @@ -47,18 +39,6 @@ public static Stream> initializeChannels(Openem case ACTIVE_POWER_L1: case ACTIVE_POWER_L2: case ACTIVE_POWER_L3: - case CONSUMPTION_ACTIVE_POWER_L1: - case CONSUMPTION_ACTIVE_POWER_L2: - case CONSUMPTION_ACTIVE_POWER_L3: - case CONSUMPTION_REACTIVE_POWER_L1: - case CONSUMPTION_REACTIVE_POWER_L2: - case CONSUMPTION_REACTIVE_POWER_L3: - case PRODUCTION_ACTIVE_POWER_L1: - case PRODUCTION_ACTIVE_POWER_L2: - case PRODUCTION_ACTIVE_POWER_L3: - case PRODUCTION_REACTIVE_POWER_L1: - case PRODUCTION_REACTIVE_POWER_L2: - case PRODUCTION_REACTIVE_POWER_L3: case REACTIVE_POWER_L1: case REACTIVE_POWER_L2: case REACTIVE_POWER_L3: diff --git a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/GridMeter.java b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/GridMeter.java index 769dec29b14..04961ebe1c7 100644 --- a/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/GridMeter.java +++ b/io.openems.edge.simulator/src/io/openems/edge/simulator/meter/grid/acting/GridMeter.java @@ -26,11 +26,10 @@ import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; -import io.openems.edge.ess.symmetric.api.SymmetricEss; -import io.openems.edge.meter.api.Meter; +import io.openems.edge.ess.api.ManagedSymmetricEss; +import io.openems.edge.meter.api.AsymmetricMeter; import io.openems.edge.meter.api.MeterType; -import io.openems.edge.meter.asymmetric.api.AsymmetricMeter; -import io.openems.edge.meter.symmetric.api.SymmetricMeter; +import io.openems.edge.meter.api.SymmetricMeter; import io.openems.edge.simulator.datasource.api.SimulatorDatasource; import io.openems.edge.simulator.meter.MeterUtils; @@ -39,7 +38,7 @@ immediate = true, configurationPolicy = ConfigurationPolicy.REQUIRE, // property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE) public class GridMeter extends AbstractOpenemsComponent - implements SymmetricMeter, AsymmetricMeter, Meter, OpenemsComponent, EventHandler { + implements SymmetricMeter, AsymmetricMeter, OpenemsComponent, EventHandler { // private final Logger log = LoggerFactory.getLogger(GridMeter.class); @@ -63,7 +62,7 @@ public Doc doc() { protected SimulatorDatasource datasource; @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) - private volatile List symmetricEsss = new CopyOnWriteArrayList<>(); + private volatile List symmetricEsss = new CopyOnWriteArrayList<>(); // @Reference(policy = ReferencePolicy.DYNAMIC, policyOption = // ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MULTIPLE) @@ -117,7 +116,7 @@ private void updateChannels() { * Calculate Active Power */ int activePower = simulatedActivePower; - for (SymmetricEss ess : this.symmetricEsss) { + for (ManagedSymmetricEss ess : this.symmetricEsss) { Optional essPowerOpt = ess.getActivePower().value().asOptional(); if (essPowerOpt.isPresent()) { activePower -= essPowerOpt.get(); @@ -128,14 +127,6 @@ private void updateChannels() { this.getActivePowerL1().setNextValue(activePower / 3); this.getActivePowerL2().setNextValue(activePower / 3); this.getActivePowerL3().setNextValue(activePower / 3); - this.getProductionActivePower().setNextValue(activePower); - this.getProductionActivePowerL1().setNextValue(activePower / 3); - this.getProductionActivePowerL2().setNextValue(activePower / 3); - this.getProductionActivePowerL3().setNextValue(activePower / 3); - this.getConsumptionActivePower().setNextValue(0); - this.getConsumptionActivePowerL1().setNextValue(0); - this.getConsumptionActivePowerL2().setNextValue(0); - this.getConsumptionActivePowerL3().setNextValue(0); } @Override diff --git a/io.openems.edge.simulator/test/.gitignore b/io.openems.edge.simulator/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/Timedata.java b/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/Timedata.java index 90831e5119e..4bbbcf667aa 100644 --- a/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/Timedata.java +++ b/io.openems.edge.timedata.api/src/io/openems/edge/timedata/api/Timedata.java @@ -1,24 +1,13 @@ package io.openems.edge.timedata.api; -import java.time.Period; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; - import org.osgi.annotation.versioning.ProviderType; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; - -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.utils.JsonUtils; +import io.openems.common.timedata.CommonTimedataService; import io.openems.edge.common.channel.doc.Doc; import io.openems.edge.common.component.OpenemsComponent; @ProviderType -public interface Timedata extends OpenemsComponent { - - // TODO merge this Service with the corresponding Backend Service +public interface Timedata extends CommonTimedataService, OpenemsComponent { public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { ; @@ -34,35 +23,4 @@ public Doc doc() { } } - /** - * TODO copied from backend.timedata.api - * - * @param jHistoricData - * @return - * @throws OpenemsException - */ - default JsonArray queryHistoricData(JsonObject jHistoricData) throws OpenemsException { - int timezoneDiff = JsonUtils.getAsInt(jHistoricData, "timezone"); - ZoneId timezone = ZoneId.ofOffset("", ZoneOffset.ofTotalSeconds(timezoneDiff * -1)); - ZonedDateTime fromDate = JsonUtils.getAsZonedDateTime(jHistoricData, "fromDate", timezone); - ZonedDateTime toDate = JsonUtils.getAsZonedDateTime(jHistoricData, "toDate", timezone).plusDays(1); - JsonObject channels = JsonUtils.getAsJsonObject(jHistoricData, "channels"); - // TODO check if role is allowed to read these channels - // JsonObject kWh = JsonUtils.getAsJsonObject(jQuery, "kWh"); - int days = Period.between(fromDate.toLocalDate(), toDate.toLocalDate()).getDays(); - // TODO better calculation of sensible resolution - int resolution = 10 * 60; // 10 Minutes - if (days > 25) { - resolution = 24 * 60 * 60; // 1 Day - } else if (days > 6) { - resolution = 3 * 60 * 60; // 3 Hours - } else if (days > 2) { - resolution = 60 * 60; // 60 Minutes - } - return this.queryHistoricData(fromDate, toDate, channels, resolution); - } - - public JsonArray queryHistoricData(ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, - int resolution/* , JsonObject kWh */) throws OpenemsException; - } diff --git a/io.openems.edge.timedata.influxdb/bnd.bnd b/io.openems.edge.timedata.influxdb/bnd.bnd index 10d98fd6577..1070186061c 100644 --- a/io.openems.edge.timedata.influxdb/bnd.bnd +++ b/io.openems.edge.timedata.influxdb/bnd.bnd @@ -14,6 +14,7 @@ Private-Package: \ io.openems.edge.common;version=latest,\ io.openems.edge.timedata.api;version=latest,\ com.google.gson,\ + io.openems.shared.influxdb;version=latest,\ io.openems.wrapper.influxdb-java;version=latest -testpath: \ diff --git a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/InfluxTimedata.java b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/InfluxTimedata.java index ba3fa7e39e7..62455961984 100644 --- a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/InfluxTimedata.java +++ b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/InfluxTimedata.java @@ -1,25 +1,15 @@ package io.openems.edge.timedata.influxdb; -import java.time.Instant; import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; import java.util.List; -import java.util.Map.Entry; import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.influxdb.BatchOptions; import org.influxdb.InfluxDB; -import org.influxdb.InfluxDBFactory; import org.influxdb.dto.Point; import org.influxdb.dto.Point.Builder; -import org.influxdb.dto.Query; -import org.influxdb.dto.QueryResult; -import org.influxdb.dto.QueryResult.Result; -import org.influxdb.dto.QueryResult.Series; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; @@ -37,19 +27,16 @@ import org.slf4j.LoggerFactory; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonNull; import com.google.gson.JsonObject; import io.openems.common.exceptions.OpenemsException; -import io.openems.common.types.ChannelAddress; -import io.openems.common.utils.JsonUtils; +import io.openems.common.timedata.Tag; import io.openems.edge.common.channel.doc.Doc; -import io.openems.edge.common.channel.doc.Level; import io.openems.edge.common.component.AbstractOpenemsComponent; import io.openems.edge.common.component.OpenemsComponent; import io.openems.edge.common.event.EdgeEventConstants; import io.openems.edge.timedata.api.Timedata; +import io.openems.shared.influxdb.InfluxConnector; /** * Provides read and write access to InfluxDB. @@ -61,17 +48,12 @@ property = EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE) public class InfluxTimedata extends AbstractOpenemsComponent implements Timedata, OpenemsComponent, EventHandler { - protected final static String MEASUREMENT = "data"; - private final Logger log = LoggerFactory.getLogger(InfluxTimedata.class); - public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { - /** - * FAULT: Unable to connect to InfluxDB - */ - STATE_0(new Doc().level(Level.FAULT).text("Unable to connect to InfluxDB (write)")), // refers to _influxDB1 - STATE_1(new Doc().level(Level.FAULT).text("Unable to connect to InfluxDB (read)")); // refers to _influxDB2 + private InfluxConnector influxConnector = null; + public enum ChannelId implements io.openems.edge.common.channel.doc.ChannelId { + ; private final Doc doc; private ChannelId(Doc doc) { @@ -84,13 +66,6 @@ public Doc doc() { } } - private String ip; - private int port; - private String username; - private String password; - private String database; - private InfluxDB _influxDB = null; - public InfluxTimedata() { Utils.initializeChannels(this).forEach(channel -> this.addChannel(channel)); } @@ -104,14 +79,12 @@ public InfluxTimedata() { @Activate void activate(ComponentContext context, Config config) { super.activate(context, config.service_pid(), config.id(), config.enabled()); - this.ip = config.ip(); - this.port = config.port(); - this.username = config.username(); - this.password = config.password(); - this.database = config.database(); + this.influxConnector = new InfluxConnector(config.ip(), config.port(), config.username(), config.password(), + config.database()); + if (config.enabled()) { try { - this.getConnection(); + this.influxConnector.getConnection(); } catch (OpenemsException e) { logWarn(this.log, e.getMessage()); } @@ -121,8 +94,8 @@ void activate(ComponentContext context, Config config) { @Deactivate protected void deactivate() { super.deactivate(); - if (this._influxDB != null) { - this._influxDB.close(); + if (this.influxConnector != null) { + this.influxConnector.deactivate(); } } @@ -138,147 +111,17 @@ public void handleEvent(Event event) { } } - /** - * Get InfluxDB Connection - * - * @return - */ - protected InfluxDB getConnection() throws OpenemsException { - if (this._influxDB == null) { - try { - InfluxDB influxDB = InfluxDBFactory.connect("http://" + this.ip + ":" + this.port, this.username, - this.password); - influxDB.setDatabase(this.database); - influxDB.enableBatch(BatchOptions.DEFAULTS); - this._influxDB = influxDB; - this.channel(ChannelId.STATE_1).setNextValue(false); - } catch (RuntimeException e) { - this.channel(ChannelId.STATE_1).setNextValue(true); - throw new OpenemsException("Unable to connect to InfluxDB (read): " + e.getMessage(), e); - } - } - return this._influxDB; - } - - /** - * copied from backend.timedata.influx.provider - * - * @param influxdb - * @param database - * @param query - * @return - * @throws OpenemsException - */ - private QueryResult executeQuery(String query) throws OpenemsException { - InfluxDB influxDB = this.getConnection(); - - // Parse result - QueryResult queryResult; - try { - queryResult = influxDB.query(new Query(query, this.database), TimeUnit.MILLISECONDS); - } catch (RuntimeException e) { - throw new OpenemsException("InfluxDB query runtime error. Query: " + query + ", Error: " + e.getMessage()); - } - if (queryResult.hasError()) { - throw new OpenemsException("InfluxDB query error. Query: " + query + ", Error: " + queryResult.getError()); - } - return queryResult; - } - - /** - * copied from backend.timedata.influx.provider - * - * @param influxdb - * @param database - * @param influxIdOpt - * @param fromDate - * @param toDate - * @param channels - * @param resolution - * @return - * @throws OpenemsException - */ - public JsonArray queryHistoricData(ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, - int resolution) throws OpenemsException { - // Prepare query string - StringBuilder query = new StringBuilder("SELECT "); - query.append(Utils.toChannelAddressList(channels)); - query.append(" FROM data WHERE "); - query.append("time > "); - query.append(String.valueOf(fromDate.toEpochSecond())); - query.append("s"); - query.append(" AND time < "); - query.append(String.valueOf(toDate.toEpochSecond())); - query.append("s"); - query.append(" GROUP BY time("); - query.append(resolution); - query.append("s) fill(null)"); - - QueryResult queryResult = executeQuery(query.toString()); - - JsonArray j = new JsonArray(); - for (Result result : queryResult.getResults()) { - List seriess = result.getSeries(); - if (seriess != null) { - for (Series series : seriess) { - // create thing/channel index - ArrayList addressIndex = new ArrayList<>(); - for (String column : series.getColumns()) { - if (column.equals("time")) { - continue; - } - addressIndex.add(ChannelAddress.fromString(column)); - } - // first: create empty timestamp objects - for (List values : series.getValues()) { - JsonObject jTimestamp = new JsonObject(); - // get timestamp - Instant timestampInstant = Instant.ofEpochMilli((long) ((Double) values.get(0)).doubleValue()); - ZonedDateTime timestamp = ZonedDateTime.ofInstant(timestampInstant, fromDate.getZone()); - String timestampString = timestamp.format(DateTimeFormatter.ISO_INSTANT); - jTimestamp.addProperty("time", timestampString); - // add empty channels by copying "channels" parameter - JsonObject jChannels = new JsonObject(); - for (Entry entry : channels.entrySet()) { - String thingId = entry.getKey(); - JsonObject jThing = new JsonObject(); - JsonArray channelIds = JsonUtils.getAsJsonArray(entry.getValue()); - for (JsonElement channelElement : channelIds) { - String channelId = JsonUtils.getAsString(channelElement); - jThing.add(channelId, JsonNull.INSTANCE); - } - jChannels.add(thingId, jThing); - } - jTimestamp.add("channels", jChannels); - j.add(jTimestamp); - } - // then: add all data - for (int columnIndex = 1; columnIndex < series.getColumns().size(); columnIndex++) { - for (int timeIndex = 0; timeIndex < series.getValues().size(); timeIndex++) { - Double value = (Double) series.getValues().get(timeIndex).get(columnIndex); - ChannelAddress address = addressIndex.get(columnIndex - 1); - j.get(timeIndex).getAsJsonObject().get("channels").getAsJsonObject() - .get(address.getComponentId()).getAsJsonObject() - .addProperty(address.getChannelId(), value); - } - } - } - } - } - return j; - } - protected synchronized void collectAndWriteChannelValues() { InfluxDB influxDB; try { - influxDB = this.getConnection(); + influxDB = this.influxConnector.getConnection(); } catch (OpenemsException e) { this.log.error("Not perisisting any data: " + e.getMessage()); return; } long timestamp = System.currentTimeMillis() / 1000; - final Builder point = Point.measurement(InfluxTimedata.MEASUREMENT).time(timestamp, TimeUnit.SECONDS); + final Builder point = Point.measurement(InfluxConnector.MEASUREMENT).time(timestamp, TimeUnit.SECONDS); final AtomicBoolean addedAtLeastOneChannelValue = new AtomicBoolean(false); this.components.stream().filter(c -> c.isEnabled()).forEach(component -> { @@ -326,4 +169,11 @@ protected synchronized void collectAndWriteChannelValues() { influxDB.write(point.build()); } } + + @Override + public JsonArray queryHistoricData(ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, + int resolution, Tag... tags) throws OpenemsException { + // ignore edgeId + return this.influxConnector.queryHistoricData(fromDate, toDate, channels, resolution, tags); + } } diff --git a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Utils.java b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Utils.java index 17332ffc3a1..2485c1dc77a 100644 --- a/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Utils.java +++ b/io.openems.edge.timedata.influxdb/src/io/openems/edge/timedata/influxdb/Utils.java @@ -1,19 +1,10 @@ package io.openems.edge.timedata.influxdb; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Map.Entry; import java.util.stream.Stream; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; - -import io.openems.common.exceptions.OpenemsException; -import io.openems.common.utils.JsonUtils; import io.openems.edge.common.channel.AbstractReadChannel; -import io.openems.edge.common.channel.BooleanReadChannel; -import io.openems.edge.common.channel.StateChannel; +import io.openems.edge.common.channel.StateCollectorChannel; import io.openems.edge.common.component.OpenemsComponent; public class Utils { @@ -22,42 +13,21 @@ public static Stream> initializeChannels(Influx Arrays.stream(OpenemsComponent.ChannelId.values()).map(channelId -> { switch (channelId) { case STATE: - return new StateChannel(c, channelId); + return new StateCollectorChannel(c, channelId); } return null; // }), Arrays.stream(Timedata.ChannelId.values()).map(channelId -> { // switch (channelId) { // } // return null; - }), Arrays.stream(InfluxTimedata.ChannelId.values()).map(channelId -> { - switch (channelId) { - case STATE_0: - case STATE_1: - return new BooleanReadChannel(c, channelId); - } - return null; + // }), Arrays.stream(InfluxTimedata.ChannelId.values()).map(channelId -> { + // switch (channelId) { + // case STATE_0: + // case STATE_1: + // return new BooleanReadChannel(c, channelId); + // } + // return null; }) // ).flatMap(channel -> channel); } - - /** - * TODO: copied from backend.timedata.influx.provider - * - * @param channels - * @return - * @throws OpenemsException - */ - protected static String toChannelAddressList(JsonObject channels) throws OpenemsException { - ArrayList channelAddresses = new ArrayList<>(); - for (Entry entry : channels.entrySet()) { - String thingId = entry.getKey(); - JsonArray channelIds = JsonUtils.getAsJsonArray(entry.getValue()); - for (JsonElement channelElement : channelIds) { - String channelId = JsonUtils.getAsString(channelElement); - channelAddresses - .add("MEAN(\"" + thingId + "/" + channelId + "\") AS \"" + thingId + "/" + channelId + "\""); - } - } - return String.join(", ", channelAddresses); - } } diff --git a/io.openems.edge.timedata.influxdb/test/.gitignore b/io.openems.edge.timedata.influxdb/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.shared.influxdb/.classpath b/io.openems.shared.influxdb/.classpath new file mode 100644 index 00000000000..26009f42341 --- /dev/null +++ b/io.openems.shared.influxdb/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/io.openems.shared.influxdb/.gitignore b/io.openems.shared.influxdb/.gitignore new file mode 100644 index 00000000000..c2b941a96de --- /dev/null +++ b/io.openems.shared.influxdb/.gitignore @@ -0,0 +1,2 @@ +/bin_test/ +/generated/ diff --git a/io.openems.shared.influxdb/bnd.bnd b/io.openems.shared.influxdb/bnd.bnd new file mode 100644 index 00000000000..db30d1bd6a2 --- /dev/null +++ b/io.openems.shared.influxdb/bnd.bnd @@ -0,0 +1,20 @@ +Bundle-Name: OpenEMS Edge Shared InfluxDB +Bundle-Vendor: FENECON GmbH +Bundle-License: https://opensource.org/licenses/EPL-2.0 +Bundle-Version: 1.0.0.${tstamp} + +Export-Package: io.openems.shared.influxdb + + +-includeresource: {readme.md} + +-buildpath: \ + osgi.enroute.base.api;version=2.1,\ + io.openems.wrapper.influxdb-java;version=latest,\ + io.openems.common;version=latest,\ + com.google.gson + +-testpath: \ + osgi.enroute.junit.wrapper;version=4.12, \ + osgi.enroute.hamcrest.wrapper;version=1.3 + diff --git a/io.openems.shared.influxdb/debug.bndrun b/io.openems.shared.influxdb/debug.bndrun new file mode 100644 index 00000000000..bbc3e6869c6 --- /dev/null +++ b/io.openems.shared.influxdb/debug.bndrun @@ -0,0 +1,13 @@ +# +# io.openems.shared.influxdb DEBUG LAUNCH SPECFICATION +# + +-include: ~io.openems.shared.influxdb.bndrun + +-runrequires.debug: \ + ${debug-bundles} + +-runtrace: true + +-runbundles: \ + ${error;Resolve first} diff --git a/io.openems.shared.influxdb/io.openems.shared.influxdb.bndrun b/io.openems.shared.influxdb/io.openems.shared.influxdb.bndrun new file mode 100644 index 00000000000..1060398511b --- /dev/null +++ b/io.openems.shared.influxdb/io.openems.shared.influxdb.bndrun @@ -0,0 +1,14 @@ +# +# io.openems.shared.influxdb LAUNCH SPECIFICATION +# + + +Bundle-Version: 1.0.0.${tstamp} +Bundle-SymbolicName: io.openems.shared.influxdb.launch +JPM-Command: provider + + +-runrequires: \ + osgi.identity;filter:='(osgi.identity=io.openems.shared.influxdb.provider)' + +-runbundles: ${error;You must first resolve this bndrun file before you can run it} diff --git a/io.openems.shared.influxdb/readme.md b/io.openems.shared.influxdb/readme.md new file mode 100644 index 00000000000..4c4e13b6767 --- /dev/null +++ b/io.openems.shared.influxdb/readme.md @@ -0,0 +1,8 @@ +# io.openems.shared.influxdb Provider + +${Bundle-Description} + +## Example + +## References + diff --git a/io.openems.shared.influxdb/src/io/openems/shared/influxdb/InfluxConnector.java b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/InfluxConnector.java new file mode 100644 index 00000000000..a3ccdf1ba92 --- /dev/null +++ b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/InfluxConnector.java @@ -0,0 +1,191 @@ +package io.openems.shared.influxdb; + +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.TimeUnit; + +import org.influxdb.BatchOptions; +import org.influxdb.InfluxDB; +import org.influxdb.InfluxDBFactory; +import org.influxdb.dto.Query; +import org.influxdb.dto.QueryResult; +import org.influxdb.dto.QueryResult.Result; +import org.influxdb.dto.QueryResult.Series; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.timedata.Tag; +import io.openems.common.types.ChannelAddress; +import io.openems.common.utils.JsonUtils; + +public class InfluxConnector { + + public final static String MEASUREMENT = "data"; + + private final String ip; + private final int port; + private final String username; + private final String password; + private final String database; + + public InfluxConnector(String ip, int port, String username, String password, String database) { + super(); + this.ip = ip; + this.port = port; + this.username = username; + this.password = password; + this.database = database; + } + + private InfluxDB _influxDB = null; + + public String getDatabase() { + return database; + } + + /** + * Get InfluxDB Connection + * + * @return + */ + public InfluxDB getConnection() throws OpenemsException { + if (this._influxDB == null) { + try { + InfluxDB influxDB = InfluxDBFactory.connect("http://" + this.ip + ":" + this.port, this.username, + this.password); + influxDB.setDatabase(this.database); + influxDB.enableBatch(BatchOptions.DEFAULTS); + this._influxDB = influxDB; + } catch (RuntimeException e) { + throw new OpenemsException("Unable to connect to InfluxDB: " + e.getMessage(), e); + } + } + return this._influxDB; + } + + public void deactivate() { + if (this._influxDB != null) { + this._influxDB.close(); + } + } + + /** + * copied from backend.timedata.influx.provider + * + * @param influxdb + * @param database + * @param query + * @return + * @throws OpenemsException + */ + public QueryResult executeQuery(String query) throws OpenemsException { + InfluxDB influxDB = this.getConnection(); + + // Parse result + QueryResult queryResult; + try { + queryResult = influxDB.query(new Query(query, this.database), TimeUnit.MILLISECONDS); + } catch (RuntimeException e) { + throw new OpenemsException("InfluxDB query runtime error. Query: " + query + ", Error: " + e.getMessage()); + } + if (queryResult.hasError()) { + throw new OpenemsException("InfluxDB query error. Query: " + query + ", Error: " + queryResult.getError()); + } + return queryResult; + } + + /** + * copied from backend.timedata.influx.provider + * + * @param influxdb + * @param database + * @param influxIdOpt + * @param fromDate + * @param toDate + * @param channels + * @param resolution + * @return + * @throws OpenemsException + */ + public JsonArray queryHistoricData(ZonedDateTime fromDate, ZonedDateTime toDate, JsonObject channels, + int resolution, Tag... tags) throws OpenemsException { + // Prepare query string + StringBuilder query = new StringBuilder("SELECT "); + query.append(Utils.toChannelAddressList(channels)); + query.append(" FROM data WHERE "); + for (Tag tag : tags) { + query.append(tag.getName() + " = '" + tag.getValue() + "' AND "); + } + query.append("time > "); + query.append(String.valueOf(fromDate.toEpochSecond())); + query.append("s"); + query.append(" AND time < "); + query.append(String.valueOf(toDate.toEpochSecond())); + query.append("s"); + query.append(" GROUP BY time("); + query.append(resolution); + query.append("s) fill(null)"); + + QueryResult queryResult = executeQuery(query.toString()); + + JsonArray j = new JsonArray(); + for (Result result : queryResult.getResults()) { + List seriess = result.getSeries(); + if (seriess != null) { + for (Series series : seriess) { + // create thing/channel index + ArrayList addressIndex = new ArrayList<>(); + for (String column : series.getColumns()) { + if (column.equals("time")) { + continue; + } + addressIndex.add(ChannelAddress.fromString(column)); + } + // first: create empty timestamp objects + for (List values : series.getValues()) { + JsonObject jTimestamp = new JsonObject(); + // get timestamp + Instant timestampInstant = Instant.ofEpochMilli((long) ((Double) values.get(0)).doubleValue()); + ZonedDateTime timestamp = ZonedDateTime.ofInstant(timestampInstant, fromDate.getZone()); + String timestampString = timestamp.format(DateTimeFormatter.ISO_INSTANT); + jTimestamp.addProperty("time", timestampString); + // add empty channels by copying "channels" parameter + JsonObject jChannels = new JsonObject(); + for (Entry entry : channels.entrySet()) { + String thingId = entry.getKey(); + JsonObject jThing = new JsonObject(); + JsonArray channelIds = JsonUtils.getAsJsonArray(entry.getValue()); + for (JsonElement channelElement : channelIds) { + String channelId = JsonUtils.getAsString(channelElement); + jThing.add(channelId, JsonNull.INSTANCE); + } + jChannels.add(thingId, jThing); + } + jTimestamp.add("channels", jChannels); + j.add(jTimestamp); + } + // then: add all data + for (int columnIndex = 1; columnIndex < series.getColumns().size(); columnIndex++) { + for (int timeIndex = 0; timeIndex < series.getValues().size(); timeIndex++) { + Double value = (Double) series.getValues().get(timeIndex).get(columnIndex); + ChannelAddress address = addressIndex.get(columnIndex - 1); + j.get(timeIndex).getAsJsonObject().get("channels").getAsJsonObject() + .get(address.getComponentId()).getAsJsonObject() + .addProperty(address.getChannelId(), value); + } + } + } + } + } + return j; + } + +} diff --git a/io.openems.shared.influxdb/src/io/openems/shared/influxdb/Utils.java b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/Utils.java new file mode 100644 index 00000000000..1092fd2c4b7 --- /dev/null +++ b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/Utils.java @@ -0,0 +1,34 @@ +package io.openems.shared.influxdb; + +import java.util.ArrayList; +import java.util.Map.Entry; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import io.openems.common.exceptions.OpenemsException; +import io.openems.common.utils.JsonUtils; + +public class Utils { + /** + * + * @param channels + * @return + * @throws OpenemsException + */ + protected static String toChannelAddressList(JsonObject channels) throws OpenemsException { + ArrayList channelAddresses = new ArrayList<>(); + for (Entry entry : channels.entrySet()) { + String thingId = entry.getKey(); + JsonArray channelIds = JsonUtils.getAsJsonArray(entry.getValue()); + for (JsonElement channelElement : channelIds) { + String channelId = JsonUtils.getAsString(channelElement); + channelAddresses + .add("MEAN(\"" + thingId + "/" + channelId + "\") AS \"" + thingId + "/" + channelId + "\""); + } + } + return String.join(", ", channelAddresses); + } + +} diff --git a/io.openems.shared.influxdb/src/io/openems/shared/influxdb/package-info.java b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/package-info.java new file mode 100644 index 00000000000..0600b9f4183 --- /dev/null +++ b/io.openems.shared.influxdb/src/io/openems/shared/influxdb/package-info.java @@ -0,0 +1,2 @@ +@org.osgi.annotation.versioning.Version("1.0.0") +package io.openems.shared.influxdb; diff --git a/io.openems.shared.influxdb/test/.gitignore b/io.openems.shared.influxdb/test/.gitignore new file mode 100644 index 00000000000..e69de29bb2d diff --git a/io.openems.wrapper/jts.bnd b/io.openems.wrapper/jts.bnd deleted file mode 100644 index 379a444f38a..00000000000 --- a/io.openems.wrapper/jts.bnd +++ /dev/null @@ -1,24 +0,0 @@ -Bundle-Name: JTS -Bundle-Description: The JTS Topology Suite is a Java library for creating and manipulating vector geometry. -Bundle-DocURL: https://github.com/locationtech/jts -Bundle-License: https://opensource.org/licenses/EPL-1.0 -Bundle-Version: 1.14 - -Include-Resource: @lib/jts-1.14.jar - --dsannotations: * - --metatypeannotations: * - --exportcontents: \ - com.vividsolutions.jts.geom, \ - com.vividsolutions.jts.operation.distance, \ - com.vividsolutions.jts.util, \ - com.vividsolutions.jts.io, \ - com.vividsolutions.jts.algorithm, \ - com.vividsolutions.jts.index, \ - com.vividsolutions.jts.index.strtree, \ - com.vividsolutions.jts.math --sources: false - -# TODO Update to latest version 1.15 which is available on maven central \ No newline at end of file diff --git a/io.openems.wrapper/lib/jts-1.14.jar b/io.openems.wrapper/lib/jts-1.14.jar deleted file mode 100644 index c45e1b8b6aa..00000000000 Binary files a/io.openems.wrapper/lib/jts-1.14.jar and /dev/null differ diff --git a/setup/devices b/setup/devices deleted file mode 100644 index 67aec8d47c3..00000000000 --- a/setup/devices +++ /dev/null @@ -1 +0,0 @@ -#name;password;apikey;packages \ No newline at end of file diff --git a/setup/setup.sh b/setup/setup.sh deleted file mode 100644 index aa12150d0d0..00000000000 --- a/setup/setup.sh +++ /dev/null @@ -1,201 +0,0 @@ -#!/bin/bash -# -# Script to automatically setup a FEMS. -# Setup parameters are taken from the first line of a devices file in the format: -# ;;; -# -set -e - -# Define status files -FINISHED_1=/opt/fems-setup/finished_1 -FINISHED_2=/opt/fems-setup/finished_2 -DEVICES=/opt/fems-setup/devices - -# First stage: Copy filesystem to internal eMMC -if [ ! -e $FINISHED_1 ]; then - echo "#" - echo "# Starting first stage of FEMS setup" - echo "#" - - if [ "$(cat /boot/uboot/fems-setup/devices | wc -l)" == "1" ]; then - echo "# No devices left in configuration file" - echo "#" - echo "# Aborting" - exit 1 - fi - -#selection process -CHOICE=$(whiptail --menu "Wähle aus:" 18 40 9 \ - "FENECON Mini" "" \ - "FENECON DESS" "" \ - "FENECON Pro" "" \ - "FENECON Pro AC-Insel" "" \ - "FENECON Pro Heizstab" "" \ - "FENECON Pro Wärmepumpe" "" \ - "FENECON Commercial AC" "" \ - "FENECON Commercial DC" "" \ - "FENECON Commercial Hybrid" "" 3>&1 1>&2 2>&3) - - if [ $? = 0 ]; then - - case $CHOICE in - "FENECON Mini") echo "Es wurde Mini gewählt";; - "FENECON DESS") echo "Es wurde Pro Hybrid gewählt";; - "FENECON Pro") echo "Es wurde Pro 9-12 gewählt";; - "FENECON Pro AC-Insel") echo "Es wurde AC-Insel gewählt";; - "FENECON Pro Heizstab") echo "Es wurde Heizstab gewählt";; - "FENECON Pro Waermepumpe") echo "Es wurde Wärmepumpe gewählt";; - "FENECON Commercial AC") echo "Es wurde Commercial AC gewählt";; - "FENECON Commercial DC") echo "Es wurde Commercial DC gewählt";; - "FENECON Commercial Hybrid") echo "Es wurde Comemrcial Hybrid gewählt";; - - esac - - else - echo "Nichts ausgewählt" - exit - fi - echo "#save variable to file" - touch /opt/choice && echo $CHOICE > /opt/choice - - echo "# Copy templates to target" - cp -r /boot/uboot/fems-setup/templates /opt/fems-setup/ - - echo "# Copy filesystem to internal eMMC" - cd /opt/scripts/tools/eMMC - ./bbb-eMMC-flasher-eewiki-ext4.sh || true - - echo "# Mount target filesystem" - /bin/mount /dev/mmcblk1p1 /mnt - - echo "# Copy setup script to target" - mkdir -p /mnt/opt/fems-setup - cp /boot/uboot/fems-setup/setup.sh /mnt/opt/fems-setup/ - - echo "# Copy current fems data to target" - /usr/bin/head -n 2 /boot/uboot/fems-setup/devices > /mnt/opt/fems-setup/devices - - echo "# Remove fems from devices list" - /bin/sed --expression='2d' /boot/uboot/fems-setup/devices --in-place - - echo "# Mark first stage as finished" - touch /mnt$FINISHED_1 - /bin/umount /mnt - - echo "# Blink all LEDs" - echo timer | tee /sys/class/leds/beaglebone:green:usr?/trigger >/dev/null - - read -p "Press [Enter] key to shutdown" - - echo "# Shutdown system" - shutdown -h now - -elif [ ! -e $FINISHED_2 ]; then - echo "#" - echo "# Starting second stage of FEMS setup" - echo "#" - - cd /opt/fems-setup - FEMS=$(head -n 2 devices | tail -n 1 | cut -d ";" -f 1) - PASSWORD=$(head -n 2 devices | tail -n 1 | cut -d ";" -f 2) - - - echo "# Set password for user fems" - echo "fems:${PASSWORD}" | /usr/sbin/chpasswd - - echo "# Set name to ${FEMS}" - echo $FEMS > /etc/hostname - /bin/sed "s/\(127.0.1.1.*\)fems.*/\1$FEMS/" /etc/hosts --in-place - echo $FEMS > /etc/mailname - rm -fv /etc/ssh/ssh_host_* - dpkg-reconfigure openssh-server - rm /etc/udev/rules.d/70-persistent-net.rules - - echo "# Blink all LEDs" - echo timer | tee /sys/class/leds/beaglebone:green:usr?/trigger >/dev/null - - echo "# Mark second stage as finished" - touch $FINISHED_2 - - read -p "Press [Enter] key to reboot" - echo "# Rebooting system" - reboot - -else - echo "#" - echo "# Starting third stage of FEMS setup" - echo "#" - - cd /opt/fems-setup - PACKAGES=$(head -n 2 devices | tail -n 1 | cut -d ";" -f 4) - - echo "# Add FENECON debian repository" - wget -O - http://fenecon.de/debian/fems.gpg.key | apt-key add - - wget http://fenecon.de/debian/fems.list -O /etc/apt/sources.list.d/fems.list - echo "# Add Debian Backports repository" - echo "deb http://ftp.de.debian.org/debian/ jessie-backports main contrib non-free" > /etc/apt/sources.list.d/jessie-backports.list - echo "# Refresh apt cache" - /usr/bin/aptitude update - echo "# Install openjdk 8" - /usr/bin/apt install -t jessie-backports openjdk-8-jre-headless -y - - CHOICE=$(cat /opt/choice) - - if [ "$CHOICE" == "FENECON DESS" ]; then - - aptitude install fems-dess fems-fenecononlinemonitoring --assume-yes - - else - aptitude install openems openems-fems openems-ui influxdb grafana - - # copy config and set name + apikey - CHOICE=$(cat /opt/choice) - mkdir -p /opt/config.d - - echo "# Write Apikey into /etc/fems" - APIKEY=$(head -n 2 /opt/fems-setup/devices | tail -n 1 | cut -d ";" -f 3) - echo "apikey=${APIKEY}" > /etc/fems - - cp "/opt/fems-setup/templates/$CHOICE.json" "/opt/config.d/$CHOICE.json" - NAME=$(head -n 2 /opt/fems-setup/devices | tail -n 1 | cut -d ";" -f 1) - - sed "s/\"###FEMS_ID###\"/${NAME:4}/" --in-place "/opt/config.d/$CHOICE.json" - - APIKEY=$(head -n 2 /opt/fems-setup/devices | tail -n 1 | cut -d ";" -f 3) - sed "s/###APIKEY###/$APIKEY/" --in-place "/opt/config.d/$CHOICE.json" - - CHOICE=$(cat /opt/choice) - mv "/opt/config.d/$CHOICE.json" "/etc/openems.d/config.json" - unlink /opt/choice - - fi - - # this is not working... - #echo "# preset apikey for dpkg-configure" - #. /usr/share/debconf/confmodule - #db_set fems-openhab-addon-fems/apikey $APIKEY - - # TODO remove setup-script from /opt/fems-setup - - if [ "${PACKAGES}" != "" ]; then - echo "# Install packages: ${PACKAGES}" - /usr/bin/aptitude install --assume-yes $PACKAGES -y - - else - echo "# Install NO packages!" - fi - - #echo "# Finialize setup with fems-autoupdate fems" - #/usr/bin/fems-autoupdate fems - - echo "#" - echo "# Finished setup" - echo "#" - - - fems-autoupdate fems -y || true - echo "# Blink all LEDs" - echo timer | tee /sys/class/leds/beaglebone:green:usr?/trigger >/dev/null - echo "# Rebooting system" - reboot -fi diff --git a/tools/.classpath b/tools/.classpath deleted file mode 100644 index ef141e6bfaa..00000000000 --- a/tools/.classpath +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/tools/.gitignore b/tools/.gitignore deleted file mode 100644 index 09e3bc9b241..00000000000 --- a/tools/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/bin/ -/target/ diff --git a/tools/.project b/tools/.project deleted file mode 100644 index 1046fea7030..00000000000 --- a/tools/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - tools - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.m2e.core.maven2Nature - org.eclipse.jdt.core.javanature - - diff --git a/tools/.settings/org.eclipse.jdt.core.prefs b/tools/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 672496e107e..00000000000 --- a/tools/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,12 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/tools/.settings/org.eclipse.m2e.core.prefs b/tools/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f1cb2..00000000000 --- a/tools/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/tools/git-settings.sh b/tools/git-settings.sh new file mode 100644 index 00000000000..aee86a95283 --- /dev/null +++ b/tools/git-settings.sh @@ -0,0 +1,12 @@ +# Initialize default GIT settings. +# +# This script sets some sensible defaults for GIT with OpenEMS. It needs to be executed in the base directory using "bash tools/git-settings.sh" +# - ignore .classpath files +# See https://stackoverflow.com/questions/10417337 +# +for D in *; do + if [ -d "${D}" ]; then + echo "${D}" + git update-index --assume-unchanged "${D}/.classpath" + fi +done diff --git a/tools/pom.xml b/tools/pom.xml deleted file mode 100644 index 0cc04180a89..00000000000 --- a/tools/pom.xml +++ /dev/null @@ -1,53 +0,0 @@ - - 4.0.0 - tools - tools - 0.0.1-SNAPSHOT - - src - - - maven-compiler-plugin - 3.7.0 - - 1.8 - 1.8 - - - - - - - com.google.guava - guava - 23.1-jre - - - ch.qos.logback - logback-classic - 1.2.3 - - - org.slf4j - slf4j-api - 1.7.25 - - - com.google.code.gson - gson - 2.8.2 - - - com.ghgande - j2mod - 2.4.1 - - - org.java-websocket - Java-WebSocket - 1.3.8 - - - \ No newline at end of file diff --git a/tools/src/tools/ChannelExport.java b/tools/src/tools/ChannelExport.java deleted file mode 100644 index fc53e65d12d..00000000000 --- a/tools/src/tools/ChannelExport.java +++ /dev/null @@ -1,123 +0,0 @@ -//package tools; -// -//import io.openems.common.exceptions.OpenemsException; -// -///** -// * This generates 'Readme.md' files for OpenEMS Edge devices -// * -// */ -//public class ChannelExport { -// -// public static void main(String[] args) throws OpenemsException { -// // String openemsPath = -// // "C:\\Users\\matthias.rossmann\\Dev\\git\\openems-neu\\edge\\src"; -// // Collection deviceNatures; -// // HashMap files = new HashMap<>(); -// // try { -// // deviceNatures = ClassRepository.getInstance().getAvailableDeviceNatures(); -// // FileWriter devices = new FileWriter( -// // Paths.get(openemsPath, "\\io\\openems\\impl\\device\\Readme.md").toFile()); -// // devices.write("# List of implemented Devices.\r\n\r\n"); -// // for (ThingDoc thingDoc : deviceNatures) { -// // try { -// // System.out.println(thingDoc.getClazz().getName()); -// // if (thingDoc.getClazz().equals(AsymmetricSymmetricCombinationEssNature.class) -// // || thingDoc.getClazz().equals(EssClusterNature.class) || -// // thingDoc.getClazz().isInterface() -// // || Modifier.isAbstract(thingDoc.getClazz().getModifiers())) { -// // continue; -// // } -// // Path p = Paths.get(openemsPath, -// // thingDoc.getClazz().getName().replaceAll("[^\\.]*$", "").replace(".", "/"), -// // "Readme.md"); -// // FileWriter fw; -// // if (files.containsKey(p)) { -// // fw = files.get(p); -// // } else { -// // fw = new FileWriter(p.toFile()); -// // files.put(p, fw); -// // fw.write(""); -// // } -// // fw.append("# " + thingDoc.getTitle() + "\r\n" + thingDoc.getText() -// // + "\r\n\r\nFollowing Values are implemented:\r\n\r\n" + -// // "|ChannelName|Unit|\r\n" -// // + "|---|---|\r\n"); -// // devices.append("* [" + thingDoc.getTitle() + "](" -// // + -// // Paths.get(thingDoc.getClazz().getName().replaceAll("io.openems.impl.device.", -// // "") -// // .replaceAll("[^\\.]*$", "").replace(".", "/"), "Readme.md").toString() -// // .replace("\\", "/") -// // + ")\r\n"); -// // Thing thing = thingDoc.getClazz().getConstructor(String.class, -// // Device.class).newInstance("", null); -// // if (thing instanceof ModbusDeviceNature) { -// // ((ModbusDeviceNature) thing).init(); -// // } -// // List channelDocs = new LinkedList<>(thingDoc.getChannelDocs()); -// // Collections.sort(channelDocs, new Comparator() { -// // -// // @Override -// // public int compare(ChannelDoc arg0, ChannelDoc arg1) { -// // return arg0.getName().compareTo(arg1.getName()); -// // } -// // }); -// // for (ChannelDoc channelDoc : channelDocs) { -// // Member member = channelDoc.getMember(); -// // try { -// // List channels = new ArrayList<>(); -// // if (member instanceof Method) { -// // if (((Method) member).getReturnType().isArray()) { -// // Channel[] ch = (Channel[]) ((Method) member).invoke(thing); -// // for (Channel c : ch) { -// // channels.add(c); -// // } -// // } else { -// // // It's a Method with ReturnType Channel -// // channels.add((Channel) ((Method) member).invoke(thing)); -// // } -// // } else if (member instanceof Field) { -// // // It's a Field with Type Channel -// // channels.add((Channel) ((Field) member).get(thing)); -// // } else { -// // continue; -// // } -// // if (channels.isEmpty()) { -// // System.out.println("Channel is returning null! Thing [" + thing.id() + "], -// // Member [" -// // + member.getName() + "]"); -// // continue; -// // } -// // for (Channel channel : channels) { -// // if (channel != null) { -// // StringBuilder unit = new StringBuilder(); -// // if (channel instanceof ReadChannel) { -// // ReadChannel rchannel = ((ReadChannel) channel); -// // unit.append(rchannel.unitOptional()); -// // rchannel.getLabels().forEach((key, value) -> { -// // unit.append(key + ": " + value + "
        "); -// // }); -// // } -// // fw.append("|" + channel.id() + "|" + unit + "|\r\n"); -// // } -// // } -// // } catch (IllegalAccessException | IllegalArgumentException | -// // InvocationTargetException e) { -// // System.out.println("Unable to add Channel. Member [" + member.getName() + -// // "]"); -// // } -// // } -// // } catch (NoSuchMethodException e) { -// // -// // } -// // } -// // for (FileWriter fw : files.values()) { -// // fw.close(); -// // } -// // devices.close(); -// // } catch (Exception e) { -// // e.printStackTrace(); -// // } -// } -// -//} diff --git a/tools/src/tools/FaultsAndWarningsTranspiler.java b/tools/src/tools/FaultsAndWarningsTranspiler.java deleted file mode 100644 index 7367cb84d66..00000000000 --- a/tools/src/tools/FaultsAndWarningsTranspiler.java +++ /dev/null @@ -1,117 +0,0 @@ -//package tools; -// -//import java.io.IOException; -//import java.nio.charset.Charset; -//import java.nio.file.Files; -//import java.nio.file.Path; -//import java.nio.file.Paths; -//import java.util.HashSet; -//import java.util.Set; -// -//import com.google.common.reflect.ClassPath; -//import com.google.gson.Gson; -//import com.google.gson.GsonBuilder; -//import com.google.gson.JsonObject; -// -//import io.openems.common.exceptions.OpenemsException; -//import io.openems.common.types.ThingStateInfo; -//import io.openems.common.utils.JsonUtils; -// -///** -// * This tool transpiles OpenEMS Edge Fault and Warning Enums to TypeScript for -// * usage in OpenEMS UI. -// * -// * @author stefan.feilmeier -// * -// */ -//public class FaultsAndWarningsTranspiler { -// -// private final static Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); -// -// public static void main(String[] args) -// throws OpenemsException, InstantiationException, IllegalAccessException, IOException { -// Path outputFile = Paths.get(".", "..", "ui", "src", "app", "device", "overview", "state", "thingstates.ts"); -// // JsonObject j = getJson(); -//// writeTypeScriptFile(outputFile, j); -// System.out.println("Wrote file " + outputFile.toAbsolutePath()); -// } -// -// private static void writeTypeScriptFile(Path outputFile, JsonObject j) throws IOException { -// Gson gson = new GsonBuilder().setPrettyPrinting().create(); -// String json = gson.toJson(j); -// String out = "interface ThingStates { [clazz: string]: { 'faults'?: { [id: number]: string }, 'warnings'?: { [id: number]: string } } };" -// + "\n" + "\n" + "export const THING_STATES: ThingStates = " + json + ";"; -// Files.write(outputFile, out.getBytes(DEFAULT_CHARSET)); -// } -// -// // private static JsonObject getJson() throws ReflectionException, -// // OpenemsException { -// // JsonObject j = new JsonObject(); -// // for (Class clazz : getEnums()) { -// // ThingStateInfo annotation = clazz.getAnnotation(ThingStateInfo.class); -// // if (annotation == null) { -// // System.err.println("@ThingStateInfo is missing for Enum [" + clazz.getName() -// // + "]"); -// // continue; -// // } -// // // Find existing Thing definition or create new one -// // for (Class thingClazz : annotation.reference()) { -// // String thingClassName = thingClazz.getName(); -// // JsonObject jThing = JsonUtils.getAsOptionalJsonObject(j, -// // thingClassName).orElse(new JsonObject()); -// // -// // // Parse enum constants -// // ThingStateEnum[] enoms = clazz.getEnumConstants(); -// // JsonObject jState = new JsonObject(); -// // for (ThingStateEnum enom : enoms) { -// // String name = splitCamelCase(enom.toString()); -// // jState.addProperty(String.valueOf(enom.getValue()), name); -// // } -// // -// // // Is it Fault or Warning? -// // if (FaultEnum.class.isAssignableFrom(clazz)) { -// // jThing.add("faults", jState); -// // } else if (WarningEnum.class.isAssignableFrom(clazz)) { -// // jThing.add("warnings", jState); -// // } else { -// // throw new OpenemsException("Neither Fault nor Warning in Enum [" + -// // clazz.getName() + "]"); -// // } -// // -// // j.add(thingClassName, jThing); -// // } -// // } -// // return j; -// // } -// -//// @SuppressWarnings("unchecked") -//// private static Set> getEnums() throws ReflectionException { -//// String topLevelPackage = "io.openems.impl"; -//// Class searchClazz = ThingStateEnum.class; -//// Set> clazzes = new HashSet<>(); -//// try { -//// ClassPath classpath = ClassPath.from(ClassLoader.getSystemClassLoader()); -//// for (ClassPath.ClassInfo classInfo : classpath.getTopLevelClassesRecursive(topLevelPackage)) { -//// Class thisClazz = classInfo.load(); -//// if (searchClazz.isAssignableFrom(thisClazz)) { -//// clazzes.add((Class) thisClazz); -//// } -//// } -//// } catch (IllegalArgumentException | IOException e) { -//// throw new ReflectionException(e.getMessage()); -//// } -//// return clazzes; -//// } -// -// /** -// * Source: -// * https://stackoverflow.com/questions/2559759/how-do-i-convert-camelcase-into-human-readable-names-in-java -// * -// * @param s -// * @return -// */ -// private static String splitCamelCase(String s) { -// return s.replaceAll(String.format("%s|%s|%s", "(?<=[A-Z])(?=[A-Z][a-z])", "(?<=[^A-Z])(?=[A-Z])", -// "(?<=[A-Za-z])(?=[^A-Za-z])"), " "); -// } -//} diff --git a/tools/src/tools/ModbusMaster.java b/tools/src/tools/ModbusMaster.java deleted file mode 100644 index 4a973f14c2d..00000000000 --- a/tools/src/tools/ModbusMaster.java +++ /dev/null @@ -1,51 +0,0 @@ -package tools; - -import com.ghgande.j2mod.modbus.Modbus; -import com.ghgande.j2mod.modbus.facade.ModbusSerialMaster; -import com.ghgande.j2mod.modbus.procimg.Register; -import com.ghgande.j2mod.modbus.util.SerialParameters; - -public class ModbusMaster { - - public static void main(String[] args) { - // ModbusTCPMaster master = new ModbusTCPMaster("localhost", 502, 10000, true); - // try { - // master.connect(); - // Register[] registers = master.readMultipleRegisters(100, 0x1402, 1); - // for (Register register : registers) { - // System.out.println(register); - // } - // } catch (Exception e) { - // e.printStackTrace(); - // } finally { - // master.disconnect(); - // } - System.out.println("Start."); - ModbusSerialMaster master; - try { - // master = new ModbusTCPMaster(
        ); // Uses port 502 and a timeout of - // 3000ms - // master = new ModbusTCPMaster(
        , ); // Uses a timeout of 3000ms - SerialParameters params = new SerialParameters(); - params.setPortName("/dev/ttySC0"); - params.setBaudRate(38400); - params.setDatabits(8); - params.setStopbits(1); - params.setParity("even"); - params.setEncoding(Modbus.SERIAL_ENCODING_RTU); - params.setEcho(false); - master = new ModbusSerialMaster(params); - master.connect(); - - System.out.println("Connected. Start read."); - Register[] registers = master.readMultipleRegisters(5, 50520, 36); - for (Register register : registers) { - System.out.println("Result: " + register); - } - } catch (Exception e) { - e.printStackTrace(); - } - System.out.println("Finished"); - } - -} diff --git a/tools/test-gitignore.sh b/tools/test-gitignore.sh new file mode 100644 index 00000000000..acfb6d6137b --- /dev/null +++ b/tools/test-gitignore.sh @@ -0,0 +1,17 @@ +# Add .gitignore file to empty test directories. +# +# When Eclipse creates 'test' src folders they are sometimes empty. Empty +# folders are not committed to GIT. Because of this Eclipse would show errors +# when importing the projects. This script creates an empty '.gitignore' file +# inside each 'test' folder to solve this. +# +# See https://stackoverflow.com/questions/115983 +# +for D in *; do + if [ -d "${D}/test" ]; then + if [ ! -f "./${D}/test/.gitignore" ]; then + echo "${D}/test/.gitignore -> missing" + touch ${D}/test/.gitignore + fi + fi +done diff --git a/ui/package-lock.json b/ui/package-lock.json index 03d2f880313..0dbc3ede45f 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,14763 +1,14763 @@ -{ - "name": "openems-ui", - "version": "2018.8.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@angular-devkit/build-optimizer": { - "version": "0.0.42", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.42.tgz", - "integrity": "sha512-BAYCVZ10ro6mgZQDZiNiVbX8ppygw4q7z/stpwG8WjMswgMRIcxsxYoC1VFuWcUPAf4UyfTIav6e8UZWA5+xnQ==", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "source-map": "^0.5.6", - "typescript": "~2.6.2", - "webpack-sources": "^1.0.1" - }, - "dependencies": { - "typescript": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", - "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", - "dev": true - } - } - }, - "@angular-devkit/core": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.0.29.tgz", - "integrity": "sha512-jtUBA0pIrkdXcVqDmDrGlniqwM7NFOKdo7vWFDmCVLBbC9rZHeYW5Xv/+4HyBhGLJ4wxsAkUjsHKWGJINPPpiw==", - "dev": true, - "requires": { - "ajv": "~5.5.1", - "chokidar": "^1.7.0", - "rxjs": "^5.5.6", - "source-map": "^0.5.6" - } - }, - "@angular-devkit/schematics": { - "version": "0.0.52", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.0.52.tgz", - "integrity": "sha512-NtG8VB5aWtg0cw1Y7EJinJMuAnXsNdkQkkVe/i7CO6TPLyFQSFQCN1YojCr43l8jTWTRebRslrBawPCMOxsOgw==", - "dev": true, - "requires": { - "@ngtools/json-schema": "^1.1.0", - "rxjs": "^5.5.6" - } - }, - "@angular/animations": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-5.2.5.tgz", - "integrity": "sha512-70ElCmaeDxLQc2OkgYhJjXj4zjtdjI4K1D5ZZm/uSPLlUcqC6uf6skCXlhMawQoPbsL/SXE5xw2HlMgEbhUysw==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/cdk": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-5.2.1.tgz", - "integrity": "sha512-8vsHeRymM+p82JeBzanrjmxp0koTU5W8cXO05ojECRsj6gUE/C950rMfFDga7fC8Pu5KTru/hWQoOcKErb3Uzg==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/cli": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.6.7.tgz", - "integrity": "sha512-TprSjnQrEdrTsCAB5K/lCLuXZUH/y+l/BAR0aZLpubpZP8Ldgmq7q56trxL5wNSs3o6A8Vh43ZKNYOuKtnzlXQ==", - "dev": true, - "requires": { - "@angular-devkit/build-optimizer": "0.0.42", - "@angular-devkit/core": "0.0.29", - "@angular-devkit/schematics": "0.0.52", - "@ngtools/json-schema": "1.1.0", - "@ngtools/webpack": "1.9.7", - "@schematics/angular": "0.1.17", - "autoprefixer": "^7.2.3", - "chalk": "~2.2.0", - "circular-dependency-plugin": "^4.2.1", - "common-tags": "^1.3.1", - "copy-webpack-plugin": "^4.1.1", - "core-object": "^3.1.0", - "css-loader": "^0.28.1", - "cssnano": "^3.10.0", - "denodeify": "^1.2.1", - "ember-cli-string-utils": "^1.0.0", - "exports-loader": "^0.6.3", - "extract-text-webpack-plugin": "^3.0.2", - "file-loader": "^1.1.5", - "fs-extra": "^4.0.0", - "glob": "^7.0.3", - "html-webpack-plugin": "^2.29.0", - "istanbul-instrumenter-loader": "^3.0.0", - "karma-source-map-support": "^1.2.0", - "less": "^2.7.2", - "less-loader": "^4.0.5", - "license-webpack-plugin": "^1.0.0", - "loader-utils": "1.1.0", - "lodash": "^4.11.1", - "memory-fs": "^0.4.1", - "minimatch": "^3.0.4", - "node-modules-path": "^1.0.0", - "node-sass": "^4.7.2", - "nopt": "^4.0.1", - "opn": "~5.1.0", - "portfinder": "~1.0.12", - "postcss-import": "^11.0.0", - "postcss-loader": "^2.0.10", - "postcss-url": "^7.1.2", - "raw-loader": "^0.5.1", - "resolve": "^1.1.7", - "rxjs": "^5.5.6", - "sass-loader": "^6.0.6", - "semver": "^5.1.0", - "silent-error": "^1.0.0", - "source-map-support": "^0.4.1", - "style-loader": "^0.13.1", - "stylus": "^0.54.5", - "stylus-loader": "^3.0.1", - "uglifyjs-webpack-plugin": "^1.1.5", - "url-loader": "^0.6.2", - "webpack": "~3.10.0", - "webpack-dev-middleware": "~1.12.0", - "webpack-dev-server": "~2.11.0", - "webpack-merge": "^4.1.0", - "webpack-sources": "^1.0.0", - "webpack-subresource-integrity": "^1.0.1" - } - }, - "@angular/common": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-5.2.5.tgz", - "integrity": "sha512-jagCxo+75pcTwjuO1ZheIiTlKBJ6REFKFWoUPTzaSS6fnzReFJ+VPf4Pb0bWtHL1lWvbvnzmITOJPB9wmuM3fg==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/compiler": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-5.2.5.tgz", - "integrity": "sha512-YU/r5omexkrrBF3bZaseWrc2Iotk6hIdUWkPIL3gPC0hKJ3wBeB3sHCBujPQXktWdMBbQRujNSMZtgra3Oh1xQ==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/compiler-cli": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-5.2.5.tgz", - "integrity": "sha512-jRFMxUKpodzOBKdZc6OMse+CjK6xfTJssZQrYeIyqz2daobaIsMZP2hZX8s/PCfV8Vxa7XFwCJb7Fq2uyZKfHg==", - "dev": true, - "requires": { - "chokidar": "^1.4.2", - "minimist": "^1.2.0", - "reflect-metadata": "^0.1.2", - "tsickle": "^0.26.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "@angular/core": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-5.2.5.tgz", - "integrity": "sha512-Uo7R3LrsvA24JkRbwXWUZWp7NSEpwdTUxT1NScyjrBK+t8ybSL5/42Jo21md5M4pjeCsIgUXlGoCm1QtT5aYnQ==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/flex-layout": { - "version": "2.0.0-beta.12", - "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-2.0.0-beta.12.tgz", - "integrity": "sha512-QTOKZxehYTh8fj64V/pNVWNbfNtebSbssyMIXiGJuHTzfyF7GYdRmtjoR2pNpllycz3rE5NYX77EB140Y6BCnw==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/forms": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-5.2.5.tgz", - "integrity": "sha512-3feqqTuv9rIu7ZOsLCtM/ugNFz5RPujLHkE8bU1gsMM4/eMYruIFir2vbjnhMkD3K6KptEg4iO6tDW18diwXug==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/http": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/http/-/http-5.2.5.tgz", - "integrity": "sha512-VqTCkAnebe+M9Bqrfp1QYpBQCTbXide/NxrQfwiJY87kjKFeRBuy9/XH/2S5wIwlF5Yx3bmlaIufd9VI5r/0aQ==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/language-service": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-5.2.5.tgz", - "integrity": "sha512-UWNbECu8svXmrgbTL03Fr+Dn06aPCZZLScmCOGVT5lkdsiJPAJpWAvKVM2Y0nzH0PmvekHw7INtV5lwfJOijYQ==", - "dev": true - }, - "@angular/material": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-5.2.1.tgz", - "integrity": "sha512-94VmxclpIwXAxeudz9AfMg0m46/TEx/GsDZ7R9yOtrbptAr9xSgOumiEqET4Xjb35/mzgD/PKqlcMWyHJCkyVQ==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/platform-browser": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-5.2.5.tgz", - "integrity": "sha512-iPAuoG/c3pD3hnk1g0VgJu/pzNITvLQyT0W71MDMSuxLxs291kq+U2jklm40pStISd1mPbCNKmvz/7M+WbdLhg==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/platform-browser-dynamic": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-5.2.5.tgz", - "integrity": "sha512-IMEe2qUTC3CA3KoswmJJs+O2Lkyd5GXgl5ULupqhhm/TOL2FLk00kwv8k3Epaf2d1wXcjK3BMG7aAwc6RLH7QA==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@angular/platform-server": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-5.2.5.tgz", - "integrity": "sha512-IpuEDNyoVfGO94jd1s+4IgoTBkWigwqD4YQTpcsC1mdY2Ax7NXXTAx28ZQF5EvPbSxsHGB5zG3oR7KE7GMNhYQ==", - "requires": { - "domino": "^1.0.29", - "tslib": "^1.7.1", - "xhr2": "^0.1.4" - } - }, - "@angular/router": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-5.2.5.tgz", - "integrity": "sha512-I8U0iy59lz0dAxU4zxRQHagfUPWF+MikLNMirRL1lrA49PG+5K1tiuIQ6p+8fZFAJ5UXwNHyXqYuWqsKRiVBHQ==", - "requires": { - "tslib": "^1.7.1" - } - }, - "@ngtools/json-schema": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz", - "integrity": "sha1-w6DFRNYjkqzCgTpCyKDcb1j4aSI=", - "dev": true - }, - "@ngtools/webpack": { - "version": "1.9.7", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.9.7.tgz", - "integrity": "sha512-D5QuaT9wENeM2j9g2qvW9Ls1tGqRz26Lp+jxwb2ZGFep7Ik1fFOX3ROLfgkxNlxZGVmbxJjsfrYUCyGlzj8gWg==", - "dev": true, - "requires": { - "chalk": "~2.2.0", - "enhanced-resolve": "^3.1.0", - "loader-utils": "^1.0.2", - "magic-string": "^0.22.3", - "semver": "^5.3.0", - "source-map": "^0.5.6", - "tree-kill": "^1.0.0", - "webpack-sources": "^1.1.0" - } - }, - "@ngx-translate/core": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-9.1.1.tgz", - "integrity": "sha1-rhA5KINrip4Gn9Li52+iGYzH5ig=" - }, - "@schematics/angular": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.1.17.tgz", - "integrity": "sha512-PHE5gk/ogPY/aN94dbbtauHMCq+/7w4Kdcl7tGmSS8mPKEI0wa6XJi//Wq/tHi55lb2fP58oEZU6n6w/wQascw==", - "dev": true, - "requires": { - "typescript": "~2.6.2" - }, - "dependencies": { - "typescript": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", - "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", - "dev": true - } - } - }, - "@types/d3": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@types/d3/-/d3-4.12.0.tgz", - "integrity": "sha512-F5lVj6c2G/WPbKFk4ZVxTS8F/6IRknWcheswQcycMjBh17iJ+bRfNUtn0yvtIHtRPQSanI9Dx2U8rSSA/I+ecQ==", - "requires": { - "@types/d3-array": "*", - "@types/d3-axis": "*", - "@types/d3-brush": "*", - "@types/d3-chord": "*", - "@types/d3-collection": "*", - "@types/d3-color": "*", - "@types/d3-dispatch": "*", - "@types/d3-drag": "*", - "@types/d3-dsv": "*", - "@types/d3-ease": "*", - "@types/d3-force": "*", - "@types/d3-format": "*", - "@types/d3-geo": "*", - "@types/d3-hierarchy": "*", - "@types/d3-interpolate": "*", - "@types/d3-path": "*", - "@types/d3-polygon": "*", - "@types/d3-quadtree": "*", - "@types/d3-queue": "*", - "@types/d3-random": "*", - "@types/d3-request": "*", - "@types/d3-scale": "*", - "@types/d3-selection": "*", - "@types/d3-shape": "*", - "@types/d3-time": "*", - "@types/d3-time-format": "*", - "@types/d3-timer": "*", - "@types/d3-transition": "*", - "@types/d3-voronoi": "*", - "@types/d3-zoom": "*" - } - }, - "@types/d3-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.1.tgz", - "integrity": "sha512-YBaAfimGdWE4nDuoGVKsH89/dkz2hWZ0i8qC+xxqmqi+XJ/aXiRF0jPtzXmN7VdkpVjy1xuDmM5/m1FNuB6VWA==" - }, - "@types/d3-axis": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.9.tgz", - "integrity": "sha512-fNUnI2a0F3xiE/nGrTdDpZG4sdcRIB4X59p9jgY8O7RQiKrVqyb433YCCYSqVID4CVyoq5v3bSFliUEk0FOMsw==", - "requires": { - "@types/d3-selection": "*" - } - }, - "@types/d3-brush": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-1.0.7.tgz", - "integrity": "sha1-BcMEQPTVN/0j+Xaw5sS6IjAB70U=", - "requires": { - "@types/d3-selection": "*" - } - }, - "@types/d3-chord": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.6.tgz", - "integrity": "sha1-BYnrl6MZH07a8Xt73kmEYokM4ew=" - }, - "@types/d3-collection": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-collection/-/d3-collection-1.0.5.tgz", - "integrity": "sha1-ux86qXzcjYgWRVQbnWz4ft/um8M=" - }, - "@types/d3-color": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.0.5.tgz", - "integrity": "sha1-ytdV8Pxt57cPpuXgivqB70wiSN4=" - }, - "@types/d3-dispatch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-1.0.5.tgz", - "integrity": "sha1-8fkYe1OOywUVdWnY3C9w37BPG1I=" - }, - "@types/d3-drag": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.0.tgz", - "integrity": "sha512-AePmm0sXj0Tpl0uQWvwmbAf1QR3yCy9aRhjJ9mRDDSZlHBdY0SCpUtdZC9uG9Q+pyHT/dEt1R2FT/sj+5k/bVA==", - "requires": { - "@types/d3-selection": "*" - } - }, - "@types/d3-dsv": { - "version": "1.0.31", - "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.0.31.tgz", - "integrity": "sha512-UCAVZdwd2NkrbkF1lZu9vzTlmUENRRrPCubyhDPlG8Ye1B8Xr2PNvk/Tp8tMm6sPoWZWagri6/P9H+t7WqkGDg==" - }, - "@types/d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha1-k6MBhovp4VBh89RDQ7GrP4rLbwk=" - }, - "@types/d3-force": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.1.0.tgz", - "integrity": "sha512-a39Uu/ltLaMpj6K0elEB1oAqhx9rlTB5X/O75uTUqyTW2CfjhPXg6hFsX1lF8oeMc29kqGJZ4g9Pf6mET25bVw==" - }, - "@types/d3-format": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.2.1.tgz", - "integrity": "sha512-dXhA9jzCbzu6Va8ZVUQ60nu6jqA5vhPhKGR4nY3lDYfjT05GyKEKuEhfwTaSTybWczY4nLEkzv9wLQCQd5+3cA==" - }, - "@types/d3-geo": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-1.9.4.tgz", - "integrity": "sha512-DoigJorMGGIG9K4n980zz5g1XnvhDhNy7rk/0O8KCpFPpUZ9hyAgN0ZHXhbtIelxhJhMZxwMRe2soxx/Fhx4Hg==", - "requires": { - "@types/geojson": "*" - } - }, - "@types/d3-hierarchy": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.0.tgz", - "integrity": "sha1-UPHuBShAY4A1y91KyrH8NHCQWQc=" - }, - "@types/d3-interpolate": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.1.6.tgz", - "integrity": "sha1-ZAQbFcnAMsNI2hsiuqvFn6TRYTY=", - "requires": { - "@types/d3-color": "*" - } - }, - "@types/d3-path": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.6.tgz", - "integrity": "sha512-YHW4cs+wOU9gFUzudjJs9TkrB/8GOgKhq32ZyNaZ2rzZjOhkqG486sGr9XSh4C91CcgIg1FRGoDaN29Ropx9nw==" - }, - "@types/d3-polygon": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-1.0.5.tgz", - "integrity": "sha1-Na1U7YTDnX6fElK2U1vmAL5srOI=" - }, - "@types/d3-quadtree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-1.0.5.tgz", - "integrity": "sha1-HOHmWerkUw3wyxJ/KX8XQaNnqC4=" - }, - "@types/d3-queue": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/d3-queue/-/d3-queue-3.0.5.tgz", - "integrity": "sha1-Pky+Kv9h22oLK4xIACmeTsasyFA=" - }, - "@types/d3-random": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-1.1.0.tgz", - "integrity": "sha1-LdCPEVnHBxknDkp8g0r4XIuI0sM=" - }, - "@types/d3-request": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-request/-/d3-request-1.0.2.tgz", - "integrity": "sha1-2524FU9HgWWEcGxub3Ar5m8i9L4=", - "requires": { - "@types/d3-dsv": "*" - } - }, - "@types/d3-scale": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-2.0.0.tgz", - "integrity": "sha512-fFLSdP3p9qQQ3W6ouO3GBI4Qg94CSykTWVc61U8SI1V62dfBWtOigBj5voxDcOniwh9MjKzTHldMSsGJ5qAFpA==", - "requires": { - "@types/d3-time": "*" - } - }, - "@types/d3-selection": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.3.0.tgz", - "integrity": "sha512-1SJhi3kTk/SHHIE6XkHuHU2REYkbSOjkQuo3HT71FOTs8/tjeGcvtXMsX4N3kU1UE1nVG+A5pg7TSjuJ4zUN3A==" - }, - "@types/d3-shape": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.2.2.tgz", - "integrity": "sha512-Ydksrces8J5WP/NXhZ/CcDx/XZZ8b7MDX+u6WGQXwEWfmimJn9eYHiD7QR4BLe3zBiAOQmmiGAwRBKUDp5zb1g==", - "requires": { - "@types/d3-path": "*" - } - }, - "@types/d3-time": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.0.7.tgz", - "integrity": "sha512-X5ZQYiJIM38XygNwld4gZ++Vtw2ftgo3KOfZOY4n/sCudUxclxf/3THBvuG8UqSV+EQ0ezYjT5eyvcrrmixOWA==" - }, - "@types/d3-time-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", - "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==" - }, - "@types/d3-timer": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.6.tgz", - "integrity": "sha1-eG1OIHMa3wOvLF32yG/ilmf+Qps=" - }, - "@types/d3-transition": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.1.1.tgz", - "integrity": "sha512-GHTghl0YYB8gGgbyKxVLHyAp9Na0HqsX2U7M0u0lGw4IdfEaslooykweZ8fDHW13T+KZeZAuzhbmqBZVFO+6kg==", - "requires": { - "@types/d3-selection": "*" - } - }, - "@types/d3-voronoi": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.7.tgz", - "integrity": "sha512-/dHFLK5jhXTb/W4XEQcFydVk8qlIAo85G3r7+N2fkBFw190l0R1GQ8C1VPeXBb2GfSU5GbT2hjlnE7i7UY5Gvg==" - }, - "@types/d3-zoom": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.7.0.tgz", - "integrity": "sha512-eIivt2ehMUXqS0guuVzRSMr5RGhO958g9EKxIJv3Z23suPnX4VQI9k1TC/bLuwKq0IWp9a1bEEcIy+PNJv9BtA==", - "requires": { - "@types/d3-interpolate": "*", - "@types/d3-selection": "*" - } - }, - "@types/geojson": { - "version": "7946.0.1", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.1.tgz", - "integrity": "sha512-BXY6tH16Snp/ZdX6cFlBD8yfEArcZemzxEGciXkMmp1/tU76oyqkxJq91JQzT8SXWzRPwj//dw0/FdCSnnT8mw==" - }, - "@types/jasmine": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.6.tgz", - "integrity": "sha512-clg9raJTY0EOo5pVZKX3ZlMjlYzVU73L71q5OV1jhE2Uezb7oF94jh4CvwrW6wInquQAdhOxJz5VDF2TLUGmmA==", - "dev": true - }, - "@types/jasminewd2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.3.tgz", - "integrity": "sha512-hYDVmQZT5VA2kigd4H4bv7vl/OhlympwREUemqBdOqtrYTo5Ytm12a5W5/nGgGYdanGVxj0x/VhZ7J3hOg/YKg==", - "dev": true, - "requires": { - "@types/jasmine": "*" - } - }, - "@types/node": { - "version": "6.0.101", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.101.tgz", - "integrity": "sha512-IQ7V3D6+kK1DArTqTBrnl3M+YgJZLw8ta8w3Q9xjR79HaJzMAoTbZ8TNzUTztrkCKPTqIstE2exdbs1FzsYLUw==", - "dev": true - }, - "@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", - "dev": true - }, - "@types/selenium-webdriver": { - "version": "2.53.43", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz", - "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", - "dev": true - }, - "@types/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", - "dev": true - }, - "@types/strip-json-comments": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", - "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true - }, - "JSONStream": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", - "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=", - "dev": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "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.4", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", - "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", - "dev": true, - "requires": { - "mime-types": "~2.1.16", - "negotiator": "0.6.1" - } - }, - "acorn": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz", - "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==", - "dev": true - }, - "acorn-dynamic-import": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", - "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", - "dev": true, - "requires": { - "acorn": "^4.0.3" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", - "dev": true - } - } - }, - "acorn-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.3.0.tgz", - "integrity": "sha512-efP54n3d1aLfjL2UMdaXa6DsswwzJeI5rqhbFvXMrKiJ6eJFpf+7R0zN7t8IC+XKn2YOAFAv6xbBNgHUkoHWLw==", - "dev": true, - "requires": { - "acorn": "^5.4.1", - "xtend": "^4.0.1" - } - }, - "addressparser": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", - "integrity": "sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=", - "dev": true, - "optional": true - }, - "adm-zip": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", - "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", - "dev": true - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", - "dev": true - }, - "agent-base": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", - "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", - "dev": true, - "requires": { - "extend": "~3.0.0", - "semver": "~5.0.1" - }, - "dependencies": { - "semver": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", - "dev": true - } - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "ajv-keywords": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", - "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=", - "dev": true - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true, - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, - "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 - }, - "amqplib": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.2.tgz", - "integrity": "sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA==", - "dev": true, - "optional": true, - "requires": { - "bitsyntax": "~0.0.4", - "bluebird": "^3.4.6", - "buffer-more-ints": "0.0.2", - "readable-stream": "1.x >=1.1.9", - "safe-buffer": "^5.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true, - "optional": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true, - "optional": true - } - } - }, - "angular2-toaster": { - "version": "5.0.0-alpha.1", - "resolved": "https://registry.npmjs.org/angular2-toaster/-/angular2-toaster-5.0.0-alpha.1.tgz", - "integrity": "sha512-4fG+JBLExcpVG7V/pt5Lhi3C7nDxnqKTKIJarwe41MP9hKP94hLExlWHsEN6nhG+nLIecp+LBamP3LFOjZCFMQ==" - }, - "angular2-uuid": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/angular2-uuid/-/angular2-uuid-1.1.1.tgz", - "integrity": "sha1-cvA81TK39AAy6x7PufhFc4S+lW4=" - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", - "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.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - }, - "dependencies": { - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "^1.1.1" - } - } - } - }, - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "dev": true, - "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" - } - }, - "app-root-path": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.0.1.tgz", - "integrity": "sha1-zWLc+OT9WkF+/GZNLlsQZTxlG0Y=", - "dev": true - }, - "append-transform": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", - "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", - "dev": true, - "requires": { - "default-require-extensions": "^1.0.0" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "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==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "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-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "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-flatten": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", - "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=", - "dev": true - }, - "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.7.0" - } - }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", - "dev": true - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", - "dev": true - }, - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", - "dev": true - }, - "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=", - "dev": true, - "optional": true - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", - "dev": true - }, - "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" - } - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "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.10.2", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.2.tgz", - "integrity": "sha512-ufWX953VU1eIuWqxS0nRDMYlGyFH+yxln5CsmIHlpzEt3fdYqUnRtsFt0XAsQot8OaVCwFqxT1RiwvtzYjeYeg==", - "dev": true, - "optional": true - }, - "astw": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", - "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=", - "dev": true, - "requires": { - "acorn": "^4.0.3" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", - "dev": true - } - } - }, - "async": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", - "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", - "dev": true, - "requires": { - "lodash": "^4.14.0" - } - }, - "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, - "optional": 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.0.3", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz", - "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=", - "dev": true - }, - "autoprefixer": { - "version": "7.2.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", - "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", - "dev": true, - "requires": { - "browserslist": "^2.11.3", - "caniuse-lite": "^1.0.30000805", - "normalize-range": "^0.1.2", - "num2fraction": "^1.2.2", - "postcss": "^6.0.17", - "postcss-value-parser": "^3.2.3" - } - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", - "dev": true - }, - "axios": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", - "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", - "dev": true, - "optional": true, - "requires": { - "follow-redirects": "1.0.0" - } - }, - "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" - } - }, - "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-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", - "dev": true, - "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", - "dev": true - } - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "dev": true, - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "debug": "^2.6.8", - "globals": "^9.18.0", - "invariant": "^2.2.2", - "lodash": "^4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", - "dev": true - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", - "dev": true - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "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": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", - "dev": true - }, - "base64-js": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz", - "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==", - "dev": true - }, - "base64id": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", - "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", - "dev": true - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "better-assert": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", - "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", - "dev": true, - "requires": { - "callsite": "1.0.0" - } - }, - "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 - }, - "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", - "dev": true - }, - "bitsyntax": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.0.4.tgz", - "integrity": "sha1-6xDMb4K4xJDj6FaY8H6D1G4MuoI=", - "dev": true, - "optional": true, - "requires": { - "buffer-more-ints": "0.0.2" - } - }, - "bl": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", - "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", - "dev": true, - "optional": true, - "requires": { - "readable-stream": "~2.0.5" - }, - "dependencies": { - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true, - "optional": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true, - "optional": true - } - } - }, - "blob": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", - "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, - "optional": true, - "requires": { - "inherits": "~2.0.0" - } - }, - "blocking-proxy": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.5.tgz", - "integrity": "sha1-RikF4Nz76pcPQao3Ij3anAexkSs=", - "dev": true, - "requires": { - "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 - } - } - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", - "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 - }, - "body-parser": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", - "dev": true, - "requires": { - "bytes": "3.0.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.1", - "http-errors": "~1.6.2", - "iconv-lite": "0.4.19", - "on-finished": "~2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "~1.6.15" - }, - "dependencies": { - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true - } - } - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "dev": true, - "requires": { - "array-flatten": "^2.1.0", - "deep-equal": "^1.0.1", - "dns-equal": "^1.0.0", - "dns-txt": "^2.0.2", - "multicast-dns": "^6.0.1", - "multicast-dns-service-types": "^1.1.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "browser-pack": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.4.tgz", - "integrity": "sha512-Q4Rvn7P6ObyWfc4stqLWHtG1MJ8vVtjgT24Zbu+8UTzxYuZouqZsmNRRTFVMY/Ux0eIKv1d+JWzsInTX+fdHPQ==", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "combine-source-map": "~0.8.0", - "defined": "^1.0.0", - "safe-buffer": "^5.1.1", - "through2": "^2.0.0", - "umd": "^3.0.0" - } - }, - "browser-resolve": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", - "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", - "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": { - "version": "14.5.0", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.5.0.tgz", - "integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "assert": "^1.4.0", - "browser-pack": "^6.0.1", - "browser-resolve": "^1.11.0", - "browserify-zlib": "~0.2.0", - "buffer": "^5.0.2", - "cached-path-relative": "^1.0.0", - "concat-stream": "~1.5.1", - "console-browserify": "^1.1.0", - "constants-browserify": "~1.0.0", - "crypto-browserify": "^3.0.0", - "defined": "^1.0.0", - "deps-sort": "^2.0.0", - "domain-browser": "~1.1.0", - "duplexer2": "~0.1.2", - "events": "~1.1.0", - "glob": "^7.1.0", - "has": "^1.0.0", - "htmlescape": "^1.1.0", - "https-browserify": "^1.0.0", - "inherits": "~2.0.1", - "insert-module-globals": "^7.0.0", - "labeled-stream-splicer": "^2.0.0", - "module-deps": "^4.0.8", - "os-browserify": "~0.3.0", - "parents": "^1.0.1", - "path-browserify": "~0.0.0", - "process": "~0.11.0", - "punycode": "^1.3.2", - "querystring-es3": "~0.2.0", - "read-only-stream": "^2.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.4", - "shasum": "^1.0.0", - "shell-quote": "^1.6.1", - "stream-browserify": "^2.0.0", - "stream-http": "^2.0.0", - "string_decoder": "~1.0.0", - "subarg": "^1.0.0", - "syntax-error": "^1.1.1", - "through2": "^2.0.0", - "timers-browserify": "^1.0.1", - "tty-browserify": "~0.0.0", - "url": "~0.11.0", - "util": "~0.10.1", - "vm-browserify": "~0.0.1", - "xtend": "^4.0.0" - }, - "dependencies": { - "buffer": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", - "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", - "dev": true, - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "domain-browser": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", - "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "timers-browserify": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", - "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", - "dev": true, - "requires": { - "process": "~0.11.0" - } - } - } - }, - "browserify-aes": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", - "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", - "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.0", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", - "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", - "dev": true, - "requires": { - "browserify-aes": "^1.0.4", - "browserify-des": "^1.0.0", - "evp_bytestokey": "^1.0.0" - } - }, - "browserify-des": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", - "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "des.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "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": "2.11.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", - "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30000792", - "electron-to-chromium": "^1.3.30" - } - }, - "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-indexof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", - "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", - "dev": true - }, - "buffer-more-ints": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz", - "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=", - "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 - }, - "buildmail": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-4.0.1.tgz", - "integrity": "sha1-h393OLeHKYccmhBeO4N9K+EaenI=", - "dev": true, - "optional": true, - "requires": { - "addressparser": "1.0.1", - "libbase64": "0.1.0", - "libmime": "3.0.0", - "libqp": "1.1.0", - "nodemailer-fetch": "1.6.0", - "nodemailer-shared": "1.1.0", - "punycode": "1.4.1" - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "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 - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", - "dev": true - }, - "cacache": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.2.tgz", - "integrity": "sha512-dljb7dk1jqO5ogE+dRpoR9tpHYv5xz9vPSNunh1+0wRuNdYxmzp9WmsyokgW/DUF1FDRVA/TMsmxt027R8djbQ==", - "dev": true, - "requires": { - "bluebird": "^3.5.0", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^1.3.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.1", - "ssri": "^5.0.0", - "unique-filename": "^1.1.0", - "y18n": "^3.2.1" - } - }, - "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" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "cached-path-relative": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", - "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=", - "dev": true - }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", - "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": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", - "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" - } - }, - "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.30000808", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000808.tgz", - "integrity": "sha1-MN/YMAnVcE8C3/s3clBo7RKjZrs=", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30000808", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000808.tgz", - "integrity": "sha512-vT0JLmHdvq1UVbYXioxCXHYdNw55tyvi+IUWyX0Zeh1OFQi2IllYtm38IJnSgHWCv/zUnX1hdhy3vMJvuTNSqw==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - }, - "dependencies": { - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true - } - } - }, - "chalk": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.2.tgz", - "integrity": "sha512-LvixLAQ4MYhbf7hgL4o5PeK32gJKvVzDRiSNIApDofQvyhl8adgG2lJVXn4+ekQoK7HL9RF8lqxwerpe0x2pCw==", - "dev": true, - "requires": { - "ansi-styles": "^3.1.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^4.0.0" - } - }, - "chart.js": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.1.tgz", - "integrity": "sha512-pX1oQAY86MiuyZ2hY593Acbl4MLHKrBBhhmZ1YqSadzQbbsBE2rnd6WISoHjIsdf0WDeC0hbePYCz2ZxkV8L+g==", - "requires": { - "chartjs-color": "~2.2.0", - "moment": "~2.18.0" - } - }, - "chartjs-color": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz", - "integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=", - "requires": { - "chartjs-color-string": "^0.5.0", - "color-convert": "^0.5.3" - } - }, - "chartjs-color-string": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz", - "integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==", - "requires": { - "color-name": "^1.0.0" - } - }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "dev": true, - "requires": { - "anymatch": "^1.3.0", - "async-each": "^1.0.0", - "fsevents": "^1.0.0", - "glob-parent": "^2.0.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^2.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0" - } - }, - "chownr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", - "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" - } - }, - "circular-dependency-plugin": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-4.4.0.tgz", - "integrity": "sha512-yEFtUNUYT4jBykEX5ZOHw+5goA3glGZr9wAXIQqoyakjz5H5TeUmScnWRc52douAhb9eYzK3s7V6bXfNnjFdzg==", - "dev": true - }, - "circular-json": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.1.tgz", - "integrity": "sha512-UjgcRlTAhAkLeXmDe2wK7ktwy/tgAqxiSndTIPiFZuIPLZmzHzWMwUIe9h9m/OokypG7snxCDEuwJshGBdPvaw==", - "dev": true - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "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 - } - } - }, - "classlist.js": { - "version": "1.1.20150312", - "resolved": "https://registry.npmjs.org/classlist.js/-/classlist.js-1.1.20150312.tgz", - "integrity": "sha1-HXCEL3Ai8I2awIbOaeWyUPLFd4k=" - }, - "clean-css": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz", - "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=", - "dev": true, - "requires": { - "source-map": "0.5.x" - } - }, - "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" - } - }, - "clone": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", - "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=", - "dev": true - }, - "clone-deep": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz", - "integrity": "sha1-NIxhrpzb4O3+BT2R/0zFIdeQ7eg=", - "dev": true, - "requires": { - "for-own": "^1.0.0", - "is-plain-object": "^2.0.1", - "kind-of": "^3.2.2", - "shallow-clone": "^0.1.2" - }, - "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" - } - } - } - }, - "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 - }, - "codelyzer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.1.0.tgz", - "integrity": "sha512-a3FCIAS3FNQIACvj7KA4iKvH3c6r7X6t6zXsrtV797QGYPQyCwD1fIEd9yV+ZDamijF3YaZ5fbB7QbUMOJGC/g==", - "dev": true, - "requires": { - "app-root-path": "^2.0.1", - "css-selector-tokenizer": "^0.7.0", - "cssauron": "^1.4.0", - "semver-dsl": "^1.0.1", - "source-map": "^0.5.6", - "sprintf-js": "^1.0.3" - } - }, - "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" - }, - "dependencies": { - "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", - "dev": true, - "requires": { - "color-name": "^1.1.1" - } - } - } - }, - "color-convert": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", - "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "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 - }, - "combine-lists": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", - "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", - "dev": true, - "requires": { - "lodash": "^4.5.0" - } - }, - "combine-source-map": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", - "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", - "dev": true, - "requires": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.6.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.5.3" - }, - "dependencies": { - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", - "dev": true - }, - "lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", - "dev": true - } - } - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", - "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" - }, - "common-tags": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.7.2.tgz", - "integrity": "sha512-joj9ZlUOjCrwdbmiLqafeUSgkUM74NqhLsZtSqDmhKudaIY197zTrb8JMl31fMnCUuxwFT23eC/oWvrZzDLRJQ==", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0" - } - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", - "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 - }, - "component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", - "dev": true - }, - "compressible": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.12.tgz", - "integrity": "sha1-xZpcmdt2dn6YdlAOJx72OzSTvWY=", - "dev": true, - "requires": { - "mime-db": ">= 1.30.0 < 2" - } - }, - "compression": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz", - "integrity": "sha1-7/JgPvwuIs+G810uuTWJ+YdTc9s=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "bytes": "3.0.0", - "compressible": "~2.0.11", - "debug": "2.6.9", - "on-headers": "~1.0.1", - "safe-buffer": "5.1.1", - "vary": "~1.1.2" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "connect": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", - "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", - "dev": true, - "requires": { - "debug": "2.6.9", - "finalhandler": "1.1.0", - "parseurl": "~1.3.2", - "utils-merge": "1.0.1" - } - }, - "connect-history-api-fallback": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", - "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=", - "dev": true - }, - "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.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", - "dev": true - }, - "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.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", - "dev": true - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "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 - }, - "copy-webpack-plugin": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.4.1.tgz", - "integrity": "sha512-ojaz8MpS3zoLJT/JbYMusYM+dCEArhW24hGAUPYPydTCS+87NFh2TWr85sywG3So4Q4E68QoerqQ+Ns1g0fhDg==", - "dev": true, - "requires": { - "cacache": "^10.0.1", - "find-cache-dir": "^1.0.0", - "globby": "^7.1.1", - "is-glob": "^4.0.0", - "loader-utils": "^0.2.15", - "minimatch": "^3.0.4", - "p-limit": "^1.0.0", - "serialize-javascript": "^1.4.0" - }, - "dependencies": { - "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" - } - }, - "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" - } - } - } - }, - "core-js": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", - "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" - }, - "core-object": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz", - "integrity": "sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg==", - "dev": true, - "requires": { - "chalk": "^2.0.0" - } - }, - "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": "2.2.2", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", - "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", - "dev": true, - "requires": { - "is-directory": "^0.3.1", - "js-yaml": "^3.4.3", - "minimist": "^1.2.0", - "object-assign": "^4.1.0", - "os-homedir": "^1.0.1", - "parse-json": "^2.2.0", - "require-from-string": "^1.1.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "create-ecdh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", - "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "elliptic": "^6.0.0" - } - }, - "create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", - "dev": true, - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "sha.js": "^2.4.0" - } - }, - "create-hmac": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", - "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", - "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": "3.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", - "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", - "dev": true, - "optional": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.x.x" - } - }, - "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" - } - }, - "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.9", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.9.tgz", - "integrity": "sha512-r3dgelMm/mkPz5Y7m9SeiGE46i2VsEU/OYbez+1llfxtv8b2y5/b5StaeEvPK3S5tlNQI+tDW/xDIhKJoZgDtw==", - "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" - }, - "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 - }, - "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" - } - }, - "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" - } - } - } - }, - "css-parse": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", - "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=", - "dev": true - }, - "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.0", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", - "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", - "dev": true, - "requires": { - "cssesc": "^0.1.0", - "fastparse": "^1.1.1", - "regexpu-core": "^1.0.0" - } - }, - "css-what": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", - "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", - "dev": true - }, - "cssauron": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", - "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", - "dev": true, - "requires": { - "through": "X.X.X" - } - }, - "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" - }, - "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 - }, - "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" - } - }, - "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" - } - }, - "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 - }, - "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" - } - }, - "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" - } - } - } - }, - "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" - } - }, - "cuint": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", - "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", - "dev": true - }, - "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" - } - }, - "custom-event": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", - "dev": true - }, - "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" - } - }, - "d3": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-4.13.0.tgz", - "integrity": "sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==", - "requires": { - "d3-array": "1.2.1", - "d3-axis": "1.0.8", - "d3-brush": "1.0.4", - "d3-chord": "1.0.4", - "d3-collection": "1.0.4", - "d3-color": "1.0.3", - "d3-dispatch": "1.0.3", - "d3-drag": "1.2.1", - "d3-dsv": "1.0.8", - "d3-ease": "1.0.3", - "d3-force": "1.1.0", - "d3-format": "1.2.2", - "d3-geo": "1.9.1", - "d3-hierarchy": "1.1.5", - "d3-interpolate": "1.1.6", - "d3-path": "1.0.5", - "d3-polygon": "1.0.3", - "d3-quadtree": "1.0.3", - "d3-queue": "3.0.7", - "d3-random": "1.1.0", - "d3-request": "1.0.6", - "d3-scale": "1.0.7", - "d3-selection": "1.3.0", - "d3-shape": "1.2.0", - "d3-time": "1.0.8", - "d3-time-format": "2.1.1", - "d3-timer": "1.0.7", - "d3-transition": "1.1.1", - "d3-voronoi": "1.1.2", - "d3-zoom": "1.7.1" - }, - "dependencies": { - "d3-scale": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz", - "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", - "requires": { - "d3-array": "^1.2.0", - "d3-collection": "1", - "d3-color": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" - } - } - } - }, - "d3-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz", - "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==" - }, - "d3-axis": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.8.tgz", - "integrity": "sha1-MacFoLU15ldZ3hQXOjGTMTfxjvo=" - }, - "d3-brush": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", - "integrity": "sha1-AMLyOAGfJPbAoZSibUGhUw/+e8Q=", - "requires": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "d3-chord": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.4.tgz", - "integrity": "sha1-fexPC6iG9xP+ERxF92NBT290yiw=", - "requires": { - "d3-array": "1", - "d3-path": "1" - } - }, - "d3-collection": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", - "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=" - }, - "d3-color": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", - "integrity": "sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs=" - }, - "d3-dispatch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", - "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=" - }, - "d3-drag": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.1.tgz", - "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", - "requires": { - "d3-dispatch": "1", - "d3-selection": "1" - } - }, - "d3-dsv": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", - "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", - "requires": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - } - }, - "d3-ease": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", - "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=" - }, - "d3-force": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", - "integrity": "sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==", - "requires": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" - } - }, - "d3-format": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", - "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==" - }, - "d3-geo": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.9.1.tgz", - "integrity": "sha512-l9wL/cEQkyZQYXw3xbmLsH3eQ5ij+icNfo4r0GrLa5rOCZR/e/3am45IQ0FvQ5uMsv+77zBRunLc9ufTWSQYFA==", - "requires": { - "d3-array": "1" - } - }, - "d3-hierarchy": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz", - "integrity": "sha1-ochFxC+Eoga88cAcAQmOpN2qeiY=" - }, - "d3-interpolate": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", - "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", - "requires": { - "d3-color": "1" - } - }, - "d3-path": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", - "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=" - }, - "d3-polygon": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.3.tgz", - "integrity": "sha1-FoiOkCZGCTPysXllKtN4Ik04LGI=" - }, - "d3-quadtree": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", - "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=" - }, - "d3-queue": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", - "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg=" - }, - "d3-random": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", - "integrity": "sha1-ZkLlBsb6OmSFldKyRpeIqNElKdM=" - }, - "d3-request": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-request/-/d3-request-1.0.6.tgz", - "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", - "requires": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-dsv": "1", - "xmlhttprequest": "1" - } - }, - "d3-scale": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.0.0.tgz", - "integrity": "sha512-Sa2Ny6CoJT7x6dozxPnvUQT61epGWsgppFvnNl8eJEzfJBG0iDBBTJAtz2JKem7Mb+NevnaZiDiIDHsuWkv6vg==", - "requires": { - "d3-array": "^1.2.0", - "d3-collection": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" - } - }, - "d3-selection": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", - "integrity": "sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==" - }, - "d3-shape": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", - "integrity": "sha1-RdAVOPBkuv0F6j1tLLdI/YxB93c=", - "requires": { - "d3-path": "1" - } - }, - "d3-time": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", - "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==" - }, - "d3-time-format": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", - "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", - "requires": { - "d3-time": "1" - } - }, - "d3-timer": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.7.tgz", - "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==" - }, - "d3-transition": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.1.1.tgz", - "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", - "requires": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - } - }, - "d3-voronoi": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", - "integrity": "sha1-Fodmfo8TotFYyAwUgMWinLDYlzw=" - }, - "d3-zoom": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.1.tgz", - "integrity": "sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==", - "requires": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "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" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "data-uri-to-buffer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", - "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", - "dev": true, - "optional": true - }, - "date-fns": { - "version": "2.0.0-alpha.7", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.0.0-alpha.7.tgz", - "integrity": "sha1-JFrRb5V2Tqur+ywKQf1dAzwg5Xo=" - }, - "date-format": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", - "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=", - "dev": true - }, - "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 - }, - "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" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "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-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, - "optional": true - }, - "default-require-extensions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", - "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", - "dev": true, - "requires": { - "strip-bom": "^2.0.0" - } - }, - "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", - "dev": true, - "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" - } - }, - "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" - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "degenerator": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", - "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", - "dev": true, - "optional": true, - "requires": { - "ast-types": "0.x.x", - "escodegen": "1.x.x", - "esprima": "3.x.x" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true, - "optional": true - } - } - }, - "del": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", - "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", - "dev": true, - "requires": { - "globby": "^6.1.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "p-map": "^1.1.1", - "pify": "^3.0.0", - "rimraf": "^2.2.8" - }, - "dependencies": { - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "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 - }, - "denodeify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", - "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", - "dev": true - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "deps-sort": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", - "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "shasum": "^1.0.0", - "subarg": "^1.0.0", - "through2": "^2.0.0" - } - }, - "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-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } - }, - "detect-node": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", - "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=", - "dev": true - }, - "detective": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", - "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", - "dev": true, - "requires": { - "acorn": "^5.2.1", - "defined": "^1.0.0" - } - }, - "di": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", - "dev": true - }, - "diff": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", - "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", - "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", - "dev": true, - "requires": { - "bn.js": "^4.1.0", - "miller-rabin": "^4.0.0", - "randombytes": "^2.0.0" - } - }, - "dir-glob": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", - "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "path-type": "^3.0.0" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", - "dev": true - }, - "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", - "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", - "dev": true, - "requires": { - "ip": "^1.1.0", - "safe-buffer": "^5.0.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "dev": true, - "requires": { - "buffer-indexof": "^1.0.0" - } - }, - "dom-converter": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", - "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", - "dev": true, - "requires": { - "utila": "~0.3" - }, - "dependencies": { - "utila": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", - "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", - "dev": true - } - } - }, - "dom-serialize": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", - "dev": true, - "requires": { - "custom-event": "~1.0.0", - "ent": "~2.2.0", - "extend": "^3.0.0", - "void-elements": "^2.0.0" - } - }, - "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", - "dev": true, - "requires": { - "domelementtype": "~1.1.1", - "entities": "~1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", - "dev": true - } - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", - "dev": true - }, - "domhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", - "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domino": { - "version": "1.0.30", - "resolved": "https://registry.npmjs.org/domino/-/domino-1.0.30.tgz", - "integrity": "sha512-ikq8WiDSkICdkElud317F2Sigc6A3EDpWsxWBwIZqOl95km4p/Vc9Rj98id7qKgsjDmExj0AVM7JOd4bb647Xg==" - }, - "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" - } - }, - "double-ended-queue": { - "version": "2.1.0-0", - "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", - "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", - "dev": true, - "optional": true - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "duplexify": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.3.tgz", - "integrity": "sha512-g8ID9OroF9hKt2POf8YLayy+9594PzmM3scI00/uBXocX3TWNgoB67hjzkFe9ITAbQOne/lLdBxHXvYUM4ZgGA==", - "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.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "dev": true, - "optional": true, - "requires": { - "jsbn": "~0.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 - }, - "ejs": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", - "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=", - "dev": true - }, - "electron-to-chromium": { - "version": "1.3.33", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.33.tgz", - "integrity": "sha1-vwBwPWKnxlI4E2V4w1LWxcBCpUU=", - "dev": true - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "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" - } - }, - "ember-cli-string-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz", - "integrity": "sha1-ObZ3/CgF9VFzc1N2/O8njqpEUqE=", - "dev": true - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "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" - } - }, - "engine.io": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.4.tgz", - "integrity": "sha1-PQIRtwpVLOhB/8fahiezAamkFi4=", - "dev": true, - "requires": { - "accepts": "1.3.3", - "base64id": "1.0.0", - "cookie": "0.3.1", - "debug": "~2.6.9", - "engine.io-parser": "~2.1.0", - "uws": "~0.14.4", - "ws": "~3.3.1" - }, - "dependencies": { - "accepts": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", - "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", - "dev": true, - "requires": { - "mime-types": "~2.1.11", - "negotiator": "0.6.1" - } - } - } - }, - "engine.io-client": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.4.tgz", - "integrity": "sha1-T88TcLRxY70s6b4nM5ckMDUNTqE=", - "dev": true, - "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "~2.6.9", - "engine.io-parser": "~2.1.1", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "~3.3.1", - "xmlhttprequest-ssl": "~1.5.4", - "yeast": "0.1.2" - } - }, - "engine.io-parser": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", - "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", - "dev": true, - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.4", - "has-binary2": "~1.0.2" - } - }, - "enhanced-resolve": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", - "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "memory-fs": "^0.4.0", - "object-assign": "^4.0.1", - "tapable": "^0.2.7" - } - }, - "ent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", - "dev": true - }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", - "dev": true - }, - "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.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.10.0.tgz", - "integrity": "sha512-/uh/DhdqIOSkAWifU+8nG78vlQxdLckUdI/sPgy0VhuXi2qJ7T8czBmqIYtLQVpCIFYafChnsRsB5pyb1JdmCQ==", - "dev": true, - "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" - } - }, - "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", - "dev": true, - "requires": { - "is-callable": "^1.1.1", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.1" - } - }, - "es5-ext": { - "version": "0.10.37", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz", - "integrity": "sha1-DudB0Ui4AGm6J9AgOTdWryV978M=", - "dev": true, - "requires": { - "es6-iterator": "~2.0.1", - "es6-symbol": "~3.1.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-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-set": "~0.1.5", - "es6-symbol": "~3.1.1", - "event-emitter": "~0.3.5" - } - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14", - "es6-iterator": "~2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "~0.3.5" - } - }, - "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-weak-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.14", - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, - "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.9.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz", - "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==", - "dev": true, - "optional": true, - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.5.6" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true, - "optional": true - } - } - }, - "escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "dev": true, - "requires": { - "es6-map": "^0.1.3", - "es6-weak-map": "^2.0.1", - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "esrecurse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", - "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", - "dev": true, - "requires": { - "estraverse": "^4.1.0", - "object-assign": "^4.0.1" - } - }, - "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 - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, - "eventemitter3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", - "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", - "dev": true - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", - "dev": true - }, - "eventsource": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", - "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", - "dev": true, - "requires": { - "original": ">=0.0.5" - } - }, - "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" - } - }, - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-braces": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", - "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", - "dev": true, - "requires": { - "array-slice": "^0.2.3", - "array-unique": "^0.2.1", - "braces": "^0.1.2" - }, - "dependencies": { - "braces": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", - "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", - "dev": true, - "requires": { - "expand-range": "^0.1.0" - } - }, - "expand-range": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", - "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", - "dev": true, - "requires": { - "is-number": "^0.1.1", - "repeat-string": "^0.2.2" - } - }, - "is-number": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", - "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", - "dev": true - }, - "repeat-string": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", - "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", - "dev": true - } - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "dev": true, - "requires": { - "fill-range": "^2.1.0" - } - }, - "exports-loader": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.6.4.tgz", - "integrity": "sha1-1w/GEhl1s1/BKDDPUnVL4nQPyIY=", - "dev": true, - "requires": { - "loader-utils": "^1.0.2", - "source-map": "0.5.x" - } - }, - "express": { - "version": "4.16.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", - "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "array-flatten": "1.1.1", - "body-parser": "1.18.2", - "content-disposition": "0.5.2", - "content-type": "~1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.1", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.1.0", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.2", - "qs": "6.5.1", - "range-parser": "~1.2.0", - "safe-buffer": "5.1.1", - "send": "0.16.1", - "serve-static": "1.13.1", - "setprototypeof": "1.1.0", - "statuses": "~1.3.1", - "type-is": "~1.6.15", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true - } - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "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" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "extract-text-webpack-plugin": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", - "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", - "dev": true, - "requires": { - "async": "^2.4.1", - "loader-utils": "^1.1.0", - "schema-utils": "^0.3.0", - "webpack-sources": "^1.0.1" - } - }, - "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": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", - "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, - "optional": true - }, - "fastparse": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", - "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=", - "dev": true - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - }, - "file-loader": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.6.tgz", - "integrity": "sha512-873ztuL+/hfvXbLDJ262PGO6XjERnybJu2gW1/5j8HUfxSiFJI9Hj/DhZ50ZGRUxBvuNiazb/cM2rh9pqrxP6Q==", - "dev": true, - "requires": { - "loader-utils": "^1.0.2", - "schema-utils": "^0.3.0" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", - "dev": true - }, - "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": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^1.1.3", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", - "unpipe": "~1.0.0" - } - }, - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.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" - } - }, - "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.0.2", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz", - "integrity": "sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - } - }, - "follow-redirects": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", - "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", - "dev": true, - "optional": true, - "requires": { - "debug": "^2.2.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "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.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "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-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", - "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", - "dev": true, - "requires": { - "null-check": "^1.0.0" - } - }, - "fs-extra": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", - "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.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=", - "dev": true - }, - "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", - "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 - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "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 - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": 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.5.1", - "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.2", - "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.21", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": "^2.1.0" - } - }, - "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 - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": 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, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "minipass": { - "version": "2.2.4", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "^5.1.1", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.2.0", - "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.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.1.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.3", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.1.10", - "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 - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": 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.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.5.1", - "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.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.0.5" - } - }, - "safe-buffer": { - "version": "5.1.1", - "bundled": true, - "dev": 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.5.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, - "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, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.0.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "yallist": { - "version": "3.0.2", - "bundled": true, - "dev": 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" - } - }, - "ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", - "dev": true, - "optional": true, - "requires": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true, - "optional": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "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" - } - }, - "gaze": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", - "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", - "dev": true, - "optional": true, - "requires": { - "globule": "^1.0.0" - } - }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true, - "optional": true - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "optional": true, - "requires": { - "is-property": "^1.0.0" - } - }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", - "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-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.1.tgz", - "integrity": "sha512-7aelVrYqCLuVjq2kEKRTH8fXPTC0xKTkM+G7UlFkEwCXY3sFbSxvY375JoFowOAYbkaU47SrBvOefUlLZZ+6QA==", - "dev": true, - "optional": true, - "requires": { - "data-uri-to-buffer": "1", - "debug": "2", - "extend": "3", - "file-uri-to-path": "1", - "ftp": "~0.3.10", - "readable-stream": "2" - } - }, - "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" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "dev": true, - "requires": { - "glob-parent": "^2.0.0", - "is-glob": "^2.0.0" - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", - "dev": true - }, - "globby": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", - "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "dir-glob": "^2.0.0", - "glob": "^7.1.2", - "ignore": "^3.3.5", - "pify": "^3.0.0", - "slash": "^1.0.0" - } - }, - "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", - "dev": true, - "optional": true, - "requires": { - "glob": "~7.1.1", - "lodash": "~4.17.10", - "minimatch": "~3.0.2" - }, - "dependencies": { - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", - "dev": true, - "optional": true - } - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "hammerjs": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" - }, - "handle-thing": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", - "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", - "dev": true - }, - "handlebars": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", - "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", - "dev": true, - "requires": { - "async": "^1.4.0", - "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true, - "optional": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "optional": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "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" - } - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dev": true, - "optional": true, - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "optional": true - } - } - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "optional": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "requires": { - "ajv": "^4.9.1", - "har-schema": "^1.0.5" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "requires": { - "co": "^4.6.0", - "json-stable-stringify": "^1.0.1" - } - } - } - }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "dev": true, - "requires": { - "function-bind": "^1.0.2" - } - }, - "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-binary2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", - "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=", - "dev": true, - "requires": { - "isarray": "2.0.1" - }, - "dependencies": { - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true - } - } - }, - "has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", - "dev": true - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", - "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" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "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": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", - "dev": true, - "requires": { - "inherits": "^2.0.1" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "hipchat-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz", - "integrity": "sha1-ttJJdVQ3wZEII2d5nTupoPI7Ix4=", - "dev": true, - "optional": true, - "requires": { - "lodash": "^4.0.0", - "request": "^2.0.0" - } - }, - "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" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", - "dev": true - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" - } - }, - "html-comment-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", - "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", - "dev": true - }, - "html-entities": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", - "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", - "dev": true - }, - "html-minifier": { - "version": "3.5.9", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.9.tgz", - "integrity": "sha512-EZqO91XJwkj8BeLx9C12sKB/AHoTANaZax39vEOP9f/X/9jgJ3r1O2+neabuHqpz5kJO71TapP9JrtCY39su1A==", - "dev": true, - "requires": { - "camel-case": "3.0.x", - "clean-css": "4.1.x", - "commander": "2.14.x", - "he": "1.1.x", - "ncname": "1.0.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.3.x" - } - }, - "html-webpack-plugin": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz", - "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=", - "dev": true, - "requires": { - "bluebird": "^3.4.7", - "html-minifier": "^3.2.3", - "loader-utils": "^0.2.16", - "lodash": "^4.17.3", - "pretty-error": "^2.0.2", - "toposort": "^1.0.0" - }, - "dependencies": { - "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" - } - } - } - }, - "htmlescape": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", - "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", - "dev": true - }, - "htmlparser2": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", - "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", - "dev": true, - "requires": { - "domelementtype": "1", - "domhandler": "2.1", - "domutils": "1.1", - "readable-stream": "1.0" - }, - "dependencies": { - "domutils": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", - "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", - "dev": true - }, - "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "dev": true, - "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": ">= 1.3.1 < 2" - }, - "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", - "dev": true - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", - "dev": true - } - } - }, - "http-parser-js": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", - "dev": true - }, - "http-proxy": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", - "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", - "dev": true, - "requires": { - "eventemitter3": "1.x.x", - "requires-port": "1.x.x" - } - }, - "http-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz", - "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=", - "dev": true, - "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3" - } - }, - "http-proxy-middleware": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", - "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", - "dev": true, - "requires": { - "http-proxy": "^1.16.2", - "is-glob": "^3.1.0", - "lodash": "^4.17.2", - "micromatch": "^2.3.11" - }, - "dependencies": { - "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": "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" - } - } - } - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "httpntlm": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", - "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", - "dev": true, - "requires": { - "httpreq": ">=0.4.22", - "underscore": "~1.7.0" - } - }, - "httpreq": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", - "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", - "dev": true - }, - "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 - }, - "https-proxy-agent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", - "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", - "dev": true, - "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3" - } - }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" - }, - "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" - } - }, - "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", - "dev": true - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", - "dev": true - }, - "ignore": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", - "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", - "dev": true - }, - "image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", - "dev": true, - "optional": 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, - "optional": true - }, - "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 - }, - "inflection": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.10.0.tgz", - "integrity": "sha1-W//LEZetPoEFD44X4hZoCH7p6y8=", - "dev": true, - "optional": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, - "inline-source-map": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", - "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", - "dev": true, - "requires": { - "source-map": "~0.5.3" - } - }, - "insert-module-globals": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz", - "integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "combine-source-map": "~0.7.1", - "concat-stream": "~1.5.1", - "is-buffer": "^1.1.0", - "lexical-scope": "^1.2.0", - "process": "~0.11.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "combine-source-map": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz", - "integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=", - "dev": true, - "requires": { - "convert-source-map": "~1.1.0", - "inline-source-map": "~0.6.0", - "lodash.memoize": "~3.0.3", - "source-map": "~0.5.3" - } - }, - "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" - } - }, - "convert-source-map": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", - "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", - "dev": true - }, - "lodash.memoize": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", - "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", - "dev": true - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "internal-ip": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", - "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", - "dev": true, - "requires": { - "meow": "^3.3.0" - } - }, - "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", - "dev": true - }, - "intl": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/intl/-/intl-1.2.5.tgz", - "integrity": "sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94=" - }, - "invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "dev": true, - "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 - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", - "dev": true - }, - "ipaddr.js": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", - "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=", - "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": "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" - }, - "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 - } - } - }, - "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-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "^1.0.0" - } - }, - "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", - "dev": true - }, - "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" - }, - "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 - } - } - }, - "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": "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" - }, - "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 - } - } - }, - "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-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", - "dev": true - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "dev": true, - "requires": { - "is-primitive": "^2.0.0" - } - }, - "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": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "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": "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" - } - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-my-ip-valid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true, - "optional": true - }, - "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", - "dev": true, - "optional": true, - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-odd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", - "integrity": "sha1-O4qTLrAos3dcObsJ6RdnrM22kIg=", - "dev": true, - "requires": { - "is-number": "^3.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" - } - } - } - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", - "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } - }, - "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==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", - "dev": true - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", - "dev": true - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true, - "optional": 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-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "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.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", - "dev": true - }, - "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-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 - }, - "isbinaryfile": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", - "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", - "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": "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" - } - }, - "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": "1.2.2", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.2.2.tgz", - "integrity": "sha512-kH5YRdqdbs5hiH4/Rr1Q0cSAGgjh3jTtg8vu9NLebBAoK3adVO4jk81J+TYOkTr2+Q4NLeb1ACvmEt65iG/Vbw==", - "dev": true, - "requires": { - "async": "^2.1.4", - "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.1.2", - "istanbul-lib-hook": "^1.1.0", - "istanbul-lib-instrument": "^1.9.2", - "istanbul-lib-report": "^1.1.3", - "istanbul-lib-source-maps": "^1.2.3", - "istanbul-reports": "^1.1.4", - "js-yaml": "^3.7.0", - "mkdirp": "^0.5.1", - "once": "^1.4.0" - } - }, - "istanbul-instrumenter-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.0.tgz", - "integrity": "sha512-alLSEFX06ApU75sm5oWcaVNaiss/bgMRiWTct3g0P0ZZTKjR+6QiCcuVOKDI1kWJgwHEnIXsv/dWm783kPpmtw==", - "dev": true, - "requires": { - "convert-source-map": "^1.5.0", - "istanbul-lib-instrument": "^1.7.3", - "loader-utils": "^1.1.0", - "schema-utils": "^0.3.0" - } - }, - "istanbul-lib-coverage": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.2.tgz", - "integrity": "sha512-tZYA0v5A7qBSsOzcebJJ/z3lk3oSzH62puG78DbBA1+zupipX2CakDyiPV3pOb8He+jBwVimuwB0dTnh38hX0w==", - "dev": true - }, - "istanbul-lib-hook": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz", - "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", - "dev": true, - "requires": { - "append-transform": "^0.4.0" - } - }, - "istanbul-lib-instrument": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.2.tgz", - "integrity": "sha512-nz8t4HQ2206a/3AXi+NHFWEa844DMpPsgbcUteJbt1j8LX1xg56H9rOMnhvcvVvPbW60qAIyrSk44H8ZDqaSSA==", - "dev": true, - "requires": { - "babel-generator": "^6.18.0", - "babel-template": "^6.16.0", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0", - "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.1.2", - "semver": "^5.3.0" - } - }, - "istanbul-lib-report": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.3.tgz", - "integrity": "sha512-D4jVbMDtT2dPmloPJS/rmeP626N5Pr3Rp+SovrPn1+zPChGHcggd/0sL29jnbm4oK9W0wHjCRsdch9oLd7cm6g==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "path-parse": "^1.0.5", - "supports-color": "^3.1.2" - }, - "dependencies": { - "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 - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz", - "integrity": "sha512-fDa0hwU/5sDXwAklXgAoCJCOsFsBplVQ6WBldz5UwaqOzmDhUK4nfuR7/G//G2lERlblUNJB8P6e8cXq3a7MlA==", - "dev": true, - "requires": { - "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.1.2", - "mkdirp": "^0.5.1", - "rimraf": "^2.6.1", - "source-map": "^0.5.3" - }, - "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" - } - } - } - }, - "istanbul-reports": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.4.tgz", - "integrity": "sha512-DfSTVOTkuO+kRmbO8Gk650Wqm1WRGr6lrdi2EwDK1vxpS71vdlLd613EpzOKdIFioB5f/scJTjeWBnvd1FWejg==", - "dev": true, - "requires": { - "handlebars": "^4.0.3" - } - }, - "jasmine": { - "version": "2.99.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.99.0.tgz", - "integrity": "sha1-jKctEC5jm4Z8ZImFbg4YqceqQrc=", - "dev": true, - "requires": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.99.0" - }, - "dependencies": { - "jasmine-core": { - "version": "2.99.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", - "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", - "dev": true - } - } - }, - "jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", - "dev": true - }, - "jasmine-spec-reporter": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", - "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", - "dev": true, - "requires": { - "colors": "1.1.2" - } - }, - "jasminewd2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", - "dev": true - }, - "js-base64": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", - "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==", - "dev": true - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, - "js-yaml": { - "version": "3.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" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true, - "optional": true - }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - }, - "json-loader": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", - "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", - "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.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } - }, - "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 - }, - "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", - "dev": true - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true, - "optional": 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" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "karma": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.0.tgz", - "integrity": "sha512-K9Kjp8CldLyL9ANSUctDyxC7zH3hpqXj/K09qVf06K3T/kXaHtFZ5tQciK7OzQu68FLvI89Na510kqQ2LCbpIw==", - "dev": true, - "requires": { - "bluebird": "^3.3.0", - "body-parser": "^1.16.1", - "browserify": "^14.5.0", - "chokidar": "^1.4.1", - "colors": "^1.1.0", - "combine-lists": "^1.0.0", - "connect": "^3.6.0", - "core-js": "^2.2.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.0", - "expand-braces": "^0.1.1", - "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "http-proxy": "^1.13.0", - "isbinaryfile": "^3.0.0", - "lodash": "^4.17.4", - "log4js": "^2.3.9", - "mime": "^1.3.4", - "minimatch": "^3.0.2", - "optimist": "^0.6.1", - "qjobs": "^1.1.4", - "range-parser": "^1.2.0", - "rimraf": "^2.6.0", - "safe-buffer": "^5.0.1", - "socket.io": "2.0.4", - "source-map": "^0.6.1", - "tmp": "0.0.33", - "useragent": "^2.1.12" - }, - "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 - } - } - }, - "karma-chrome-launcher": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", - "dev": true, - "requires": { - "fs-access": "^1.0.0", - "which": "^1.2.1" - } - }, - "karma-coverage-istanbul-reporter": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.1.tgz", - "integrity": "sha512-5og0toMjgLvsL9+TzGH4Rk1D0nr7pMIRJBg29xP4mHMKy/1KUJ12UzoqI6mBNCRFa4nDvZS2MRrN7p+RkZNWxQ==", - "dev": true, - "requires": { - "istanbul-api": "^1.1.14", - "minimatch": "^3.0.4" - } - }, - "karma-jasmine": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.1.tgz", - "integrity": "sha1-b+hA51oRYAydkehLM8RY4cRqNSk=", - "dev": true - }, - "karma-jasmine-html-reporter": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz", - "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", - "dev": true, - "requires": { - "karma-jasmine": "^1.0.2" - } - }, - "karma-source-map-support": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.2.0.tgz", - "integrity": "sha1-G/gee7SwiWJ6s1LsQXnhF8QGpUA=", - "dev": true, - "requires": { - "source-map-support": "^0.4.1" - } - }, - "killable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz", - "integrity": "sha1-2ouEvUfeU5WHj5XWTQLyRJ/gXms=", - "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" - } - }, - "labeled-stream-splicer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz", - "integrity": "sha1-pS4dE4AkwAuGscDJH2d5GLiuClk=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "isarray": "~0.0.1", - "stream-splicer": "^2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, - "lazy-cache": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", - "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", - "dev": true - }, - "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" - } - }, - "less": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", - "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", - "dev": true, - "requires": { - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "mime": "^1.2.11", - "mkdirp": "^0.5.0", - "promise": "^7.1.1", - "request": "2.81.0", - "source-map": "^0.5.3" - } - }, - "less-loader": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.0.5.tgz", - "integrity": "sha1-rhVadAbKxqzSk9eFWH/P8PR4xN0=", - "dev": true, - "requires": { - "clone": "^2.1.1", - "loader-utils": "^1.1.0", - "pify": "^2.3.0" - }, - "dependencies": { - "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "optional": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lexical-scope": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", - "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=", - "dev": true, - "requires": { - "astw": "^2.0.0" - } - }, - "libbase64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", - "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", - "dev": true - }, - "libmime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", - "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", - "dev": true, - "requires": { - "iconv-lite": "0.4.15", - "libbase64": "0.1.0", - "libqp": "1.1.0" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", - "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", - "dev": true - } - } - }, - "libqp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", - "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", - "dev": true - }, - "license-webpack-plugin": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-1.1.1.tgz", - "integrity": "sha512-TjKOyiC0exqd4Idy/4M8/DETR22dXBZks387DuS5LbslxHiMRXGx/Q2F/j9IUtvEoH5uFvt72vRgk/G6f8j3Dg==", - "dev": true, - "requires": { - "ejs": "^2.5.7" - } - }, - "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" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "loader-runner": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", - "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", - "dev": true - }, - "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "dev": true, - "requires": { - "big.js": "^3.1.3", - "emojis-list": "^2.0.0", - "json5": "^0.5.0" - } - }, - "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.5", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", - "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", - "dev": true - }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "dev": true, - "optional": 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.endswith": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.endswith/-/lodash.endswith-4.2.1.tgz", - "integrity": "sha1-/tWawXOO0+I27dcGTsRWRIs3vAk=", - "dev": true - }, - "lodash.isfunction": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", - "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", - "dev": true - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", - "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, - "optional": true - }, - "lodash.startswith": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz", - "integrity": "sha1-xZjErc4YiiflMUVzHNxsDnF3YAw=", - "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 - }, - "log4js": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.5.3.tgz", - "integrity": "sha512-YL/qpTxYtK0iWWbuKCrevDZz5lh+OjyHHD+mICqpjnYGKdNRBvPeh/1uYjkKUemT1CSO4wwLOwphWMpKAnD9kw==", - "dev": true, - "requires": { - "amqplib": "^0.5.2", - "axios": "^0.15.3", - "circular-json": "^0.5.1", - "date-format": "^1.2.0", - "debug": "^3.1.0", - "hipchat-notifier": "^1.1.0", - "loggly": "^1.1.0", - "mailgun-js": "^0.7.0", - "nodemailer": "^2.5.0", - "redis": "^2.7.1", - "semver": "^5.3.0", - "slack-node": "~0.2.0", - "streamroller": "^0.7.0" - }, - "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" - } - } - } - }, - "loggly": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/loggly/-/loggly-1.1.1.tgz", - "integrity": "sha1-Cg/B0/o6XsRP3HuJe+uipGlc6+4=", - "dev": true, - "optional": true, - "requires": { - "json-stringify-safe": "5.0.x", - "request": "2.75.x", - "timespan": "2.3.x" - }, - "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, - "optional": true - }, - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true, - "optional": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "optional": 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" - } - }, - "form-data": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", - "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", - "dev": true, - "optional": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.11" - } - }, - "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "dev": true, - "optional": true, - "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" - } - }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", - "dev": true, - "optional": true - }, - "qs": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", - "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", - "dev": true, - "optional": true - }, - "request": { - "version": "2.75.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", - "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "bl": "~1.1.2", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.0.0", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "node-uuid": "~1.4.7", - "oauth-sign": "~0.8.1", - "qs": "~6.2.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1" - } - }, - "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, - "optional": true - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true, - "optional": true - } - } - }, - "loglevel": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", - "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", - "dev": true - }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "dev": true, - "requires": { - "js-tokens": "^3.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 - }, - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "macaddress": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", - "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=", - "dev": true - }, - "magic-string": { - "version": "0.22.4", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.4.tgz", - "integrity": "sha512-kxBL06p6iO2qPBHsqGK2b3cRwiRGpnmSuVWNhwHcMX7qJOUr1HvricYP1LZOCdkQBUp0jiWg2d6WJwR3vYgByw==", - "dev": true, - "requires": { - "vlq": "^0.2.1" - } - }, - "mailcomposer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz", - "integrity": "sha1-DhxEsqB890DuF9wUm6AJ8Zyt/rQ=", - "dev": true, - "optional": true, - "requires": { - "buildmail": "4.0.1", - "libmime": "3.0.0" - } - }, - "mailgun-js": { - "version": "0.7.15", - "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.7.15.tgz", - "integrity": "sha1-7jZqINrGTDwVwD1sGz4O15UlKrs=", - "dev": true, - "optional": true, - "requires": { - "async": "~2.1.2", - "debug": "~2.2.0", - "form-data": "~2.1.1", - "inflection": "~1.10.0", - "is-stream": "^1.1.0", - "path-proxy": "~1.0.0", - "proxy-agent": "~2.0.0", - "q": "~1.4.0", - "tsscmp": "~1.0.0" - }, - "dependencies": { - "async": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/async/-/async-2.1.5.tgz", - "integrity": "sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw=", - "dev": true, - "optional": true, - "requires": { - "lodash": "^4.14.0" - } - }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "optional": 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, - "optional": true - }, - "q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", - "dev": true, - "optional": true - } - } - }, - "make-dir": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.1.0.tgz", - "integrity": "sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "make-error": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", - "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", - "dev": true - }, - "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-design-icons-iconfont": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-3.0.3.tgz", - "integrity": "sha1-FUoQhAR9Ticjf6f1o34Qdc7qbfI=" - }, - "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.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", - "dev": true, - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - }, - "dependencies": { - "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" - } - } - } - }, - "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": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "dev": true, - "requires": { - "mimic-fn": "^1.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-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "dev": true, - "requires": { - "arr-diff": "^2.0.0", - "array-unique": "^0.2.1", - "braces": "^1.8.2", - "expand-brackets": "^0.1.4", - "extglob": "^0.3.1", - "filename-regex": "^2.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.1", - "kind-of": "^3.0.2", - "normalize-path": "^2.0.1", - "object.omit": "^2.0.0", - "parse-glob": "^3.0.4", - "regex-cache": "^0.4.2" - } - }, - "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": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", - "dev": true - }, - "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "dev": true, - "requires": { - "mime-db": "~1.30.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.0", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", - "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=", - "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==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mississippi": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-1.3.1.tgz", - "integrity": "sha512-/6rB8YXFbAtsUVRphIRQqB0+9c7VaPHCjVtvto+JqwVxgz8Zz+I+f68/JgQ+Pb4VlZb2svA9OtdXnHHsZz7ltg==", - "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": "^1.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" - } - }, - "module-deps": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz", - "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=", - "dev": true, - "requires": { - "JSONStream": "^1.0.3", - "browser-resolve": "^1.7.0", - "cached-path-relative": "^1.0.0", - "concat-stream": "~1.5.0", - "defined": "^1.0.0", - "detective": "^4.0.0", - "duplexer2": "^0.1.2", - "inherits": "^2.0.1", - "parents": "^1.0.0", - "readable-stream": "^2.0.2", - "resolve": "^1.1.3", - "stream-combiner2": "^1.1.1", - "subarg": "^1.0.0", - "through2": "^2.0.0", - "xtend": "^4.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - } - } - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "moment": { - "version": "2.18.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", - "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" - }, - "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.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "multicast-dns": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", - "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", - "dev": true, - "requires": { - "dns-packet": "^1.3.1", - "thunky": "^1.0.2" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", - "dev": true - }, - "mydaterangepicker": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/mydaterangepicker/-/mydaterangepicker-4.2.1.tgz", - "integrity": "sha1-8GPkdHAWJZua2IIVnvwcffCSIc0=" - }, - "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.7.tgz", - "integrity": "sha512-/5ldsnyurvEw7wNpxLFgjVvBLMta43niEYOy0CJ4ntcYSbx6bugRUTQeFb4BR/WanEL1o3aQgHuVLHQaB6tOqg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "is-odd": "^1.0.0", - "kind-of": "^5.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": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "ncname": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz", - "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=", - "dev": true, - "requires": { - "xml-char-classes": "^1.0.0" - } - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", - "dev": true - }, - "netmask": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", - "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", - "dev": true, - "optional": true - }, - "ng2-charts": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-1.6.0.tgz", - "integrity": "sha512-9w0WH69x5/nuqC1og2WaY39NbaBqTGIP1+5gZaH7/KPN6UEPonNg/pYnsIVklLj1DWPWXKa8+XXIJZ1jy5nLxg==", - "requires": { - "chart.js": "^2.6.0" - } - }, - "ng2-cookies": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/ng2-cookies/-/ng2-cookies-1.0.12.tgz", - "integrity": "sha1-Pz5hPgE3sGSbcFxngHS0vQgUnMw=" - }, - "ngx-loading": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/ngx-loading/-/ngx-loading-1.0.14.tgz", - "integrity": "sha1-GXWMM+o/qbuW3KH0DKGdTYa4BCw=" - }, - "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-forge": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.1.tgz", - "integrity": "sha1-naYR6giYL0uUIGs760zJZl8gwwA=", - "dev": true - }, - "node-gyp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", - "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", - "dev": true, - "optional": true, - "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "2", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" - }, - "dependencies": { - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "dev": true, - "optional": true, - "requires": { - "abbrev": "1" - } - }, - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true, - "optional": true - } - } - }, - "node-libs-browser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", - "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", - "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": "^1.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.10.3", - "vm-browserify": "0.0.4" - } - }, - "node-modules-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz", - "integrity": "sha1-QAlrCM560OoUaAhjr0ScfHWl0cg=", - "dev": true - }, - "node-sass": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", - "integrity": "sha512-QFHfrZl6lqRU3csypwviz2XLgGNOoWQbo2GOvtsfQqOfL4cy1BtWnhx/XUeAO9LT3ahBzSRXcEO6DdvAH9DzSg==", - "dev": true, - "optional": 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.3.1", - "npmlog": "^4.0.0", - "request": "~2.79.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 - }, - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true, - "optional": 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" - } - }, - "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", - "dev": true, - "optional": true, - "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" - } - }, - "qs": { - "version": "6.3.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", - "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", - "dev": true, - "optional": true - }, - "request": { - "version": "2.79.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", - "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "qs": "~6.3.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1", - "uuid": "^3.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 - }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true, - "optional": true - } - } - }, - "nodemailer": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-2.7.2.tgz", - "integrity": "sha1-8kLmSa7q45tsftdA73sGHEBNMPk=", - "dev": true, - "optional": true, - "requires": { - "libmime": "3.0.0", - "mailcomposer": "4.0.1", - "nodemailer-direct-transport": "3.3.2", - "nodemailer-shared": "1.1.0", - "nodemailer-smtp-pool": "2.8.2", - "nodemailer-smtp-transport": "2.7.2", - "socks": "1.1.9" - }, - "dependencies": { - "socks": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", - "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", - "dev": true, - "optional": true, - "requires": { - "ip": "^1.1.2", - "smart-buffer": "^1.0.4" - } - } - } - }, - "nodemailer-direct-transport": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", - "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", - "dev": true, - "optional": true, - "requires": { - "nodemailer-shared": "1.1.0", - "smtp-connection": "2.12.0" - } - }, - "nodemailer-fetch": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", - "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=", - "dev": true - }, - "nodemailer-shared": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", - "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", - "dev": true, - "requires": { - "nodemailer-fetch": "1.6.0" - } - }, - "nodemailer-smtp-pool": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz", - "integrity": "sha1-LrlNbPhXgLG0clzoU7nL1ejajHI=", - "dev": true, - "optional": true, - "requires": { - "nodemailer-shared": "1.1.0", - "nodemailer-wellknown": "0.1.10", - "smtp-connection": "2.12.0" - } - }, - "nodemailer-smtp-transport": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz", - "integrity": "sha1-A9ccdjFPFKx9vHvwM6am0W1n+3c=", - "dev": true, - "optional": true, - "requires": { - "nodemailer-shared": "1.1.0", - "nodemailer-wellknown": "0.1.10", - "smtp-connection": "2.12.0" - } - }, - "nodemailer-wellknown": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", - "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", - "dev": true - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "dev": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.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-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.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", - "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", - "dev": true, - "requires": { - "boolbase": "~1.0.0" - } - }, - "null-check": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", - "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", - "dev": true - }, - "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 - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "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=", - "dev": true - }, - "object-component": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", - "dev": true - }, - "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" - } - }, - "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-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-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 - } - } - } - } - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", - "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" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "dev": true, - "requires": { - "for-own": "^0.1.4", - "is-extendable": "^0.1.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" - }, - "dependencies": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "obuf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.1.tgz", - "integrity": "sha1-EEEktsYCxnlogaBCVB0220OlJk4=", - "dev": true - }, - "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" - } - }, - "on-headers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "opn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", - "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", - "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, - "optional": 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, - "optional": true - } - } - }, - "options": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", - "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", - "dev": true - }, - "original": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", - "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=", - "dev": true, - "requires": { - "url-parse": "1.0.x" - }, - "dependencies": { - "url-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz", - "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=", - "dev": true, - "requires": { - "querystringify": "0.0.x", - "requires-port": "1.0.x" - } - } - } - }, - "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": "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" - } - }, - "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-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", - "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-map": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", - "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", - "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 - }, - "pac-proxy-agent": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz", - "integrity": "sha512-QBELCWyLYPgE2Gj+4wUEiMscHrQ8nRPBzYItQNOHWavwBt25ohZHQC4qnd5IszdVVrFbLsQ+dPkm6eqdjJAmwQ==", - "dev": true, - "optional": true, - "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3", - "get-uri": "2", - "http-proxy-agent": "1", - "https-proxy-agent": "1", - "pac-resolver": "~2.0.0", - "raw-body": "2", - "socks-proxy-agent": "2" - } - }, - "pac-resolver": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-2.0.0.tgz", - "integrity": "sha1-mbiNLxk/ve78HJpSnB8yYKtSd80=", - "dev": true, - "optional": true, - "requires": { - "co": "~3.0.6", - "degenerator": "~1.0.2", - "ip": "1.0.1", - "netmask": "~1.0.4", - "thunkify": "~2.1.1" - }, - "dependencies": { - "co": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/co/-/co-3.0.6.tgz", - "integrity": "sha1-FEXyJsXrlWE45oyawwFn6n0ua9o=", - "dev": true, - "optional": true - }, - "ip": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.0.1.tgz", - "integrity": "sha1-x+NWzeoiWucbNtcPLnGpK6TkJZA=", - "dev": true, - "optional": true - } - } - }, - "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", - "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" - } - }, - "parents": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", - "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", - "dev": true, - "requires": { - "path-platform": "~0.11.15" - } - }, - "parse-asn1": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", - "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", - "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" - } - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "dev": true, - "requires": { - "glob-base": "^0.3.0", - "is-dotfile": "^1.0.0", - "is-extglob": "^1.0.0", - "is-glob": "^2.0.0" - } - }, - "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 - }, - "parseqs": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", - "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", - "dev": true, - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseuri": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", - "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", - "dev": true, - "requires": { - "better-assert": "~1.0.0" - } - }, - "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=", - "dev": true - }, - "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.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", - "dev": true - }, - "path-proxy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", - "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=", - "dev": true, - "optional": true, - "requires": { - "inflection": "~1.3.0" - }, - "dependencies": { - "inflection": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz", - "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4=", - "dev": true, - "optional": true - } - } - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "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" - } - }, - "pbkdf2": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", - "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", - "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": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "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" - } - }, - "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" - } - }, - "portfinder": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz", - "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", - "dev": true, - "requires": { - "async": "^1.5.2", - "debug": "^2.2.0", - "mkdirp": "0.5.x" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - } - } - }, - "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": "6.0.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.18.tgz", - "integrity": "sha512-X8MyLi3OYI1o71u0SsefWLpGBo5xnGiK1Pn+nrZFplc671Ts7L8aPwEbPIO8AWpulK5wuaVzyM9Rw6R8o7hYBw==", - "dev": true, - "requires": { - "chalk": "^2.3.1", - "source-map": "^0.6.1", - "supports-color": "^5.2.0" - }, - "dependencies": { - "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.2.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 - }, - "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 - }, - "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", - "dev": true, - "requires": { - "has-flag": "^3.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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-filter-plugins": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", - "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", - "dev": true, - "requires": { - "postcss": "^5.0.4", - "uniqid": "^4.0.0" - }, - "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 - }, - "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" - } - }, - "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-import": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", - "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", - "dev": true, - "requires": { - "postcss": "^6.0.1", - "postcss-value-parser": "^3.2.3", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - }, - "postcss-load-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", - "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", - "dev": true, - "requires": { - "cosmiconfig": "^2.1.0", - "object-assign": "^4.1.0", - "postcss-load-options": "^1.2.0", - "postcss-load-plugins": "^2.3.0" - } - }, - "postcss-load-options": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", - "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", - "dev": true, - "requires": { - "cosmiconfig": "^2.1.0", - "object-assign": "^4.1.0" - } - }, - "postcss-load-plugins": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", - "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", - "dev": true, - "requires": { - "cosmiconfig": "^2.1.1", - "object-assign": "^4.1.0" - } - }, - "postcss-loader": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.0.tgz", - "integrity": "sha512-S/dKzpDwGFmP9g8eyCu9sUIV+/+3UooeTpYlsKf23qKDdrhHuA4pTSfytVu0rEJ0iDqUavXrgtOPq5KhNyNMOw==", - "dev": true, - "requires": { - "loader-utils": "^1.1.0", - "postcss": "^6.0.0", - "postcss-load-config": "^1.2.0", - "schema-utils": "^0.4.0" - }, - "dependencies": { - "ajv": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", - "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-keywords": "^3.1.0" - } - } - } - }, - "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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "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" - } - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-modules-extract-imports": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz", - "integrity": "sha1-ZhQOzs447wa/DT41XWm/WdFB6oU=", - "dev": true, - "requires": { - "postcss": "^6.0.1" - } - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-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" - }, - "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 - }, - "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" - } - }, - "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-url": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-7.3.0.tgz", - "integrity": "sha512-VBP6uf6iL3AZra23nkPkOEkS/5azj1xf/toRrjfkolfFEgg9Gyzg9UhJZeIsz12EGKZTNVeGbPa2XtaZm/iZvg==", - "dev": true, - "requires": { - "mime": "^1.4.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.0", - "postcss": "^6.0.1", - "xxhashjs": "^0.2.1" - } - }, - "postcss-value-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", - "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", - "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" - }, - "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 - }, - "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" - } - }, - "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" - } - } - } - }, - "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 - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "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" - } - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "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==", - "dev": true, - "optional": true, - "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 - }, - "protractor": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.1.2.tgz", - "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", - "dev": true, - "requires": { - "@types/node": "^6.0.46", - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "~2.53.39", - "blocking-proxy": "0.0.5", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "^2.5.3", - "jasminewd2": "^2.1.0", - "optimist": "~0.6.0", - "q": "1.4.1", - "saucelabs": "~1.3.0", - "selenium-webdriver": "3.0.1", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "^1.0.0", - "webdriver-manager": "^12.0.6" - }, - "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" - } - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - } - }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", - "dev": true - }, - "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 - }, - "webdriver-manager": { - "version": "12.0.6", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz", - "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", - "dev": true, - "requires": { - "adm-zip": "^0.4.7", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.78.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - } - } - } - }, - "proxy-addr": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", - "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", - "dev": true, - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.5.2" - } - }, - "proxy-agent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-2.0.0.tgz", - "integrity": "sha1-V+tTR6qAXXTsaByyVknbo5yTNJk=", - "dev": true, - "optional": true, - "requires": { - "agent-base": "2", - "debug": "2", - "extend": "3", - "http-proxy-agent": "1", - "https-proxy-agent": "1", - "lru-cache": "~2.6.5", - "pac-proxy-agent": "1", - "socks-proxy-agent": "2" - }, - "dependencies": { - "lru-cache": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz", - "integrity": "sha1-5W1jVBSO3o13B7WNFDIg/QjfD9U=", - "dev": true, - "optional": true - } - } - }, - "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 - }, - "public-encrypt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", - "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", - "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" - } - }, - "pump": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", - "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.4.0.tgz", - "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", - "dev": true, - "requires": { - "duplexify": "^3.5.3", - "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": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "q": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", - "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", - "dev": true - }, - "qjobs": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz", - "integrity": "sha1-ZZ3p8s+NzCehSBJ28gU3cnI4LnM=", - "dev": true - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "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 - }, - "querystringify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz", - "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", - "dev": true - }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", - "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" - } - } - } - }, - "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "randomfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz", - "integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==", - "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 - }, - "raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "dev": true, - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", - "unpipe": "1.0.0" - } - }, - "raw-loader": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", - "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=", - "dev": true - }, - "read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", - "dev": true, - "requires": { - "pify": "^2.3.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "read-only-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", - "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "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" - }, - "dependencies": { - "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" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, - "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.4", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", - "integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==", - "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.0.3", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" - } - }, - "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" - } - }, - "redis": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", - "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", - "dev": true, - "optional": true, - "requires": { - "double-ended-queue": "^2.1.0-0", - "redis-commands": "^1.2.0", - "redis-parser": "^2.6.0" - } - }, - "redis-commands": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz", - "integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs=", - "dev": true, - "optional": true - }, - "redis-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", - "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", - "dev": true, - "optional": true - }, - "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 - } - } - }, - "reflect-metadata": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", - "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==", - "dev": true - }, - "regenerate": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", - "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", - "dev": true - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", - "dev": true - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "dev": true, - "requires": { - "is-equal-shallow": "^0.1.3" - } - }, - "regex-not": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.0.tgz", - "integrity": "sha1-Qvg+OXcWIt+CawKvF2Ul1qXxV/k=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1" - } - }, - "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" - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "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.1", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz", - "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", - "dev": true, - "requires": { - "css-select": "^1.1.0", - "dom-converter": "~0.1", - "htmlparser2": "~3.3.0", - "strip-ansi": "^3.0.0", - "utila": "~0.3" - }, - "dependencies": { - "utila": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", - "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", - "dev": true - } - } - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "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.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.1.1", - "har-validator": "~4.2.1", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "oauth-sign": "~0.8.1", - "performance-now": "^0.2.0", - "qs": "~6.4.0", - "safe-buffer": "^5.0.1", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.0.0" - } - }, - "requestretry": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", - "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", - "dev": true, - "optional": true, - "requires": { - "extend": "^3.0.0", - "lodash": "^4.15.0", - "request": "^2.74.0", - "when": "^3.7.7" - }, - "dependencies": { - "when": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", - "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", - "dev": true, - "optional": true - } - } - }, - "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": "1.2.1", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", - "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", - "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 - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", - "dev": true - }, - "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", - "dev": true, - "requires": { - "path-parse": "^1.0.5" - } - }, - "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-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "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 - }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "requires": { - "align-text": "^0.1.1" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "dev": true, - "requires": { - "glob": "^7.0.5" - } - }, - "ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", - "dev": true, - "requires": { - "hash-base": "^2.0.0", - "inherits": "^2.0.1" - } - }, - "roboto-fontface": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.8.0.tgz", - "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ==" - }, - "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" - } - }, - "rw": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" - }, - "rxjs": { - "version": "5.5.6", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.6.tgz", - "integrity": "sha512-v4Q5HDC0FHAQ7zcBX7T2IL6O5ltl1a2GX4ENjPXg6SjDY69Cmx9v4113C99a4wGF16ClPv5Z8mghuYorVkg/kg==", - "requires": { - "symbol-observable": "1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "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, - "optional": true, - "requires": { - "glob": "^7.0.0", - "lodash": "^4.0.0", - "scss-tokenizer": "^0.2.3", - "yargs": "^7.0.0" - } - }, - "sass-loader": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-6.0.6.tgz", - "integrity": "sha512-c3/Zc+iW+qqDip6kXPYLEgsAu2lf4xz0EZDplB7EmSUMda12U1sGJPetH55B/j9eu0bTtKzKlNPWWyYC7wFNyQ==", - "dev": true, - "requires": { - "async": "^2.1.5", - "clone-deep": "^0.3.0", - "loader-utils": "^1.0.1", - "lodash.tail": "^4.1.1", - "pify": "^3.0.0" - } - }, - "saucelabs": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", - "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", - "dev": true, - "requires": { - "https-proxy-agent": "^1.0.0" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "schema-utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", - "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", - "dev": true, - "requires": { - "ajv": "^5.0.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, - "optional": 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, - "optional": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", - "dev": true - }, - "selenium-webdriver": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz", - "integrity": "sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=", - "dev": true, - "requires": { - "adm-zip": "^0.4.7", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" - }, - "dependencies": { - "tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.1" - } - } - } - }, - "selfsigned": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.2.tgz", - "integrity": "sha1-tESVgNmZKbZbEKSDiTAaZZIIh1g=", - "dev": true, - "requires": { - "node-forge": "0.7.1" - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", - "dev": true - }, - "semver-compare-multi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/semver-compare-multi/-/semver-compare-multi-1.0.3.tgz", - "integrity": "sha1-PhaVtL2MStvQGsHEb6CEZtNp3Ug=" - }, - "semver-dsl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", - "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", - "dev": true, - "requires": { - "semver": "^5.3.0" - } - }, - "send": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", - "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.1", - "destroy": "~1.0.4", - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.6.2", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "~2.3.0", - "range-parser": "~1.2.0", - "statuses": "~1.3.1" - }, - "dependencies": { - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", - "dev": true - } - } - }, - "serialize-javascript": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.4.0.tgz", - "integrity": "sha1-fJWFFNtqwkQ6irwGLcn3iGp/YAU=", - "dev": true - }, - "serve-index": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" - } - }, - "serve-static": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", - "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", - "dev": true, - "requires": { - "encodeurl": "~1.0.1", - "escape-html": "~1.0.3", - "parseurl": "~1.3.2", - "send": "0.16.1" - } - }, - "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-getter": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", - "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", - "dev": true, - "requires": { - "to-object-path": "^0.3.0" - } - }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "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" - } - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", - "dev": true - }, - "sha.js": { - "version": "2.4.10", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.10.tgz", - "integrity": "sha512-vnwmrFDlOExK4Nm16J2KMWHLrp14lBrjxMxBJpu++EnsuBmpiYaM/MEs46Vxxm/4FvdP5yTwuCTO9it5FSjrqA==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "shallow-clone": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", - "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", - "dev": true, - "requires": { - "is-extendable": "^0.1.1", - "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", - "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", - "dev": true, - "requires": { - "is-buffer": "^1.0.2" - } - } - } - }, - "shasum": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", - "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", - "dev": true, - "requires": { - "json-stable-stringify": "~0.0.0", - "sha.js": "~2.4.4" - }, - "dependencies": { - "json-stable-stringify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", - "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", - "dev": true, - "requires": { - "jsonify": "~0.0.0" - } - } - } - }, - "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 - }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dev": true, - "requires": { - "array-filter": "~0.0.0", - "array-map": "~0.0.0", - "array-reduce": "~0.0.0", - "jsonify": "~0.0.0" - } - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "silent-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz", - "integrity": "sha1-IglwbxyFCp8dENDYQJGLRvJuG8k=", - "dev": true, - "requires": { - "debug": "^2.2.0" - } - }, - "slack-node": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.2.0.tgz", - "integrity": "sha1-3kuN3aqLeT9h29KTgQT9q/N9+jA=", - "dev": true, - "optional": true, - "requires": { - "requestretry": "^1.2.2" - } - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "smart-buffer": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", - "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=", - "dev": true - }, - "smtp-connection": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", - "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", - "dev": true, - "requires": { - "httpntlm": "1.6.1", - "nodemailer-shared": "1.1.0" - } - }, - "snapdragon": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz", - "integrity": "sha1-4StUh/re0+PeoKyR6UAL91tAE3A=", - "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": "^2.0.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" - } - }, - "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 - } - } - }, - "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": { - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "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" - } - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } - }, - "socket.io": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", - "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", - "dev": true, - "requires": { - "debug": "~2.6.6", - "engine.io": "~3.1.0", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.0.4", - "socket.io-parser": "~3.1.1" - } - }, - "socket.io-adapter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", - "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", - "dev": true - }, - "socket.io-client": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", - "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", - "dev": true, - "requires": { - "backo2": "1.0.2", - "base64-arraybuffer": "0.1.5", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "~2.6.4", - "engine.io-client": "~3.1.0", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "socket.io-parser": "~3.1.1", - "to-array": "0.1.4" - } - }, - "socket.io-parser": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.2.tgz", - "integrity": "sha1-28IoIVH8T6675Aru3Ady66YZ9/I=", - "dev": true, - "requires": { - "component-emitter": "1.2.1", - "debug": "~2.6.4", - "has-binary2": "~1.0.2", - "isarray": "2.0.1" - }, - "dependencies": { - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true - } - } - }, - "sockjs": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", - "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", - "dev": true, - "requires": { - "faye-websocket": "^0.10.0", - "uuid": "^3.0.1" - } - }, - "sockjs-client": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz", - "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", - "dev": true, - "requires": { - "debug": "^2.6.6", - "eventsource": "0.1.6", - "faye-websocket": "~0.11.0", - "inherits": "^2.0.1", - "json3": "^3.3.2", - "url-parse": "^1.1.8" - }, - "dependencies": { - "faye-websocket": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", - "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", - "dev": true, - "requires": { - "websocket-driver": ">=0.5.1" - } - } - } - }, - "socks": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", - "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", - "dev": true, - "requires": { - "ip": "^1.1.4", - "smart-buffer": "^1.0.13" - } - }, - "socks-proxy-agent": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz", - "integrity": "sha512-sFtmYqdUK5dAMh85H0LEVFUCO7OhJJe1/z2x/Z6mxp3s7/QPf1RkZmpZy+BpuU0bEjcV9npqKjq9Y3kwFUjnxw==", - "dev": true, - "requires": { - "agent-base": "2", - "extend": "3", - "socks": "~1.1.5" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", - "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.1", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", - "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", - "dev": true, - "requires": { - "atob": "^2.0.0", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "^0.5.6" - } - }, - "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": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "dev": true, - "requires": { - "spdx-license-ids": "^1.0.2" - } - }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", - "dev": true - }, - "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", - "dev": true - }, - "spdy": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", - "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", - "dev": true, - "requires": { - "debug": "^2.6.8", - "handle-thing": "^1.2.5", - "http-deceiver": "^1.2.7", - "safe-buffer": "^5.0.1", - "select-hose": "^2.0.0", - "spdy-transport": "^2.0.18" - } - }, - "spdy-transport": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.20.tgz", - "integrity": "sha1-c15yBUxIayNU/onnAiVgBKOazk0=", - "dev": true, - "requires": { - "debug": "^2.6.8", - "detect-node": "^2.0.3", - "hpack.js": "^2.1.6", - "obuf": "^1.1.1", - "readable-stream": "^2.2.9", - "safe-buffer": "^5.0.1", - "wbuf": "^1.7.2" - } - }, - "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" - }, - "dependencies": { - "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" - } - }, - "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" - } - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "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", - "tweetnacl": "~0.14.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "ssri": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.2.2.tgz", - "integrity": "sha512-hm46mN8YSzjGuJtVocXPjwo0yTRXobXqYuK/tV6gr557/tRck4yWXKPRW8OxyJgRvcL3QgX+5ng/kMHBMco7KA==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.1" - } - }, - "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" - } - }, - "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 - } - } - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", - "dev": true - }, - "stdout-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", - "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", - "dev": true, - "optional": true, - "requires": { - "readable-stream": "^2.0.1" - } - }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", - "dev": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "^2.0.2" - } - }, - "stream-combiner2": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", - "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", - "dev": true, - "requires": { - "duplexer2": "~0.1.0", - "readable-stream": "^2.0.2" - } - }, - "stream-each": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", - "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-http": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.0.tgz", - "integrity": "sha512-sZOFxI/5xw058XIRHl4dU3dZ+TTOIGJR78Dvo0oEAejIt4ou27k+3ne1zYmCV+v7UucbxIFQuOgnkTVHh8YPnw==", - "dev": true, - "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.3.3", - "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 - }, - "stream-splicer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", - "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.2" - } - }, - "streamroller": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", - "dev": true, - "requires": { - "date-format": "^1.2.0", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "readable-stream": "^2.3.0" - }, - "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" - } - } - } - }, - "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-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" - } - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", - "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" - } - }, - "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.13.2", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.13.2.tgz", - "integrity": "sha1-dFMzhM9pjHEEx5URULSXF63C87s=", - "dev": true, - "requires": { - "loader-utils": "^1.0.2" - } - }, - "stylus": { - "version": "0.54.5", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", - "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", - "dev": true, - "requires": { - "css-parse": "1.7.x", - "debug": "*", - "glob": "7.0.x", - "mkdirp": "0.5.x", - "sax": "0.5.x", - "source-map": "0.1.x" - }, - "dependencies": { - "glob": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", - "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.2", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "sax": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", - "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", - "dev": true - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } - } - }, - "stylus-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.1.tgz", - "integrity": "sha1-d/SzT9Aw0lsmF7z1UT21sHMMQIk=", - "dev": true, - "requires": { - "loader-utils": "^1.0.2", - "lodash.clonedeep": "^4.5.0", - "when": "~3.6.x" - } - }, - "subarg": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", - "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", - "dev": true, - "requires": { - "minimist": "^1.1.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "dev": true, - "requires": { - "has-flag": "^2.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" - } - }, - "symbol-observable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", - "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" - }, - "syntax-error": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", - "dev": true, - "requires": { - "acorn-node": "^1.2.0" - } - }, - "tapable": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", - "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", - "dev": true - }, - "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", - "dev": true, - "optional": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.2", - "inherits": "2" - } - }, - "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.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "dev": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - } - }, - "thunkify": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", - "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", - "dev": true, - "optional": true - }, - "thunky": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz", - "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=", - "dev": true - }, - "time-stamp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz", - "integrity": "sha1-lcakRTDhW6jW9KPsuMOj+sRto1c=", - "dev": true - }, - "timers-browserify": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.6.tgz", - "integrity": "sha512-HQ3nbYRAowdVd0ckGFvmJPPCOH/CHleFN/Y0YQCX1DVaB7t+KFvisuyN09fuP8Jtp1CpfSh8O8bMkHbdbPe6Pw==", - "dev": true, - "requires": { - "setimmediate": "^1.0.4" - } - }, - "timespan": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", - "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=", - "dev": true, - "optional": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", - "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-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "dev": true - }, - "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.1", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.1.tgz", - "integrity": "sha1-FTWL7kosg712N3uh3ASdDxiDeq4=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "regex-not": "^1.0.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" - } - }, - "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 - } - } - }, - "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" - } - } - } - }, - "toposort": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.6.tgz", - "integrity": "sha1-wxdI5V0hDv/AD9zcfW5o19e7nOw=", - "dev": true - }, - "tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", - "dev": true, - "requires": { - "punycode": "^1.4.1" - } - }, - "tree-kill": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz", - "integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==", - "dev": true - }, - "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.2", - "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", - "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", - "dev": true, - "optional": true, - "requires": { - "glob": "^6.0.4" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", - "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", - "dev": true, - "optional": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "ts-node": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-4.1.0.tgz", - "integrity": "sha512-xcZH12oVg9PShKhy3UHyDmuDLV3y7iKwX25aMVPt1SIXSuAfWkFiGPEkg+th8R4YKW/QCxDoW7lJdb15lx6QWg==", - "dev": true, - "requires": { - "arrify": "^1.0.0", - "chalk": "^2.3.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.0", - "tsconfig": "^7.0.0", - "v8flags": "^3.0.0", - "yn": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.2.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 - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "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 - }, - "source-map-support": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.3.tgz", - "integrity": "sha512-eKkTgWYeBOQqFGXRfKabMFdnWepo51vWqEdoeikaEPFiJC7MCU5j2h4+6Q8npkZTeLGbSyecZvRxiSoWl3rh+w==", - "dev": true, - "requires": { - "source-map": "^0.6.0" - } - }, - "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "tsconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", - "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", - "dev": true, - "requires": { - "@types/strip-bom": "^3.0.0", - "@types/strip-json-comments": "0.0.30", - "strip-bom": "^3.0.0", - "strip-json-comments": "^2.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 - } - } - }, - "tsickle": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.26.0.tgz", - "integrity": "sha512-eWJ2CUfttGK0LqF9iJ/Avnxbj4M+fCyJ50Zag3wm73Fut1hsasPRHKxKdrMWVj4BMHnQNx7TO+DdNmLmJTSuNw==", - "dev": true, - "requires": { - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map": "^0.5.6", - "source-map-support": "^0.4.2" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "tslib": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", - "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==" - }, - "tslint": { - "version": "5.9.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", - "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", - "dev": true, - "requires": { - "babel-code-frame": "^6.22.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^3.2.0", - "glob": "^7.1.1", - "js-yaml": "^3.7.0", - "minimatch": "^3.0.4", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.12.1" - }, - "dependencies": { - "chalk": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", - "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.2.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 - }, - "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "tsscmp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", - "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc=", - "dev": true, - "optional": true - }, - "tsutils": { - "version": "2.21.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.21.1.tgz", - "integrity": "sha512-heMkdeQ9iUc90ynfiNo5Y+GXrEEGy86KMvnSTfHO+Q40AuNQ1lZGXcv58fuU9XTUxI0V7YIN9xPN+CO9b1Gn3w==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "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, - "optional": 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.15", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", - "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.15" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "typescript": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", - "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", - "dev": true - }, - "uglify-js": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.11.tgz", - "integrity": "sha512-AKLsYcdV+sS5eAE4NtVXF6f2u/DCQynQm0jTGxF261+Vltu1dYNuHzjqDmk11gInj+H/zJIM2EAwXG3MzPb3VA==", - "dev": true, - "requires": { - "commander": "~2.14.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 - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, - "uglifyjs-webpack-plugin": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.8.tgz", - "integrity": "sha512-XG8/QmR1pyPeE1kj2aigo5kos8umefB31zW+PMvAAytHSB0T/vQvN6sqt8+Sh+y0b0A7zlmxNi2dzRnj0wcqGA==", - "dev": true, - "requires": { - "cacache": "^10.0.1", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.2", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" - }, - "dependencies": { - "ajv": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", - "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", - "dev": true - }, - "schema-utils": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", - "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", - "dev": true, - "requires": { - "ajv": "^6.1.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 - }, - "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "dev": true, - "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - } - } - } - }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "dev": true - }, - "umd": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.1.tgz", - "integrity": "sha1-iuVW4RAR9jwllnCKiDclnwGz1g4=", - "dev": true - }, - "underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", - "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": { - "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 - }, - "uniqid": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", - "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", - "dev": true, - "requires": { - "macaddress": "^0.2.8" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", - "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "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 - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - } - } - }, - "upath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.2.tgz", - "integrity": "sha512-fCmij7T5LnwUme3dbnVSejvOHHlARjB3ikJFwgZfz386pHmf/gueuTLRFU94FZEaeCLlbQrweiUU700gG41tUw==", - "dev": true, - "requires": { - "lodash.endswith": "^4.2.1", - "lodash.isfunction": "^3.0.8", - "lodash.isstring": "^4.0.1", - "lodash.startswith": "^4.2.1" - } - }, - "upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", - "dev": true - }, - "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-loader": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz", - "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==", - "dev": true, - "requires": { - "loader-utils": "^1.0.2", - "mime": "^1.4.1", - "schema-utils": "^0.3.0" - } - }, - "url-parse": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.2.0.tgz", - "integrity": "sha512-DT1XbYAfmQP65M/mE6OALxmXzZ/z1+e5zk2TcSKe/KiYbNGZxgtttzC0mR/sjopbpOXcbniq7eIKmocJnUWlEw==", - "dev": true, - "requires": { - "querystringify": "~1.0.0", - "requires-port": "~1.0.0" - }, - "dependencies": { - "querystringify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz", - "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs=", - "dev": true - } - } - }, - "use": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", - "integrity": "sha1-riig1y+TvyJCKhii43mZMRLeyOg=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "lazy-cache": "^2.0.2" - }, - "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" - } - }, - "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" - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "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 - }, - "lazy-cache": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", - "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", - "dev": true, - "requires": { - "set-getter": "^0.1.0" - } - } - } - }, - "useragent": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", - "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", - "dev": true, - "requires": { - "lru-cache": "4.1.x", - "tmp": "0.0.x" - } - }, - "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" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", - "dev": true - }, - "uws": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/uws/-/uws-0.14.5.tgz", - "integrity": "sha1-Z6rzPEaypYel9mZtAPdpEyjxSdw=", - "dev": true, - "optional": true - }, - "v8flags": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.1.tgz", - "integrity": "sha1-3Oj8N5wX2fLJ6e142JzgAFKxt2s=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "dev": true, - "requires": { - "spdx-correct": "~1.0.0", - "spdx-expression-parse": "~1.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.1", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", - "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=", - "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" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - } - } - }, - "vlq": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", - "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", - "dev": true - }, - "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" - } - }, - "void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", - "dev": true - }, - "watchpack": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz", - "integrity": "sha1-ShRyvLuVK9Cpu0A2gB+VTfs5+qw=", - "dev": true, - "requires": { - "async": "^2.1.2", - "chokidar": "^1.7.0", - "graceful-fs": "^4.1.2" - } - }, - "wbuf": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.2.tgz", - "integrity": "sha1-1pe5nx9ZUS3ydRvkJ2nBWAtYAf4=", - "dev": true, - "requires": { - "minimalistic-assert": "^1.0.0" - } - }, - "web-animations-js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.1.tgz", - "integrity": "sha1-Om2bwVGWN3qQ+OKAP6UmIWWwRRA=" - }, - "webdriver-js-extender": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", - "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", - "dev": true, - "requires": { - "@types/selenium-webdriver": "^2.53.35", - "selenium-webdriver": "^2.53.2" - }, - "dependencies": { - "adm-zip": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", - "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", - "dev": true - }, - "sax": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", - "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=", - "dev": true - }, - "selenium-webdriver": { - "version": "2.53.3", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz", - "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=", - "dev": true, - "requires": { - "adm-zip": "0.4.4", - "rimraf": "^2.2.8", - "tmp": "0.0.24", - "ws": "^1.0.1", - "xml2js": "0.4.4" - } - }, - "tmp": { - "version": "0.0.24", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", - "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=", - "dev": true - }, - "ultron": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", - "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", - "dev": true - }, - "ws": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", - "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", - "dev": true, - "requires": { - "options": ">=0.0.5", - "ultron": "1.0.x" - } - }, - "xml2js": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", - "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", - "dev": true, - "requires": { - "sax": "0.6.x", - "xmlbuilder": ">=1.0.0" - } - } - } - }, - "webpack": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz", - "integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==", - "dev": true, - "requires": { - "acorn": "^5.0.0", - "acorn-dynamic-import": "^2.0.0", - "ajv": "^5.1.5", - "ajv-keywords": "^2.0.0", - "async": "^2.1.2", - "enhanced-resolve": "^3.4.0", - "escope": "^3.6.0", - "interpret": "^1.0.0", - "json-loader": "^0.5.4", - "json5": "^0.5.1", - "loader-runner": "^2.3.0", - "loader-utils": "^1.1.0", - "memory-fs": "~0.4.1", - "mkdirp": "~0.5.0", - "node-libs-browser": "^2.0.0", - "source-map": "^0.5.3", - "supports-color": "^4.2.1", - "tapable": "^0.2.7", - "uglifyjs-webpack-plugin": "^0.4.6", - "watchpack": "^1.4.0", - "webpack-sources": "^1.0.1", - "yargs": "^8.0.2" - }, - "dependencies": { - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - } - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "lcid": "^1.0.0", - "mem": "^1.1.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.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" - }, - "dependencies": { - "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 - }, - "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" - } - } - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dev": true, - "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - } - } - }, - "uglifyjs-webpack-plugin": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", - "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", - "dev": true, - "requires": { - "source-map": "^0.5.6", - "uglify-js": "^2.8.29", - "webpack-sources": "^1.0.1" - } - }, - "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 - }, - "yargs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", - "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", - "dev": true, - "requires": { - "camelcase": "^4.1.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "read-pkg-up": "^2.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", - "yargs-parser": "^7.0.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "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" - }, - "dependencies": { - "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" - } - } - } - } - } - }, - "yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - } - } - } - } - }, - "webpack-core": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz", - "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=", - "dev": true, - "requires": { - "source-list-map": "~0.1.7", - "source-map": "~0.4.1" - }, - "dependencies": { - "source-list-map": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", - "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=", - "dev": true - }, - "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" - } - } - } - }, - "webpack-dev-middleware": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz", - "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==", - "dev": true, - "requires": { - "memory-fs": "~0.4.1", - "mime": "^1.5.0", - "path-is-absolute": "^1.0.0", - "range-parser": "^1.0.3", - "time-stamp": "^2.0.0" - } - }, - "webpack-dev-server": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.1.tgz", - "integrity": "sha512-ombhu5KsO/85sVshIDTyQ5HF3xjZR3N0sf5Ao6h3vFwpNyzInEzA1GV3QPVjTMLTNckp8PjfG1PFGznzBwS5lg==", - "dev": true, - "requires": { - "ansi-html": "0.0.7", - "array-includes": "^3.0.3", - "bonjour": "^3.5.0", - "chokidar": "^2.0.0", - "compression": "^1.5.2", - "connect-history-api-fallback": "^1.3.0", - "debug": "^3.1.0", - "del": "^3.0.0", - "express": "^4.16.2", - "html-entities": "^1.2.0", - "http-proxy-middleware": "~0.17.4", - "import-local": "^1.0.0", - "internal-ip": "1.2.0", - "ip": "^1.1.5", - "killable": "^1.0.0", - "loglevel": "^1.4.1", - "opn": "^5.1.0", - "portfinder": "^1.0.9", - "selfsigned": "^1.9.1", - "serve-index": "^1.7.2", - "sockjs": "0.3.19", - "sockjs-client": "1.1.4", - "spdy": "^3.4.1", - "strip-ansi": "^3.0.0", - "supports-color": "^5.1.0", - "webpack-dev-middleware": "1.12.2", - "yargs": "6.6.0" - }, - "dependencies": { - "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" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.0.tgz", - "integrity": "sha512-P4O8UQRdGiMLWSizsApmXVQDBS6KCt7dSexgLKBmH5Hr1CZq7vsnscFh8oR1sP1ab1Zj0uCHCEzZeV6SfUf3rA==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "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" - } - }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - }, - "chokidar": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.2.tgz", - "integrity": "sha512-l32Hw3wqB0L2kGVmSbK/a+xXLDrUEsc84pSgMkmwygHvD7ubRsP/vxxHa5BtB6oix1XLLVCHyYMsckRXxThmZw==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.0.0", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.0" - } - }, - "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" - } - }, - "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" - } - } - } - }, - "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" - } - }, - "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" - } - } - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "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" - }, - "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" - }, - "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-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" - }, - "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" - } - } - } - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "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 - }, - "micromatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.5.tgz", - "integrity": "sha512-ykttrLPQrz1PUJcXjwsTUjGoPJ64StIGNE2lGVD1c9CuguJ+L7/navsE8IcDNndOoCMvYV0qc/exfVbMHkUhvA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.0", - "define-property": "^1.0.0", - "extend-shallow": "^2.0.1", - "extglob": "^2.0.2", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.0", - "nanomatch": "^1.2.5", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "supports-color": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", - "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "yargs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", - "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", - "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": "^4.2.0" - } - }, - "yargs-parser": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", - "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", - "dev": true, - "requires": { - "camelcase": "^3.0.0" - } - } - } - }, - "webpack-merge": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.1.tgz", - "integrity": "sha512-geQsZ86YkXOVOjvPC5yv3JSNnL6/X3Kzh935AQ/gJNEYXEfJDQFu/sdFuktS9OW2JcH/SJec8TGfRdrpHshH7A==", - "dev": true, - "requires": { - "lodash": "^4.17.4" - } - }, - "webpack-sources": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", - "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", - "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 - } - } - }, - "webpack-subresource-integrity": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.0.4.tgz", - "integrity": "sha1-j6yKfo61n8ahZ2ioXJ2U7n+dDts=", - "dev": true, - "requires": { - "webpack-core": "^0.6.8" - } - }, - "websocket-driver": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", - "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", - "dev": true, - "requires": { - "http-parser-js": ">=0.4.0", - "websocket-extensions": ">=0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", - "dev": true - }, - "when": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", - "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", - "dev": true - }, - "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.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", - "dev": true, - "requires": { - "isexe": "^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 - }, - "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" - } - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true - }, - "worker-farm": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.2.tgz", - "integrity": "sha512-XxiQ9kZN5n6mmnW+mFJ+wXjNNI/Nx4DIdaAKLX1Bn6LYBWlN/zaBhu34DQYPZ1AJobQuu67S2OfDdNSVULvXkQ==", - "dev": true, - "requires": { - "errno": "^0.1.4", - "xtend": "^4.0.1" - } - }, - "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" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, - "xhr2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz", - "integrity": "sha1-f4dliEdxbbUCYyOBL4GMras4el8=" - }, - "xml-char-classes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", - "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=", - "dev": true - }, - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", - "dev": true - }, - "xmlhttprequest": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", - "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" - }, - "xmlhttprequest-ssl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", - "dev": true - }, - "xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", - "dev": true, - "optional": true - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", - "dev": true - }, - "xxhashjs": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", - "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", - "dev": true, - "requires": { - "cuint": "^0.2.2" - } - }, - "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 - }, - "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "dev": true, - "optional": 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" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true, - "optional": true - } - } - }, - "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, - "optional": true, - "requires": { - "camelcase": "^3.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, - "optional": true - } - } - }, - "yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", - "dev": true - }, - "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", - "dev": true - }, - "zone.js": { - "version": "0.8.20", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.20.tgz", - "integrity": "sha512-FXlA37ErSXCMy5RNBcGFgCI/Zivqzr0D19GuvDxhcYIJc7xkFp6c29DKyODJu0Zo+EMyur/WPPgcBh1EHjB9jA==" - } - } -} +{ + "name": "openems-ui", + "version": "2018.9.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@angular-devkit/build-optimizer": { + "version": "0.0.42", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.42.tgz", + "integrity": "sha512-BAYCVZ10ro6mgZQDZiNiVbX8ppygw4q7z/stpwG8WjMswgMRIcxsxYoC1VFuWcUPAf4UyfTIav6e8UZWA5+xnQ==", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "source-map": "0.5.7", + "typescript": "2.6.2", + "webpack-sources": "1.1.0" + }, + "dependencies": { + "typescript": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", + "dev": true + } + } + }, + "@angular-devkit/core": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.0.29.tgz", + "integrity": "sha512-jtUBA0pIrkdXcVqDmDrGlniqwM7NFOKdo7vWFDmCVLBbC9rZHeYW5Xv/+4HyBhGLJ4wxsAkUjsHKWGJINPPpiw==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "chokidar": "1.7.0", + "rxjs": "5.5.6", + "source-map": "0.5.7" + } + }, + "@angular-devkit/schematics": { + "version": "0.0.52", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.0.52.tgz", + "integrity": "sha512-NtG8VB5aWtg0cw1Y7EJinJMuAnXsNdkQkkVe/i7CO6TPLyFQSFQCN1YojCr43l8jTWTRebRslrBawPCMOxsOgw==", + "dev": true, + "requires": { + "@ngtools/json-schema": "1.1.0", + "rxjs": "5.5.6" + } + }, + "@angular/animations": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-5.2.5.tgz", + "integrity": "sha512-70ElCmaeDxLQc2OkgYhJjXj4zjtdjI4K1D5ZZm/uSPLlUcqC6uf6skCXlhMawQoPbsL/SXE5xw2HlMgEbhUysw==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/cdk": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-5.2.1.tgz", + "integrity": "sha512-8vsHeRymM+p82JeBzanrjmxp0koTU5W8cXO05ojECRsj6gUE/C950rMfFDga7fC8Pu5KTru/hWQoOcKErb3Uzg==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/cli": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-1.6.7.tgz", + "integrity": "sha512-TprSjnQrEdrTsCAB5K/lCLuXZUH/y+l/BAR0aZLpubpZP8Ldgmq7q56trxL5wNSs3o6A8Vh43ZKNYOuKtnzlXQ==", + "dev": true, + "requires": { + "@angular-devkit/build-optimizer": "0.0.42", + "@angular-devkit/core": "0.0.29", + "@angular-devkit/schematics": "0.0.52", + "@ngtools/json-schema": "1.1.0", + "@ngtools/webpack": "1.9.7", + "@schematics/angular": "0.1.17", + "autoprefixer": "7.2.6", + "chalk": "2.2.2", + "circular-dependency-plugin": "4.4.0", + "common-tags": "1.7.2", + "copy-webpack-plugin": "4.4.1", + "core-object": "3.1.5", + "css-loader": "0.28.9", + "cssnano": "3.10.0", + "denodeify": "1.2.1", + "ember-cli-string-utils": "1.1.0", + "exports-loader": "0.6.4", + "extract-text-webpack-plugin": "3.0.2", + "file-loader": "1.1.6", + "fs-extra": "4.0.3", + "glob": "7.1.2", + "html-webpack-plugin": "2.30.1", + "istanbul-instrumenter-loader": "3.0.0", + "karma-source-map-support": "1.2.0", + "less": "2.7.3", + "less-loader": "4.0.5", + "license-webpack-plugin": "1.1.1", + "loader-utils": "1.1.0", + "lodash": "4.17.5", + "memory-fs": "0.4.1", + "minimatch": "3.0.4", + "node-modules-path": "1.0.1", + "node-sass": "4.9.0", + "nopt": "4.0.1", + "opn": "5.1.0", + "portfinder": "1.0.13", + "postcss-import": "11.1.0", + "postcss-loader": "2.1.0", + "postcss-url": "7.3.0", + "raw-loader": "0.5.1", + "resolve": "1.5.0", + "rxjs": "5.5.6", + "sass-loader": "6.0.6", + "semver": "5.5.0", + "silent-error": "1.1.0", + "source-map-support": "0.4.18", + "style-loader": "0.13.2", + "stylus": "0.54.5", + "stylus-loader": "3.0.1", + "uglifyjs-webpack-plugin": "1.1.8", + "url-loader": "0.6.2", + "webpack": "3.10.0", + "webpack-dev-middleware": "1.12.2", + "webpack-dev-server": "2.11.1", + "webpack-merge": "4.1.1", + "webpack-sources": "1.1.0", + "webpack-subresource-integrity": "1.0.4" + } + }, + "@angular/common": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-5.2.5.tgz", + "integrity": "sha512-jagCxo+75pcTwjuO1ZheIiTlKBJ6REFKFWoUPTzaSS6fnzReFJ+VPf4Pb0bWtHL1lWvbvnzmITOJPB9wmuM3fg==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/compiler": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-5.2.5.tgz", + "integrity": "sha512-YU/r5omexkrrBF3bZaseWrc2Iotk6hIdUWkPIL3gPC0hKJ3wBeB3sHCBujPQXktWdMBbQRujNSMZtgra3Oh1xQ==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/compiler-cli": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-5.2.5.tgz", + "integrity": "sha512-jRFMxUKpodzOBKdZc6OMse+CjK6xfTJssZQrYeIyqz2daobaIsMZP2hZX8s/PCfV8Vxa7XFwCJb7Fq2uyZKfHg==", + "dev": true, + "requires": { + "chokidar": "1.7.0", + "minimist": "1.2.0", + "reflect-metadata": "0.1.12", + "tsickle": "0.26.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@angular/core": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-5.2.5.tgz", + "integrity": "sha512-Uo7R3LrsvA24JkRbwXWUZWp7NSEpwdTUxT1NScyjrBK+t8ybSL5/42Jo21md5M4pjeCsIgUXlGoCm1QtT5aYnQ==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/flex-layout": { + "version": "2.0.0-beta.12", + "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-2.0.0-beta.12.tgz", + "integrity": "sha512-QTOKZxehYTh8fj64V/pNVWNbfNtebSbssyMIXiGJuHTzfyF7GYdRmtjoR2pNpllycz3rE5NYX77EB140Y6BCnw==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/forms": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-5.2.5.tgz", + "integrity": "sha512-3feqqTuv9rIu7ZOsLCtM/ugNFz5RPujLHkE8bU1gsMM4/eMYruIFir2vbjnhMkD3K6KptEg4iO6tDW18diwXug==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/http": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-5.2.5.tgz", + "integrity": "sha512-VqTCkAnebe+M9Bqrfp1QYpBQCTbXide/NxrQfwiJY87kjKFeRBuy9/XH/2S5wIwlF5Yx3bmlaIufd9VI5r/0aQ==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/language-service": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-5.2.5.tgz", + "integrity": "sha512-UWNbECu8svXmrgbTL03Fr+Dn06aPCZZLScmCOGVT5lkdsiJPAJpWAvKVM2Y0nzH0PmvekHw7INtV5lwfJOijYQ==", + "dev": true + }, + "@angular/material": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-5.2.1.tgz", + "integrity": "sha512-94VmxclpIwXAxeudz9AfMg0m46/TEx/GsDZ7R9yOtrbptAr9xSgOumiEqET4Xjb35/mzgD/PKqlcMWyHJCkyVQ==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/platform-browser": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-5.2.5.tgz", + "integrity": "sha512-iPAuoG/c3pD3hnk1g0VgJu/pzNITvLQyT0W71MDMSuxLxs291kq+U2jklm40pStISd1mPbCNKmvz/7M+WbdLhg==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-5.2.5.tgz", + "integrity": "sha512-IMEe2qUTC3CA3KoswmJJs+O2Lkyd5GXgl5ULupqhhm/TOL2FLk00kwv8k3Epaf2d1wXcjK3BMG7aAwc6RLH7QA==", + "requires": { + "tslib": "1.9.0" + } + }, + "@angular/platform-server": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-5.2.5.tgz", + "integrity": "sha512-IpuEDNyoVfGO94jd1s+4IgoTBkWigwqD4YQTpcsC1mdY2Ax7NXXTAx28ZQF5EvPbSxsHGB5zG3oR7KE7GMNhYQ==", + "requires": { + "domino": "1.0.30", + "tslib": "1.9.0", + "xhr2": "0.1.4" + } + }, + "@angular/router": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-5.2.5.tgz", + "integrity": "sha512-I8U0iy59lz0dAxU4zxRQHagfUPWF+MikLNMirRL1lrA49PG+5K1tiuIQ6p+8fZFAJ5UXwNHyXqYuWqsKRiVBHQ==", + "requires": { + "tslib": "1.9.0" + } + }, + "@ngtools/json-schema": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz", + "integrity": "sha1-w6DFRNYjkqzCgTpCyKDcb1j4aSI=", + "dev": true + }, + "@ngtools/webpack": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-1.9.7.tgz", + "integrity": "sha512-D5QuaT9wENeM2j9g2qvW9Ls1tGqRz26Lp+jxwb2ZGFep7Ik1fFOX3ROLfgkxNlxZGVmbxJjsfrYUCyGlzj8gWg==", + "dev": true, + "requires": { + "chalk": "2.2.2", + "enhanced-resolve": "3.4.1", + "loader-utils": "1.1.0", + "magic-string": "0.22.4", + "semver": "5.5.0", + "source-map": "0.5.7", + "tree-kill": "1.2.0", + "webpack-sources": "1.1.0" + } + }, + "@ngx-translate/core": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-9.1.1.tgz", + "integrity": "sha1-rhA5KINrip4Gn9Li52+iGYzH5ig=" + }, + "@schematics/angular": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.1.17.tgz", + "integrity": "sha512-PHE5gk/ogPY/aN94dbbtauHMCq+/7w4Kdcl7tGmSS8mPKEI0wa6XJi//Wq/tHi55lb2fP58oEZU6n6w/wQascw==", + "dev": true, + "requires": { + "typescript": "2.6.2" + }, + "dependencies": { + "typescript": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.2.tgz", + "integrity": "sha1-PFtv1/beCRQmkCfwPAlGdY92c6Q=", + "dev": true + } + } + }, + "@types/d3": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-4.12.0.tgz", + "integrity": "sha512-F5lVj6c2G/WPbKFk4ZVxTS8F/6IRknWcheswQcycMjBh17iJ+bRfNUtn0yvtIHtRPQSanI9Dx2U8rSSA/I+ecQ==", + "requires": { + "@types/d3-array": "1.2.1", + "@types/d3-axis": "1.0.9", + "@types/d3-brush": "1.0.7", + "@types/d3-chord": "1.0.6", + "@types/d3-collection": "1.0.5", + "@types/d3-color": "1.0.5", + "@types/d3-dispatch": "1.0.5", + "@types/d3-drag": "1.2.0", + "@types/d3-dsv": "1.0.31", + "@types/d3-ease": "1.0.7", + "@types/d3-force": "1.1.0", + "@types/d3-format": "1.2.1", + "@types/d3-geo": "1.9.4", + "@types/d3-hierarchy": "1.1.0", + "@types/d3-interpolate": "1.1.6", + "@types/d3-path": "1.0.6", + "@types/d3-polygon": "1.0.5", + "@types/d3-quadtree": "1.0.5", + "@types/d3-queue": "3.0.5", + "@types/d3-random": "1.1.0", + "@types/d3-request": "1.0.2", + "@types/d3-scale": "2.0.0", + "@types/d3-selection": "1.3.0", + "@types/d3-shape": "1.2.2", + "@types/d3-time": "1.0.7", + "@types/d3-time-format": "2.1.0", + "@types/d3-timer": "1.0.6", + "@types/d3-transition": "1.1.1", + "@types/d3-voronoi": "1.1.7", + "@types/d3-zoom": "1.7.0" + } + }, + "@types/d3-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.1.tgz", + "integrity": "sha512-YBaAfimGdWE4nDuoGVKsH89/dkz2hWZ0i8qC+xxqmqi+XJ/aXiRF0jPtzXmN7VdkpVjy1xuDmM5/m1FNuB6VWA==" + }, + "@types/d3-axis": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.9.tgz", + "integrity": "sha512-fNUnI2a0F3xiE/nGrTdDpZG4sdcRIB4X59p9jgY8O7RQiKrVqyb433YCCYSqVID4CVyoq5v3bSFliUEk0FOMsw==", + "requires": { + "@types/d3-selection": "1.3.0" + } + }, + "@types/d3-brush": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-1.0.7.tgz", + "integrity": "sha1-BcMEQPTVN/0j+Xaw5sS6IjAB70U=", + "requires": { + "@types/d3-selection": "1.3.0" + } + }, + "@types/d3-chord": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.6.tgz", + "integrity": "sha1-BYnrl6MZH07a8Xt73kmEYokM4ew=" + }, + "@types/d3-collection": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-collection/-/d3-collection-1.0.5.tgz", + "integrity": "sha1-ux86qXzcjYgWRVQbnWz4ft/um8M=" + }, + "@types/d3-color": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.0.5.tgz", + "integrity": "sha1-ytdV8Pxt57cPpuXgivqB70wiSN4=" + }, + "@types/d3-dispatch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-1.0.5.tgz", + "integrity": "sha1-8fkYe1OOywUVdWnY3C9w37BPG1I=" + }, + "@types/d3-drag": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.0.tgz", + "integrity": "sha512-AePmm0sXj0Tpl0uQWvwmbAf1QR3yCy9aRhjJ9mRDDSZlHBdY0SCpUtdZC9uG9Q+pyHT/dEt1R2FT/sj+5k/bVA==", + "requires": { + "@types/d3-selection": "1.3.0" + } + }, + "@types/d3-dsv": { + "version": "1.0.31", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.0.31.tgz", + "integrity": "sha512-UCAVZdwd2NkrbkF1lZu9vzTlmUENRRrPCubyhDPlG8Ye1B8Xr2PNvk/Tp8tMm6sPoWZWagri6/P9H+t7WqkGDg==" + }, + "@types/d3-ease": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-1.0.7.tgz", + "integrity": "sha1-k6MBhovp4VBh89RDQ7GrP4rLbwk=" + }, + "@types/d3-force": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.1.0.tgz", + "integrity": "sha512-a39Uu/ltLaMpj6K0elEB1oAqhx9rlTB5X/O75uTUqyTW2CfjhPXg6hFsX1lF8oeMc29kqGJZ4g9Pf6mET25bVw==" + }, + "@types/d3-format": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.2.1.tgz", + "integrity": "sha512-dXhA9jzCbzu6Va8ZVUQ60nu6jqA5vhPhKGR4nY3lDYfjT05GyKEKuEhfwTaSTybWczY4nLEkzv9wLQCQd5+3cA==" + }, + "@types/d3-geo": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-1.9.4.tgz", + "integrity": "sha512-DoigJorMGGIG9K4n980zz5g1XnvhDhNy7rk/0O8KCpFPpUZ9hyAgN0ZHXhbtIelxhJhMZxwMRe2soxx/Fhx4Hg==", + "requires": { + "@types/geojson": "7946.0.1" + } + }, + "@types/d3-hierarchy": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.0.tgz", + "integrity": "sha1-UPHuBShAY4A1y91KyrH8NHCQWQc=" + }, + "@types/d3-interpolate": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.1.6.tgz", + "integrity": "sha1-ZAQbFcnAMsNI2hsiuqvFn6TRYTY=", + "requires": { + "@types/d3-color": "1.0.5" + } + }, + "@types/d3-path": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.6.tgz", + "integrity": "sha512-YHW4cs+wOU9gFUzudjJs9TkrB/8GOgKhq32ZyNaZ2rzZjOhkqG486sGr9XSh4C91CcgIg1FRGoDaN29Ropx9nw==" + }, + "@types/d3-polygon": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-1.0.5.tgz", + "integrity": "sha1-Na1U7YTDnX6fElK2U1vmAL5srOI=" + }, + "@types/d3-quadtree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-1.0.5.tgz", + "integrity": "sha1-HOHmWerkUw3wyxJ/KX8XQaNnqC4=" + }, + "@types/d3-queue": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/d3-queue/-/d3-queue-3.0.5.tgz", + "integrity": "sha1-Pky+Kv9h22oLK4xIACmeTsasyFA=" + }, + "@types/d3-random": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-1.1.0.tgz", + "integrity": "sha1-LdCPEVnHBxknDkp8g0r4XIuI0sM=" + }, + "@types/d3-request": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-request/-/d3-request-1.0.2.tgz", + "integrity": "sha1-2524FU9HgWWEcGxub3Ar5m8i9L4=", + "requires": { + "@types/d3-dsv": "1.0.31" + } + }, + "@types/d3-scale": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-2.0.0.tgz", + "integrity": "sha512-fFLSdP3p9qQQ3W6ouO3GBI4Qg94CSykTWVc61U8SI1V62dfBWtOigBj5voxDcOniwh9MjKzTHldMSsGJ5qAFpA==", + "requires": { + "@types/d3-time": "1.0.7" + } + }, + "@types/d3-selection": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.3.0.tgz", + "integrity": "sha512-1SJhi3kTk/SHHIE6XkHuHU2REYkbSOjkQuo3HT71FOTs8/tjeGcvtXMsX4N3kU1UE1nVG+A5pg7TSjuJ4zUN3A==" + }, + "@types/d3-shape": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.2.2.tgz", + "integrity": "sha512-Ydksrces8J5WP/NXhZ/CcDx/XZZ8b7MDX+u6WGQXwEWfmimJn9eYHiD7QR4BLe3zBiAOQmmiGAwRBKUDp5zb1g==", + "requires": { + "@types/d3-path": "1.0.6" + } + }, + "@types/d3-time": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.0.7.tgz", + "integrity": "sha512-X5ZQYiJIM38XygNwld4gZ++Vtw2ftgo3KOfZOY4n/sCudUxclxf/3THBvuG8UqSV+EQ0ezYjT5eyvcrrmixOWA==" + }, + "@types/d3-time-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", + "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==" + }, + "@types/d3-timer": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.6.tgz", + "integrity": "sha1-eG1OIHMa3wOvLF32yG/ilmf+Qps=" + }, + "@types/d3-transition": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.1.1.tgz", + "integrity": "sha512-GHTghl0YYB8gGgbyKxVLHyAp9Na0HqsX2U7M0u0lGw4IdfEaslooykweZ8fDHW13T+KZeZAuzhbmqBZVFO+6kg==", + "requires": { + "@types/d3-selection": "1.3.0" + } + }, + "@types/d3-voronoi": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.7.tgz", + "integrity": "sha512-/dHFLK5jhXTb/W4XEQcFydVk8qlIAo85G3r7+N2fkBFw190l0R1GQ8C1VPeXBb2GfSU5GbT2hjlnE7i7UY5Gvg==" + }, + "@types/d3-zoom": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.7.0.tgz", + "integrity": "sha512-eIivt2ehMUXqS0guuVzRSMr5RGhO958g9EKxIJv3Z23suPnX4VQI9k1TC/bLuwKq0IWp9a1bEEcIy+PNJv9BtA==", + "requires": { + "@types/d3-interpolate": "1.1.6", + "@types/d3-selection": "1.3.0" + } + }, + "@types/geojson": { + "version": "7946.0.1", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.1.tgz", + "integrity": "sha512-BXY6tH16Snp/ZdX6cFlBD8yfEArcZemzxEGciXkMmp1/tU76oyqkxJq91JQzT8SXWzRPwj//dw0/FdCSnnT8mw==" + }, + "@types/jasmine": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.6.tgz", + "integrity": "sha512-clg9raJTY0EOo5pVZKX3ZlMjlYzVU73L71q5OV1jhE2Uezb7oF94jh4CvwrW6wInquQAdhOxJz5VDF2TLUGmmA==", + "dev": true + }, + "@types/jasminewd2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.3.tgz", + "integrity": "sha512-hYDVmQZT5VA2kigd4H4bv7vl/OhlympwREUemqBdOqtrYTo5Ytm12a5W5/nGgGYdanGVxj0x/VhZ7J3hOg/YKg==", + "dev": true, + "requires": { + "@types/jasmine": "2.8.6" + } + }, + "@types/node": { + "version": "6.0.101", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.101.tgz", + "integrity": "sha512-IQ7V3D6+kK1DArTqTBrnl3M+YgJZLw8ta8w3Q9xjR79HaJzMAoTbZ8TNzUTztrkCKPTqIstE2exdbs1FzsYLUw==", + "dev": true + }, + "@types/q": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=", + "dev": true + }, + "@types/selenium-webdriver": { + "version": "2.53.43", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.43.tgz", + "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", + "dev": true + }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "dev": true + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, + "JSONStream": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz", + "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=", + "dev": true, + "requires": { + "jsonparse": "1.3.1", + "through": "2.3.8" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "dev": true, + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "acorn": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz", + "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", + "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", + "dev": true, + "requires": { + "acorn": "4.0.13" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "acorn-node": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.3.0.tgz", + "integrity": "sha512-efP54n3d1aLfjL2UMdaXa6DsswwzJeI5rqhbFvXMrKiJ6eJFpf+7R0zN7t8IC+XKn2YOAFAv6xbBNgHUkoHWLw==", + "dev": true, + "requires": { + "acorn": "5.4.1", + "xtend": "4.0.1" + } + }, + "addressparser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", + "integrity": "sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=", + "dev": true, + "optional": true + }, + "adm-zip": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", + "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", + "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, + "requires": { + "extend": "3.0.1", + "semver": "5.0.3" + }, + "dependencies": { + "semver": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.1.0.tgz", + "integrity": "sha1-rCsnk5xUPpXSwG5/f1wnvkqlQ74=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "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 + }, + "amqplib": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.2.tgz", + "integrity": "sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA==", + "dev": true, + "optional": true, + "requires": { + "bitsyntax": "0.0.4", + "bluebird": "3.5.1", + "buffer-more-ints": "0.0.2", + "readable-stream": "1.1.14", + "safe-buffer": "5.1.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true, + "optional": true + } + } + }, + "angular2-toaster": { + "version": "5.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/angular2-toaster/-/angular2-toaster-5.0.0-alpha.1.tgz", + "integrity": "sha512-4fG+JBLExcpVG7V/pt5Lhi3C7nDxnqKTKIJarwe41MP9hKP94hLExlWHsEN6nhG+nLIecp+LBamP3LFOjZCFMQ==" + }, + "angular2-uuid": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/angular2-uuid/-/angular2-uuid-1.1.1.tgz", + "integrity": "sha1-cvA81TK39AAy6x7PufhFc4S+lW4=" + }, + "ansi-html": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", + "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=", + "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.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + }, + "dependencies": { + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + } + } + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "app-root-path": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.0.1.tgz", + "integrity": "sha1-zWLc+OT9WkF+/GZNLlsQZTxlG0Y=", + "dev": true + }, + "append-transform": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", + "dev": true, + "requires": { + "default-require-extensions": "1.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "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.3.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "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-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "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-flatten": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", + "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=", + "dev": true + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.10.0" + } + }, + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "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=", + "dev": true, + "optional": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "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.11.8", + "inherits": "2.0.3", + "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" + } + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "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.10.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.2.tgz", + "integrity": "sha512-ufWX953VU1eIuWqxS0nRDMYlGyFH+yxln5CsmIHlpzEt3fdYqUnRtsFt0XAsQot8OaVCwFqxT1RiwvtzYjeYeg==", + "dev": true, + "optional": true + }, + "astw": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", + "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=", + "dev": true, + "requires": { + "acorn": "4.0.13" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + } + } + }, + "async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", + "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "dev": true, + "requires": { + "lodash": "4.17.5" + } + }, + "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, + "optional": 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.0.3", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz", + "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=", + "dev": true + }, + "autoprefixer": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.2.6.tgz", + "integrity": "sha512-Iq8TRIB+/9eQ8rbGhcP7ct5cYb/3qjNYAR2SnzLCEcwF6rvVOax8+9+fccgXk4bEhQGjOZd5TLhsksmAdsbGqQ==", + "dev": true, + "requires": { + "browserslist": "2.11.3", + "caniuse-lite": "1.0.30000808", + "normalize-range": "0.1.2", + "num2fraction": "1.2.2", + "postcss": "6.0.18", + "postcss-value-parser": "3.3.0" + } + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "axios": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", + "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", + "dev": true, + "optional": true, + "requires": { + "follow-redirects": "1.0.0" + } + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "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-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.5", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + } + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.3", + "regenerator-runtime": "0.11.1" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.5" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.5" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.5", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "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.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64-js": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz", + "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w==", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "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 + }, + "binary-extensions": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "dev": true + }, + "bitsyntax": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.0.4.tgz", + "integrity": "sha1-6xDMb4K4xJDj6FaY8H6D1G4MuoI=", + "dev": true, + "optional": true, + "requires": { + "buffer-more-ints": "0.0.2" + } + }, + "bl": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", + "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", + "dev": true, + "optional": true, + "requires": { + "readable-stream": "2.0.6" + }, + "dependencies": { + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true, + "optional": true + } + } + }, + "blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", + "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, + "optional": true, + "requires": { + "inherits": "2.0.3" + } + }, + "blocking-proxy": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.5.tgz", + "integrity": "sha1-RikF4Nz76pcPQao3Ij3anAexkSs=", + "dev": true, + "requires": { + "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 + } + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "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 + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.2", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.15" + }, + "dependencies": { + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "2.1.1", + "deep-equal": "1.0.1", + "dns-equal": "1.0.0", + "dns-txt": "2.0.2", + "multicast-dns": "6.2.3", + "multicast-dns-service-types": "1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browser-pack": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.4.tgz", + "integrity": "sha512-Q4Rvn7P6ObyWfc4stqLWHtG1MJ8vVtjgT24Zbu+8UTzxYuZouqZsmNRRTFVMY/Ux0eIKv1d+JWzsInTX+fdHPQ==", + "dev": true, + "requires": { + "JSONStream": "1.3.2", + "combine-source-map": "0.8.0", + "defined": "1.0.0", + "safe-buffer": "5.1.1", + "through2": "2.0.3", + "umd": "3.0.1" + } + }, + "browser-resolve": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", + "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", + "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": { + "version": "14.5.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.5.0.tgz", + "integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==", + "dev": true, + "requires": { + "JSONStream": "1.3.2", + "assert": "1.4.1", + "browser-pack": "6.0.4", + "browser-resolve": "1.11.2", + "browserify-zlib": "0.2.0", + "buffer": "5.1.0", + "cached-path-relative": "1.0.1", + "concat-stream": "1.5.2", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.12.0", + "defined": "1.0.0", + "deps-sort": "2.0.0", + "domain-browser": "1.1.7", + "duplexer2": "0.1.4", + "events": "1.1.1", + "glob": "7.1.2", + "has": "1.0.1", + "htmlescape": "1.1.1", + "https-browserify": "1.0.0", + "inherits": "2.0.3", + "insert-module-globals": "7.0.1", + "labeled-stream-splicer": "2.0.0", + "module-deps": "4.1.1", + "os-browserify": "0.3.0", + "parents": "1.0.1", + "path-browserify": "0.0.0", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "read-only-stream": "2.0.0", + "readable-stream": "2.3.4", + "resolve": "1.5.0", + "shasum": "1.0.2", + "shell-quote": "1.6.1", + "stream-browserify": "2.0.1", + "stream-http": "2.8.0", + "string_decoder": "1.0.3", + "subarg": "1.0.0", + "syntax-error": "1.4.0", + "through2": "2.0.3", + "timers-browserify": "1.4.2", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.10.3", + "vm-browserify": "0.0.4", + "xtend": "4.0.1" + }, + "dependencies": { + "buffer": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz", + "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==", + "dev": true, + "requires": { + "base64-js": "1.2.3", + "ieee754": "1.1.8" + } + }, + "concat-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", + "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.0.6", + "typedarray": "0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "dev": true, + "requires": { + "process": "0.11.10" + } + } + } + }, + "browserify-aes": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz", + "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==", + "dev": true, + "requires": { + "buffer-xor": "1.0.3", + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "browserify-cipher": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", + "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", + "dev": true, + "requires": { + "browserify-aes": "1.1.1", + "browserify-des": "1.0.0", + "evp_bytestokey": "1.0.3" + } + }, + "browserify-des": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", + "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "des.js": "1.0.0", + "inherits": "2.0.3" + } + }, + "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.11.8", + "randombytes": "2.0.6" + } + }, + "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.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "elliptic": "6.4.0", + "inherits": "2.0.3", + "parse-asn1": "5.1.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.6" + } + }, + "browserslist": { + "version": "2.11.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.11.3.tgz", + "integrity": "sha512-yWu5cXT7Av6mVwzWc8lMsJMHWn4xyjSuGYi4IozbVTLUOEYPSagUB8kiMDUHA1fS3zjr8nkxkn9jdvug4BBRmA==", + "dev": true, + "requires": { + "caniuse-lite": "1.0.30000808", + "electron-to-chromium": "1.3.33" + } + }, + "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.2.3", + "ieee754": "1.1.8", + "isarray": "1.0.0" + } + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-more-ints": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz", + "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=", + "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 + }, + "buildmail": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-4.0.1.tgz", + "integrity": "sha1-h393OLeHKYccmhBeO4N9K+EaenI=", + "dev": true, + "optional": true, + "requires": { + "addressparser": "1.0.1", + "libbase64": "0.1.0", + "libmime": "3.0.0", + "libqp": "1.1.0", + "nodemailer-fetch": "1.6.0", + "nodemailer-shared": "1.1.0", + "punycode": "1.4.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "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 + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.2.tgz", + "integrity": "sha512-dljb7dk1jqO5ogE+dRpoR9tpHYv5xz9vPSNunh1+0wRuNdYxmzp9WmsyokgW/DUF1FDRVA/TMsmxt027R8djbQ==", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "chownr": "1.0.1", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "lru-cache": "4.1.1", + "mississippi": "1.3.1", + "mkdirp": "0.5.1", + "move-concurrently": "1.0.1", + "promise-inflight": "1.0.1", + "rimraf": "2.6.2", + "ssri": "5.2.2", + "unique-filename": "1.1.0", + "y18n": "3.2.1" + } + }, + "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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "cached-path-relative": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", + "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=", + "dev": true + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "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.3.2", + "upper-case": "1.1.3" + } + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "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.1.1", + "map-obj": "1.0.1" + } + }, + "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.7.7", + "caniuse-db": "1.0.30000808", + "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.30000808", + "electron-to-chromium": "1.3.33" + } + } + } + }, + "caniuse-db": { + "version": "1.0.30000808", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000808.tgz", + "integrity": "sha1-MN/YMAnVcE8C3/s3clBo7RKjZrs=", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30000808", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000808.tgz", + "integrity": "sha512-vT0JLmHdvq1UVbYXioxCXHYdNw55tyvi+IUWyX0Zeh1OFQi2IllYtm38IJnSgHWCv/zUnX1hdhy3vMJvuTNSqw==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + }, + "dependencies": { + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true + } + } + }, + "chalk": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.2.tgz", + "integrity": "sha512-LvixLAQ4MYhbf7hgL4o5PeK32gJKvVzDRiSNIApDofQvyhl8adgG2lJVXn4+ekQoK7HL9RF8lqxwerpe0x2pCw==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "chart.js": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.1.tgz", + "integrity": "sha512-pX1oQAY86MiuyZ2hY593Acbl4MLHKrBBhhmZ1YqSadzQbbsBE2rnd6WISoHjIsdf0WDeC0hbePYCz2ZxkV8L+g==", + "requires": { + "chartjs-color": "2.2.0", + "moment": "2.18.1" + } + }, + "chartjs-color": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz", + "integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=", + "requires": { + "chartjs-color-string": "0.5.0", + "color-convert": "0.5.3" + } + }, + "chartjs-color-string": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz", + "integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==", + "requires": { + "color-name": "1.1.3" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "fsevents": "1.2.4", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "chownr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", + "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.3", + "safe-buffer": "5.1.1" + } + }, + "circular-dependency-plugin": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-4.4.0.tgz", + "integrity": "sha512-yEFtUNUYT4jBykEX5ZOHw+5goA3glGZr9wAXIQqoyakjz5H5TeUmScnWRc52douAhb9eYzK3s7V6bXfNnjFdzg==", + "dev": true + }, + "circular-json": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.1.tgz", + "integrity": "sha512-UjgcRlTAhAkLeXmDe2wK7ktwy/tgAqxiSndTIPiFZuIPLZmzHzWMwUIe9h9m/OokypG7snxCDEuwJshGBdPvaw==", + "dev": true + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "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.1", + "static-extend": "0.1.2" + }, + "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.6" + } + }, + "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.2.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.6" + } + } + } + }, + "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.2.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.6" + } + } + } + }, + "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.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + } + } + }, + "classlist.js": { + "version": "1.1.20150312", + "resolved": "https://registry.npmjs.org/classlist.js/-/classlist.js-1.1.20150312.tgz", + "integrity": "sha1-HXCEL3Ai8I2awIbOaeWyUPLFd4k=" + }, + "clean-css": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz", + "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "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.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "clone": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", + "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=", + "dev": true + }, + "clone-deep": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz", + "integrity": "sha1-NIxhrpzb4O3+BT2R/0zFIdeQ7eg=", + "dev": true, + "requires": { + "for-own": "1.0.0", + "is-plain-object": "2.0.4", + "kind-of": "3.2.2", + "shallow-clone": "0.1.2" + }, + "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.2" + } + } + } + }, + "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.5.1" + } + }, + "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 + }, + "codelyzer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-4.1.0.tgz", + "integrity": "sha512-a3FCIAS3FNQIACvj7KA4iKvH3c6r7X6t6zXsrtV797QGYPQyCwD1fIEd9yV+ZDamijF3YaZ5fbB7QbUMOJGC/g==", + "dev": true, + "requires": { + "app-root-path": "2.0.1", + "css-selector-tokenizer": "0.7.0", + "cssauron": "1.4.0", + "semver-dsl": "1.0.1", + "source-map": "0.5.7", + "sprintf-js": "1.0.3" + } + }, + "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.1" + } + }, + "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.3", + "color-convert": "1.9.1", + "color-string": "0.3.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + } + } + }, + "color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "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.1.3" + } + }, + "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.4", + "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 + }, + "combine-lists": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", + "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", + "dev": true, + "requires": { + "lodash": "4.17.5" + } + }, + "combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "dev": true, + "requires": { + "convert-source-map": "1.1.3", + "inline-source-map": "0.6.2", + "lodash.memoize": "3.0.4", + "source-map": "0.5.7" + }, + "dependencies": { + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", + "dev": true + }, + "lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", + "dev": true + } + } + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==" + }, + "common-tags": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.7.2.tgz", + "integrity": "sha512-joj9ZlUOjCrwdbmiLqafeUSgkUM74NqhLsZtSqDmhKudaIY197zTrb8JMl31fMnCUuxwFT23eC/oWvrZzDLRJQ==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "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 + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compressible": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.12.tgz", + "integrity": "sha1-xZpcmdt2dn6YdlAOJx72OzSTvWY=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "compression": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.1.tgz", + "integrity": "sha1-7/JgPvwuIs+G810uuTWJ+YdTc9s=", + "dev": true, + "requires": { + "accepts": "1.3.4", + "bytes": "3.0.0", + "compressible": "2.0.12", + "debug": "2.6.9", + "on-headers": "1.0.1", + "safe-buffer": "5.1.1", + "vary": "1.1.2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.4", + "typedarray": "0.0.6" + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "1.3.2", + "utils-merge": "1.0.1" + } + }, + "connect-history-api-fallback": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz", + "integrity": "sha1-sGhzk0vF40T+9hGhlqb6rgruAVo=", + "dev": true + }, + "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.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "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.5.1", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "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.2.0", + "fs-write-stream-atomic": "1.0.10", + "iferr": "0.1.5", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "run-queue": "1.0.3" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-webpack-plugin": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.4.1.tgz", + "integrity": "sha512-ojaz8MpS3zoLJT/JbYMusYM+dCEArhW24hGAUPYPydTCS+87NFh2TWr85sywG3So4Q4E68QoerqQ+Ns1g0fhDg==", + "dev": true, + "requires": { + "cacache": "10.0.2", + "find-cache-dir": "1.0.0", + "globby": "7.1.1", + "is-glob": "4.0.0", + "loader-utils": "0.2.17", + "minimatch": "3.0.4", + "p-limit": "1.2.0", + "serialize-javascript": "1.4.0" + }, + "dependencies": { + "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" + } + }, + "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.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, + "core-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" + }, + "core-object": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz", + "integrity": "sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg==", + "dev": true, + "requires": { + "chalk": "2.2.2" + } + }, + "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": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "0.3.1", + "js-yaml": "3.7.0", + "minimist": "1.2.0", + "object-assign": "4.1.1", + "os-homedir": "1.0.2", + "parse-json": "2.2.0", + "require-from-string": "1.2.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "create-ecdh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "elliptic": "6.4.0" + } + }, + "create-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", + "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "sha.js": "2.4.10" + } + }, + "create-hmac": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", + "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "dev": true, + "requires": { + "cipher-base": "1.0.4", + "create-hash": "1.1.3", + "inherits": "2.0.3", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.10" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "optional": true, + "requires": { + "lru-cache": "4.1.1", + "which": "1.3.0" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "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.4", + "create-ecdh": "4.0.0", + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "diffie-hellman": "5.0.2", + "inherits": "2.0.3", + "pbkdf2": "3.0.14", + "public-encrypt": "4.0.0", + "randombytes": "2.0.6", + "randomfill": "1.0.3" + } + }, + "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.9", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.9.tgz", + "integrity": "sha512-r3dgelMm/mkPz5Y7m9SeiGE46i2VsEU/OYbez+1llfxtv8b2y5/b5StaeEvPK3S5tlNQI+tDW/xDIhKJoZgDtw==", + "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.1.0", + "lodash.camelcase": "4.3.0", + "object-assign": "4.1.1", + "postcss": "5.2.18", + "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" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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" + } + } + } + }, + "css-parse": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", + "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=", + "dev": true + }, + "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.0", + "domutils": "1.5.1", + "nth-check": "1.0.1" + } + }, + "css-selector-tokenizer": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", + "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", + "dev": true, + "requires": { + "cssesc": "0.1.0", + "fastparse": "1.1.1", + "regexpu-core": "1.0.0" + } + }, + "css-what": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "2.3.8" + } + }, + "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.7.7", + "decamelize": "1.2.0", + "defined": "1.0.0", + "has": "1.0.1", + "object-assign": "4.1.1", + "postcss": "5.2.18", + "postcss-calc": "5.3.1", + "postcss-colormin": "2.2.2", + "postcss-convert-values": "2.6.1", + "postcss-discard-comments": "2.0.4", + "postcss-discard-duplicates": "2.1.0", + "postcss-discard-empty": "2.1.0", + "postcss-discard-overridden": "0.1.1", + "postcss-discard-unused": "2.2.3", + "postcss-filter-plugins": "2.0.2", + "postcss-merge-idents": "2.1.7", + "postcss-merge-longhand": "2.0.2", + "postcss-merge-rules": "2.1.2", + "postcss-minify-font-values": "1.0.5", + "postcss-minify-gradients": "1.0.5", + "postcss-minify-params": "1.2.2", + "postcss-minify-selectors": "2.1.1", + "postcss-normalize-charset": "1.1.1", + "postcss-normalize-url": "3.0.8", + "postcss-ordered-values": "2.2.3", + "postcss-reduce-idents": "2.4.0", + "postcss-reduce-initial": "1.0.1", + "postcss-reduce-transforms": "1.0.4", + "postcss-svgo": "2.1.6", + "postcss-unique-selectors": "2.0.2", + "postcss-value-parser": "3.3.0", + "postcss-zindex": "2.2.0" + }, + "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 + }, + "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.7", + "caniuse-db": "1.0.30000808", + "normalize-range": "0.1.2", + "num2fraction": "1.2.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "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.30000808", + "electron-to-chromium": "1.3.33" + } + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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" + } + } + } + }, + "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.2.3", + "source-map": "0.5.7" + } + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", + "dev": true + }, + "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.2" + } + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "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.37" + } + }, + "d3": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-4.13.0.tgz", + "integrity": "sha512-l8c4+0SldjVKLaE2WG++EQlqD7mh/dmQjvi2L2lKPadAVC+TbJC4ci7Uk9bRi+To0+ansgsS0iWfPjD7DBy+FQ==", + "requires": { + "d3-array": "1.2.1", + "d3-axis": "1.0.8", + "d3-brush": "1.0.4", + "d3-chord": "1.0.4", + "d3-collection": "1.0.4", + "d3-color": "1.0.3", + "d3-dispatch": "1.0.3", + "d3-drag": "1.2.1", + "d3-dsv": "1.0.8", + "d3-ease": "1.0.3", + "d3-force": "1.1.0", + "d3-format": "1.2.2", + "d3-geo": "1.9.1", + "d3-hierarchy": "1.1.5", + "d3-interpolate": "1.1.6", + "d3-path": "1.0.5", + "d3-polygon": "1.0.3", + "d3-quadtree": "1.0.3", + "d3-queue": "3.0.7", + "d3-random": "1.1.0", + "d3-request": "1.0.6", + "d3-scale": "1.0.7", + "d3-selection": "1.3.0", + "d3-shape": "1.2.0", + "d3-time": "1.0.8", + "d3-time-format": "2.1.1", + "d3-timer": "1.0.7", + "d3-transition": "1.1.1", + "d3-voronoi": "1.1.2", + "d3-zoom": "1.7.1" + }, + "dependencies": { + "d3-scale": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz", + "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", + "requires": { + "d3-array": "1.2.1", + "d3-collection": "1.0.4", + "d3-color": "1.0.3", + "d3-format": "1.2.2", + "d3-interpolate": "1.1.6", + "d3-time": "1.0.8", + "d3-time-format": "2.1.1" + } + } + } + }, + "d3-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz", + "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==" + }, + "d3-axis": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.8.tgz", + "integrity": "sha1-MacFoLU15ldZ3hQXOjGTMTfxjvo=" + }, + "d3-brush": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", + "integrity": "sha1-AMLyOAGfJPbAoZSibUGhUw/+e8Q=", + "requires": { + "d3-dispatch": "1.0.3", + "d3-drag": "1.2.1", + "d3-interpolate": "1.1.6", + "d3-selection": "1.3.0", + "d3-transition": "1.1.1" + } + }, + "d3-chord": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.4.tgz", + "integrity": "sha1-fexPC6iG9xP+ERxF92NBT290yiw=", + "requires": { + "d3-array": "1.2.1", + "d3-path": "1.0.5" + } + }, + "d3-collection": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", + "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=" + }, + "d3-color": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.0.3.tgz", + "integrity": "sha1-vHZD/KjlOoNH4vva/6I2eWtYUJs=" + }, + "d3-dispatch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", + "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=" + }, + "d3-drag": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.1.tgz", + "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", + "requires": { + "d3-dispatch": "1.0.3", + "d3-selection": "1.3.0" + } + }, + "d3-dsv": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.0.8.tgz", + "integrity": "sha512-IVCJpQ+YGe3qu6odkPQI0KPqfxkhbP/oM1XhhE/DFiYmcXKfCRub4KXyiuehV1d4drjWVXHUWx4gHqhdZb6n/A==", + "requires": { + "commander": "2.14.1", + "iconv-lite": "0.4.19", + "rw": "1.3.3" + } + }, + "d3-ease": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", + "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=" + }, + "d3-force": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", + "integrity": "sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==", + "requires": { + "d3-collection": "1.0.4", + "d3-dispatch": "1.0.3", + "d3-quadtree": "1.0.3", + "d3-timer": "1.0.7" + } + }, + "d3-format": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", + "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==" + }, + "d3-geo": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.9.1.tgz", + "integrity": "sha512-l9wL/cEQkyZQYXw3xbmLsH3eQ5ij+icNfo4r0GrLa5rOCZR/e/3am45IQ0FvQ5uMsv+77zBRunLc9ufTWSQYFA==", + "requires": { + "d3-array": "1.2.1" + } + }, + "d3-hierarchy": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.5.tgz", + "integrity": "sha1-ochFxC+Eoga88cAcAQmOpN2qeiY=" + }, + "d3-interpolate": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", + "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", + "requires": { + "d3-color": "1.0.3" + } + }, + "d3-path": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", + "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=" + }, + "d3-polygon": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.3.tgz", + "integrity": "sha1-FoiOkCZGCTPysXllKtN4Ik04LGI=" + }, + "d3-quadtree": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", + "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=" + }, + "d3-queue": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", + "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg=" + }, + "d3-random": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.0.tgz", + "integrity": "sha1-ZkLlBsb6OmSFldKyRpeIqNElKdM=" + }, + "d3-request": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/d3-request/-/d3-request-1.0.6.tgz", + "integrity": "sha512-FJj8ySY6GYuAJHZMaCQ83xEYE4KbkPkmxZ3Hu6zA1xxG2GD+z6P+Lyp+zjdsHf0xEbp2xcluDI50rCS855EQ6w==", + "requires": { + "d3-collection": "1.0.4", + "d3-dispatch": "1.0.3", + "d3-dsv": "1.0.8", + "xmlhttprequest": "1.8.0" + } + }, + "d3-scale": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.0.0.tgz", + "integrity": "sha512-Sa2Ny6CoJT7x6dozxPnvUQT61epGWsgppFvnNl8eJEzfJBG0iDBBTJAtz2JKem7Mb+NevnaZiDiIDHsuWkv6vg==", + "requires": { + "d3-array": "1.2.1", + "d3-collection": "1.0.4", + "d3-format": "1.2.2", + "d3-interpolate": "1.1.6", + "d3-time": "1.0.8", + "d3-time-format": "2.1.1" + } + }, + "d3-selection": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", + "integrity": "sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==" + }, + "d3-shape": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", + "integrity": "sha1-RdAVOPBkuv0F6j1tLLdI/YxB93c=", + "requires": { + "d3-path": "1.0.5" + } + }, + "d3-time": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", + "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==" + }, + "d3-time-format": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", + "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", + "requires": { + "d3-time": "1.0.8" + } + }, + "d3-timer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.7.tgz", + "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==" + }, + "d3-transition": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.1.1.tgz", + "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", + "requires": { + "d3-color": "1.0.3", + "d3-dispatch": "1.0.3", + "d3-ease": "1.0.3", + "d3-interpolate": "1.1.6", + "d3-selection": "1.3.0", + "d3-timer": "1.0.7" + } + }, + "d3-voronoi": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.2.tgz", + "integrity": "sha1-Fodmfo8TotFYyAwUgMWinLDYlzw=" + }, + "d3-zoom": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.1.tgz", + "integrity": "sha512-sZHQ55DGq5BZBFGnRshUT8tm2sfhPHFnOlmPbbwTkAoPeVdRTkB4Xsf9GCY0TSHrTD8PeJPZGmP/TpGicwJDJQ==", + "requires": { + "d3-dispatch": "1.0.3", + "d3-drag": "1.2.1", + "d3-interpolate": "1.1.6", + "d3-selection": "1.3.0", + "d3-transition": "1.1.1" + } + }, + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "data-uri-to-buffer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", + "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", + "dev": true, + "optional": true + }, + "date-fns": { + "version": "2.0.0-alpha.7", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.0.0-alpha.7.tgz", + "integrity": "sha1-JFrRb5V2Tqur+ywKQf1dAzwg5Xo=" + }, + "date-format": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", + "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=", + "dev": true + }, + "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 + }, + "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" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "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-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, + "optional": true + }, + "default-require-extensions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", + "dev": true, + "requires": { + "strip-bom": "2.0.0" + } + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "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.2" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "dev": true, + "optional": true, + "requires": { + "ast-types": "0.10.2", + "escodegen": "1.9.0", + "esprima": "3.1.3" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true, + "optional": true + } + } + }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "6.1.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "p-map": "1.2.0", + "pify": "3.0.0", + "rimraf": "2.6.2" + }, + "dependencies": { + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "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 + }, + "denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "deps-sort": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", + "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=", + "dev": true, + "requires": { + "JSONStream": "1.3.2", + "shasum": "1.0.2", + "subarg": "1.0.0", + "through2": "2.0.3" + } + }, + "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.3", + "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-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "detect-node": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", + "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=", + "dev": true + }, + "detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "dev": true, + "requires": { + "acorn": "5.4.1", + "defined": "1.0.0" + } + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "diff": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", + "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", + "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "miller-rabin": "4.0.1", + "randombytes": "2.0.6" + } + }, + "dir-glob": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", + "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", + "dev": true, + "requires": { + "arrify": "1.0.1", + "path-type": "3.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", + "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "dev": true, + "requires": { + "ip": "1.1.5", + "safe-buffer": "5.1.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "1.1.1" + } + }, + "dom-converter": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", + "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", + "dev": true, + "requires": { + "utila": "0.3.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "requires": { + "custom-event": "1.0.1", + "ent": "2.2.0", + "extend": "3.0.1", + "void-elements": "2.0.1" + } + }, + "dom-serializer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", + "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", + "dev": true, + "requires": { + "domelementtype": "1.1.3", + "entities": "1.1.1" + }, + "dependencies": { + "domelementtype": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", + "dev": true + } + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", + "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", + "dev": true + }, + "domhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", + "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "domino": { + "version": "1.0.30", + "resolved": "https://registry.npmjs.org/domino/-/domino-1.0.30.tgz", + "integrity": "sha512-ikq8WiDSkICdkElud317F2Sigc6A3EDpWsxWBwIZqOl95km4p/Vc9Rj98id7qKgsjDmExj0AVM7JOd4bb647Xg==" + }, + "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.1.0", + "domelementtype": "1.3.0" + } + }, + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", + "dev": true, + "optional": true + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, + "requires": { + "readable-stream": "2.3.4" + } + }, + "duplexify": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.3.tgz", + "integrity": "sha512-g8ID9OroF9hKt2POf8YLayy+9594PzmM3scI00/uBXocX3TWNgoB67hjzkFe9ITAbQOne/lLdBxHXvYUM4ZgGA==", + "dev": true, + "requires": { + "end-of-stream": "1.4.1", + "inherits": "2.0.3", + "readable-stream": "2.3.4", + "stream-shift": "1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", + "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.33", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.33.tgz", + "integrity": "sha1-vwBwPWKnxlI4E2V4w1LWxcBCpUU=", + "dev": true + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "ember-cli-string-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz", + "integrity": "sha1-ObZ3/CgF9VFzc1N2/O8njqpEUqE=", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "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" + } + }, + "engine.io": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.4.tgz", + "integrity": "sha1-PQIRtwpVLOhB/8fahiezAamkFi4=", + "dev": true, + "requires": { + "accepts": "1.3.3", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "2.6.9", + "engine.io-parser": "2.1.2", + "uws": "0.14.5", + "ws": "3.3.3" + }, + "dependencies": { + "accepts": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", + "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", + "dev": true, + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + } + } + }, + "engine.io-client": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.4.tgz", + "integrity": "sha1-T88TcLRxY70s6b4nM5ckMDUNTqE=", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "2.6.9", + "engine.io-parser": "2.1.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "3.3.3", + "xmlhttprequest-ssl": "1.5.5", + "yeast": "0.1.2" + } + }, + "engine.io-parser": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", + "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.4", + "has-binary2": "1.0.2" + } + }, + "enhanced-resolve": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", + "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "memory-fs": "0.4.1", + "object-assign": "4.1.1", + "tapable": "0.2.8" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "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.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.10.0.tgz", + "integrity": "sha512-/uh/DhdqIOSkAWifU+8nG78vlQxdLckUdI/sPgy0VhuXi2qJ7T8czBmqIYtLQVpCIFYafChnsRsB5pyb1JdmCQ==", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "es5-ext": { + "version": "0.10.37", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz", + "integrity": "sha1-DudB0Ui4AGm6J9AgOTdWryV978M=", + "dev": true, + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.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.0.0", + "es5-ext": "0.10.37", + "es6-symbol": "3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.37", + "es6-iterator": "2.0.3", + "es6-set": "0.1.5", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.37", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1", + "event-emitter": "0.3.5" + } + }, + "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.0.0", + "es5-ext": "0.10.37" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.37", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "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.9.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz", + "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==", + "dev": true, + "optional": true, + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.5.7" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true, + "optional": true + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true, + "requires": { + "es6-map": "0.1.5", + "es6-weak-map": "2.0.2", + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } + }, + "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 + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.37" + } + }, + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", + "dev": true + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true + }, + "eventsource": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", + "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", + "dev": true, + "requires": { + "original": "1.0.0" + } + }, + "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" + } + }, + "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.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + }, + "dependencies": { + "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.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + } + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-braces": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", + "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "dev": true, + "requires": { + "array-slice": "0.2.3", + "array-unique": "0.2.1", + "braces": "0.1.5" + }, + "dependencies": { + "braces": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", + "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "dev": true, + "requires": { + "expand-range": "0.1.1" + } + }, + "expand-range": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", + "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "dev": true, + "requires": { + "is-number": "0.1.1", + "repeat-string": "0.2.2" + } + }, + "is-number": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", + "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", + "dev": true + }, + "repeat-string": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", + "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", + "dev": true + } + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "exports-loader": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.6.4.tgz", + "integrity": "sha1-1w/GEhl1s1/BKDDPUnVL4nQPyIY=", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "source-map": "0.5.7" + } + }, + "express": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", + "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", + "dev": true, + "requires": { + "accepts": "1.3.4", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.2", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.2", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.1", + "serve-static": "1.13.1", + "setprototypeof": "1.1.0", + "statuses": "1.3.1", + "type-is": "1.6.15", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "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.1" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extract-text-webpack-plugin": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz", + "integrity": "sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==", + "dev": true, + "requires": { + "async": "2.6.0", + "loader-utils": "1.1.0", + "schema-utils": "0.3.0", + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "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, + "optional": true + }, + "fastparse": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", + "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=", + "dev": true + }, + "faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "dev": true, + "requires": { + "websocket-driver": "0.7.0" + } + }, + "file-loader": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.6.tgz", + "integrity": "sha512-873ztuL+/hfvXbLDJ262PGO6XjERnybJu2gW1/5j8HUfxSiFJI9Hj/DhZ50ZGRUxBvuNiazb/cM2rh9pqrxP6Q==", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "schema-utils": "0.3.0" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "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.1.2", + "minimatch": "3.0.4" + } + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + } + }, + "find-cache-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", + "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, + "requires": { + "commondir": "1.0.1", + "make-dir": "1.1.0", + "pkg-dir": "2.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" + } + }, + "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.0.2", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz", + "integrity": "sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.4" + } + }, + "follow-redirects": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", + "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "dev": true, + "optional": true, + "requires": { + "debug": "2.6.9" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "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.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.17" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "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.3", + "readable-stream": "2.3.4" + } + }, + "fs-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", + "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=", + "dev": true, + "requires": { + "null-check": "1.0.0" + } + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "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.11", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.3.4" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", + "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "dev": true, + "optional": true, + "requires": { + "nan": "2.10.0", + "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 + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "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 + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": 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.5.1", + "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.2", + "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.21", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": "^2.1.0" + } + }, + "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 + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": 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, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "minipass": { + "version": "2.2.4", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "^5.1.1", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "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.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.1.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.3", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.1.10", + "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 + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": 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.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.5.1", + "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.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.1", + "bundled": true, + "dev": 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.5.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, + "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, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.0.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.2.4", + "minizlib": "^1.1.0", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.1", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "3.0.2", + "bundled": true, + "dev": 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.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "optional": true, + "requires": { + "readable-stream": "1.1.14", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true, + "optional": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true, + "optional": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "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.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.3" + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "optional": true, + "requires": { + "globule": "1.2.1" + } + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true, + "optional": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "optional": true, + "requires": { + "is-property": "1.0.2" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "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-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.1.tgz", + "integrity": "sha512-7aelVrYqCLuVjq2kEKRTH8fXPTC0xKTkM+G7UlFkEwCXY3sFbSxvY375JoFowOAYbkaU47SrBvOefUlLZZ+6QA==", + "dev": true, + "optional": true, + "requires": { + "data-uri-to-buffer": "1.2.0", + "debug": "2.6.9", + "extend": "3.0.1", + "file-uri-to-path": "1.0.0", + "ftp": "0.3.10", + "readable-stream": "2.3.4" + } + }, + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "dir-glob": "2.0.0", + "glob": "7.1.2", + "ignore": "3.3.7", + "pify": "3.0.0", + "slash": "1.0.0" + } + }, + "globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "dev": true, + "optional": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.10", + "minimatch": "3.0.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true, + "optional": true + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "hammerjs": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", + "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" + }, + "handle-thing": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", + "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=", + "dev": true + }, + "handlebars": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, + "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": "1.0.1" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + }, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + } + } + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "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.1.1" + } + }, + "has-binary2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", + "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=", + "dev": true, + "requires": { + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "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.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "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.2.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.6" + } + } + } + }, + "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.6" + } + } + } + }, + "hash-base": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", + "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hipchat-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz", + "integrity": "sha1-ttJJdVQ3wZEII2d5nTupoPI7Ix4=", + "dev": true, + "optional": true, + "requires": { + "lodash": "4.17.5", + "request": "2.81.0" + } + }, + "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.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "1.0.0" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "obuf": "1.1.1", + "readable-stream": "2.3.4", + "wbuf": "1.7.2" + } + }, + "html-comment-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", + "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", + "dev": true + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=", + "dev": true + }, + "html-minifier": { + "version": "3.5.9", + "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.9.tgz", + "integrity": "sha512-EZqO91XJwkj8BeLx9C12sKB/AHoTANaZax39vEOP9f/X/9jgJ3r1O2+neabuHqpz5kJO71TapP9JrtCY39su1A==", + "dev": true, + "requires": { + "camel-case": "3.0.0", + "clean-css": "4.1.9", + "commander": "2.14.1", + "he": "1.1.1", + "ncname": "1.0.0", + "param-case": "2.1.1", + "relateurl": "0.2.7", + "uglify-js": "3.3.11" + } + }, + "html-webpack-plugin": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz", + "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "html-minifier": "3.5.9", + "loader-utils": "0.2.17", + "lodash": "4.17.5", + "pretty-error": "2.1.1", + "toposort": "1.0.6" + }, + "dependencies": { + "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.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1", + "object-assign": "4.1.1" + } + } + } + }, + "htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", + "dev": true + }, + "htmlparser2": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", + "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.1.0", + "domutils": "1.1.6", + "readable-stream": "1.0.34" + }, + "dependencies": { + "domutils": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", + "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "dev": true, + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + }, + "dependencies": { + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "dev": true + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "dev": true + }, + "http-proxy": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", + "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", + "dev": true, + "requires": { + "eventemitter3": "1.2.0", + "requires-port": "1.0.0" + } + }, + "http-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz", + "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.9", + "extend": "3.0.1" + } + }, + "http-proxy-middleware": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", + "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", + "dev": true, + "requires": { + "http-proxy": "1.16.2", + "is-glob": "3.1.0", + "lodash": "4.17.5", + "micromatch": "2.3.11" + }, + "dependencies": { + "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": "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.1" + } + } + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "httpntlm": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", + "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", + "dev": true, + "requires": { + "httpreq": "0.4.24", + "underscore": "1.7.0" + } + }, + "httpreq": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", + "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", + "dev": true + }, + "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 + }, + "https-proxy-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", + "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.9", + "extend": "3.0.1" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "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.18" + } + }, + "ieee754": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "ignore": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", + "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", + "dev": true + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", + "dev": true, + "optional": 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, + "optional": true + }, + "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.1" + } + }, + "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 + }, + "inflection": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.10.0.tgz", + "integrity": "sha1-W//LEZetPoEFD44X4hZoCH7p6y8=", + "dev": true, + "optional": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "insert-module-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz", + "integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=", + "dev": true, + "requires": { + "JSONStream": "1.3.2", + "combine-source-map": "0.7.2", + "concat-stream": "1.5.2", + "is-buffer": "1.1.6", + "lexical-scope": "1.2.0", + "process": "0.11.10", + "through2": "2.0.3", + "xtend": "4.0.1" + }, + "dependencies": { + "combine-source-map": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz", + "integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=", + "dev": true, + "requires": { + "convert-source-map": "1.1.3", + "inline-source-map": "0.6.2", + "lodash.memoize": "3.0.4", + "source-map": "0.5.7" + } + }, + "concat-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", + "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.0.6", + "typedarray": "0.0.6" + } + }, + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=", + "dev": true + }, + "lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "internal-ip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", + "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", + "dev": true, + "requires": { + "meow": "3.7.0" + } + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "dev": true + }, + "intl": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/intl/-/intl-1.2.5.tgz", + "integrity": "sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94=" + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "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 + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=", + "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": "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.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 + } + } + }, + "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.11.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "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.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 + } + } + }, + "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": "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" + }, + "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 + } + } + }, + "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-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "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": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "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.1" + } + }, + "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.1" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "dev": true, + "optional": true + }, + "is-my-json-valid": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", + "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "dev": true, + "optional": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "is-my-ip-valid": "1.0.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-odd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", + "integrity": "sha1-O4qTLrAos3dcObsJ6RdnrM22kIg=", + "dev": true, + "requires": { + "is-number": "3.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.2.2" + } + } + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "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.2" + } + }, + "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==", + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true, + "optional": 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-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "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.1" + } + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "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-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 + }, + "isbinaryfile": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", + "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", + "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": "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" + } + }, + "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": "1.2.2", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.2.2.tgz", + "integrity": "sha512-kH5YRdqdbs5hiH4/Rr1Q0cSAGgjh3jTtg8vu9NLebBAoK3adVO4jk81J+TYOkTr2+Q4NLeb1ACvmEt65iG/Vbw==", + "dev": true, + "requires": { + "async": "2.6.0", + "fileset": "2.0.3", + "istanbul-lib-coverage": "1.1.2", + "istanbul-lib-hook": "1.1.0", + "istanbul-lib-instrument": "1.9.2", + "istanbul-lib-report": "1.1.3", + "istanbul-lib-source-maps": "1.2.3", + "istanbul-reports": "1.1.4", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "once": "1.4.0" + } + }, + "istanbul-instrumenter-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.0.tgz", + "integrity": "sha512-alLSEFX06ApU75sm5oWcaVNaiss/bgMRiWTct3g0P0ZZTKjR+6QiCcuVOKDI1kWJgwHEnIXsv/dWm783kPpmtw==", + "dev": true, + "requires": { + "convert-source-map": "1.5.1", + "istanbul-lib-instrument": "1.9.2", + "loader-utils": "1.1.0", + "schema-utils": "0.3.0" + } + }, + "istanbul-lib-coverage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.2.tgz", + "integrity": "sha512-tZYA0v5A7qBSsOzcebJJ/z3lk3oSzH62puG78DbBA1+zupipX2CakDyiPV3pOb8He+jBwVimuwB0dTnh38hX0w==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz", + "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", + "dev": true, + "requires": { + "append-transform": "0.4.0" + } + }, + "istanbul-lib-instrument": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.2.tgz", + "integrity": "sha512-nz8t4HQ2206a/3AXi+NHFWEa844DMpPsgbcUteJbt1j8LX1xg56H9rOMnhvcvVvPbW60qAIyrSk44H8ZDqaSSA==", + "dev": true, + "requires": { + "babel-generator": "6.26.1", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "istanbul-lib-coverage": "1.1.2", + "semver": "5.5.0" + } + }, + "istanbul-lib-report": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.3.tgz", + "integrity": "sha512-D4jVbMDtT2dPmloPJS/rmeP626N5Pr3Rp+SovrPn1+zPChGHcggd/0sL29jnbm4oK9W0wHjCRsdch9oLd7cm6g==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "1.1.2", + "mkdirp": "0.5.1", + "path-parse": "1.0.5", + "supports-color": "3.2.3" + }, + "dependencies": { + "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 + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz", + "integrity": "sha512-fDa0hwU/5sDXwAklXgAoCJCOsFsBplVQ6WBldz5UwaqOzmDhUK4nfuR7/G//G2lERlblUNJB8P6e8cXq3a7MlA==", + "dev": true, + "requires": { + "debug": "3.1.0", + "istanbul-lib-coverage": "1.1.2", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "source-map": "0.5.7" + }, + "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" + } + } + } + }, + "istanbul-reports": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.4.tgz", + "integrity": "sha512-DfSTVOTkuO+kRmbO8Gk650Wqm1WRGr6lrdi2EwDK1vxpS71vdlLd613EpzOKdIFioB5f/scJTjeWBnvd1FWejg==", + "dev": true, + "requires": { + "handlebars": "4.0.11" + } + }, + "jasmine": { + "version": "2.99.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.99.0.tgz", + "integrity": "sha1-jKctEC5jm4Z8ZImFbg4YqceqQrc=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "7.1.2", + "jasmine-core": "2.99.1" + }, + "dependencies": { + "jasmine-core": { + "version": "2.99.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", + "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", + "dev": true + } + } + }, + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", + "dev": true + }, + "jasmine-spec-reporter": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", + "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "dev": true, + "requires": { + "colors": "1.1.2" + } + }, + "jasminewd2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=", + "dev": true + }, + "js-base64": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz", + "integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.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.10", + "esprima": "2.7.3" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "json-loader": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", + "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==", + "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.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "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 + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true, + "optional": 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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "karma": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.0.tgz", + "integrity": "sha512-K9Kjp8CldLyL9ANSUctDyxC7zH3hpqXj/K09qVf06K3T/kXaHtFZ5tQciK7OzQu68FLvI89Na510kqQ2LCbpIw==", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "body-parser": "1.18.2", + "browserify": "14.5.0", + "chokidar": "1.7.0", + "colors": "1.1.2", + "combine-lists": "1.0.1", + "connect": "3.6.6", + "core-js": "2.5.3", + "di": "0.0.1", + "dom-serialize": "2.2.1", + "expand-braces": "0.1.2", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "http-proxy": "1.16.2", + "isbinaryfile": "3.0.2", + "lodash": "4.17.5", + "log4js": "2.5.3", + "mime": "1.6.0", + "minimatch": "3.0.4", + "optimist": "0.6.1", + "qjobs": "1.1.5", + "range-parser": "1.2.0", + "rimraf": "2.6.2", + "safe-buffer": "5.1.1", + "socket.io": "2.0.4", + "source-map": "0.6.1", + "tmp": "0.0.33", + "useragent": "2.3.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 + } + } + }, + "karma-chrome-launcher": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "dev": true, + "requires": { + "fs-access": "1.0.1", + "which": "1.3.0" + } + }, + "karma-coverage-istanbul-reporter": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.1.tgz", + "integrity": "sha512-5og0toMjgLvsL9+TzGH4Rk1D0nr7pMIRJBg29xP4mHMKy/1KUJ12UzoqI6mBNCRFa4nDvZS2MRrN7p+RkZNWxQ==", + "dev": true, + "requires": { + "istanbul-api": "1.2.2", + "minimatch": "3.0.4" + } + }, + "karma-jasmine": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.1.tgz", + "integrity": "sha1-b+hA51oRYAydkehLM8RY4cRqNSk=", + "dev": true + }, + "karma-jasmine-html-reporter": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz", + "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=", + "dev": true, + "requires": { + "karma-jasmine": "1.1.1" + } + }, + "karma-source-map-support": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.2.0.tgz", + "integrity": "sha1-G/gee7SwiWJ6s1LsQXnhF8QGpUA=", + "dev": true, + "requires": { + "source-map-support": "0.4.18" + } + }, + "killable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.0.tgz", + "integrity": "sha1-2ouEvUfeU5WHj5XWTQLyRJ/gXms=", + "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.6" + } + }, + "labeled-stream-splicer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz", + "integrity": "sha1-pS4dE4AkwAuGscDJH2d5GLiuClk=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "isarray": "0.0.1", + "stream-splicer": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, + "lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", + "dev": true + }, + "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" + } + }, + "less": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", + "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", + "dev": true, + "requires": { + "errno": "0.1.7", + "graceful-fs": "4.1.11", + "image-size": "0.5.5", + "mime": "1.6.0", + "mkdirp": "0.5.1", + "promise": "7.3.1", + "request": "2.81.0", + "source-map": "0.5.7" + } + }, + "less-loader": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.0.5.tgz", + "integrity": "sha1-rhVadAbKxqzSk9eFWH/P8PR4xN0=", + "dev": true, + "requires": { + "clone": "2.1.1", + "loader-utils": "1.1.0", + "pify": "2.3.0" + }, + "dependencies": { + "clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "optional": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lexical-scope": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", + "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=", + "dev": true, + "requires": { + "astw": "2.2.0" + } + }, + "libbase64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", + "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", + "dev": true + }, + "libmime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", + "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", + "dev": true, + "requires": { + "iconv-lite": "0.4.15", + "libbase64": "0.1.0", + "libqp": "1.1.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", + "dev": true + } + } + }, + "libqp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", + "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", + "dev": true + }, + "license-webpack-plugin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-1.1.1.tgz", + "integrity": "sha512-TjKOyiC0exqd4Idy/4M8/DETR22dXBZks387DuS5LbslxHiMRXGx/Q2F/j9IUtvEoH5uFvt72vRgk/G6f8j3Dg==", + "dev": true, + "requires": { + "ejs": "2.5.7" + } + }, + "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.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "loader-runner": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", + "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "dev": true + }, + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1" + } + }, + "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.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true, + "optional": 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.endswith": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.endswith/-/lodash.endswith-4.2.1.tgz", + "integrity": "sha1-/tWawXOO0+I27dcGTsRWRIs3vAk=", + "dev": true + }, + "lodash.isfunction": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", + "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==", + "dev": true + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=", + "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, + "optional": true + }, + "lodash.startswith": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz", + "integrity": "sha1-xZjErc4YiiflMUVzHNxsDnF3YAw=", + "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 + }, + "log4js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.5.3.tgz", + "integrity": "sha512-YL/qpTxYtK0iWWbuKCrevDZz5lh+OjyHHD+mICqpjnYGKdNRBvPeh/1uYjkKUemT1CSO4wwLOwphWMpKAnD9kw==", + "dev": true, + "requires": { + "amqplib": "0.5.2", + "axios": "0.15.3", + "circular-json": "0.5.1", + "date-format": "1.2.0", + "debug": "3.1.0", + "hipchat-notifier": "1.1.0", + "loggly": "1.1.1", + "mailgun-js": "0.7.15", + "nodemailer": "2.7.2", + "redis": "2.8.0", + "semver": "5.5.0", + "slack-node": "0.2.0", + "streamroller": "0.7.0" + }, + "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" + } + } + } + }, + "loggly": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/loggly/-/loggly-1.1.1.tgz", + "integrity": "sha1-Cg/B0/o6XsRP3HuJe+uipGlc6+4=", + "dev": true, + "optional": true, + "requires": { + "json-stringify-safe": "5.0.1", + "request": "2.75.0", + "timespan": "2.3.0" + }, + "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, + "optional": true + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "form-data": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", + "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", + "dev": true, + "optional": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.17" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "optional": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.14.1", + "is-my-json-valid": "2.17.2", + "pinkie-promise": "2.0.1" + } + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "dev": true, + "optional": true + }, + "qs": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", + "dev": true, + "optional": true + }, + "request": { + "version": "2.75.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", + "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "bl": "1.1.2", + "caseless": "0.11.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.0.0", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "node-uuid": "1.4.8", + "oauth-sign": "0.8.2", + "qs": "6.2.3", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.4.3" + } + }, + "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, + "optional": true + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true, + "optional": true + } + } + }, + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "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.2" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=", + "dev": true + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "macaddress": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", + "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=", + "dev": true + }, + "magic-string": { + "version": "0.22.4", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.4.tgz", + "integrity": "sha512-kxBL06p6iO2qPBHsqGK2b3cRwiRGpnmSuVWNhwHcMX7qJOUr1HvricYP1LZOCdkQBUp0jiWg2d6WJwR3vYgByw==", + "dev": true, + "requires": { + "vlq": "0.2.3" + } + }, + "mailcomposer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz", + "integrity": "sha1-DhxEsqB890DuF9wUm6AJ8Zyt/rQ=", + "dev": true, + "optional": true, + "requires": { + "buildmail": "4.0.1", + "libmime": "3.0.0" + } + }, + "mailgun-js": { + "version": "0.7.15", + "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.7.15.tgz", + "integrity": "sha1-7jZqINrGTDwVwD1sGz4O15UlKrs=", + "dev": true, + "optional": true, + "requires": { + "async": "2.1.5", + "debug": "2.2.0", + "form-data": "2.1.4", + "inflection": "1.10.0", + "is-stream": "1.1.0", + "path-proxy": "1.0.0", + "proxy-agent": "2.0.0", + "q": "1.4.1", + "tsscmp": "1.0.5" + }, + "dependencies": { + "async": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.5.tgz", + "integrity": "sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw=", + "dev": true, + "optional": true, + "requires": { + "lodash": "4.17.5" + } + }, + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "optional": 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, + "optional": true + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true, + "optional": true + } + } + }, + "make-dir": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.1.0.tgz", + "integrity": "sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==", + "dev": true, + "requires": { + "pify": "3.0.0" + } + }, + "make-error": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", + "integrity": "sha512-0Dab5btKVPhibSalc9QGXb559ED7G7iLjFXBaj9Wq8O3vorueR5K5jaE3hkG6ZQINyhA/JgG6Qk4qdFQjsYV6g==", + "dev": true + }, + "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.1" + } + }, + "material-design-icons-iconfont": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/material-design-icons-iconfont/-/material-design-icons-iconfont-3.0.3.tgz", + "integrity": "sha1-FUoQhAR9Ticjf6f1o34Qdc7qbfI=" + }, + "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.4", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", + "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "dev": true, + "requires": { + "hash-base": "3.0.4", + "inherits": "2.0.3" + }, + "dependencies": { + "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.3", + "safe-buffer": "5.1.1" + } + } + } + }, + "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": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.2.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.7", + "readable-stream": "2.3.4" + } + }, + "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.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.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-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "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.11.8", + "brorand": "1.1.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.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.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=", + "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==", + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mississippi": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-1.3.1.tgz", + "integrity": "sha512-/6rB8YXFbAtsUVRphIRQqB0+9c7VaPHCjVtvto+JqwVxgz8Zz+I+f68/JgQ+Pb4VlZb2svA9OtdXnHHsZz7ltg==", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "duplexify": "3.5.3", + "end-of-stream": "1.4.1", + "flush-write-stream": "1.0.2", + "from2": "2.3.0", + "parallel-transform": "1.1.0", + "pump": "1.0.3", + "pumpify": "1.4.0", + "stream-each": "1.2.2", + "through2": "2.0.3" + } + }, + "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.8", + "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" + } + }, + "module-deps": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz", + "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=", + "dev": true, + "requires": { + "JSONStream": "1.3.2", + "browser-resolve": "1.11.2", + "cached-path-relative": "1.0.1", + "concat-stream": "1.5.2", + "defined": "1.0.0", + "detective": "4.7.1", + "duplexer2": "0.1.4", + "inherits": "2.0.3", + "parents": "1.0.1", + "readable-stream": "2.3.4", + "resolve": "1.5.0", + "stream-combiner2": "1.1.1", + "subarg": "1.0.0", + "through2": "2.0.3", + "xtend": "4.0.1" + }, + "dependencies": { + "concat-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", + "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.0.6", + "typedarray": "0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + } + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "moment": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz", + "integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=" + }, + "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.2.0", + "copy-concurrently": "1.0.5", + "fs-write-stream-atomic": "1.0.10", + "mkdirp": "0.5.1", + "rimraf": "2.6.2", + "run-queue": "1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "1.3.1", + "thunky": "1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "mydaterangepicker": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/mydaterangepicker/-/mydaterangepicker-4.2.1.tgz", + "integrity": "sha1-8GPkdHAWJZua2IIVnvwcffCSIc0=" + }, + "nan": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.7.tgz", + "integrity": "sha512-/5ldsnyurvEw7wNpxLFgjVvBLMta43niEYOy0CJ4ntcYSbx6bugRUTQeFb4BR/WanEL1o3aQgHuVLHQaB6tOqg==", + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "1.0.0", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "is-odd": "1.0.0", + "kind-of": "5.1.0", + "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": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "ncname": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz", + "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=", + "dev": true, + "requires": { + "xml-char-classes": "1.0.0" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "dev": true, + "optional": true + }, + "ng2-charts": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ng2-charts/-/ng2-charts-1.6.0.tgz", + "integrity": "sha512-9w0WH69x5/nuqC1og2WaY39NbaBqTGIP1+5gZaH7/KPN6UEPonNg/pYnsIVklLj1DWPWXKa8+XXIJZ1jy5nLxg==", + "requires": { + "chart.js": "2.7.1" + } + }, + "ng2-cookies": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/ng2-cookies/-/ng2-cookies-1.0.12.tgz", + "integrity": "sha1-Pz5hPgE3sGSbcFxngHS0vQgUnMw=" + }, + "ngx-loading": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/ngx-loading/-/ngx-loading-1.0.14.tgz", + "integrity": "sha1-GXWMM+o/qbuW3KH0DKGdTYa4BCw=" + }, + "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.4" + } + }, + "node-forge": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.1.tgz", + "integrity": "sha1-naYR6giYL0uUIGs760zJZl8gwwA=", + "dev": true + }, + "node-gyp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", + "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", + "dev": true, + "optional": true, + "requires": { + "fstream": "1.0.11", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.1.2", + "osenv": "0.1.5", + "request": "2.81.0", + "rimraf": "2.6.2", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.3.0" + }, + "dependencies": { + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "optional": true, + "requires": { + "abbrev": "1.1.1" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true, + "optional": true + } + } + }, + "node-libs-browser": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", + "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", + "dev": true, + "requires": { + "assert": "1.4.1", + "browserify-zlib": "0.2.0", + "buffer": "4.9.1", + "console-browserify": "1.1.0", + "constants-browserify": "1.0.0", + "crypto-browserify": "3.12.0", + "domain-browser": "1.2.0", + "events": "1.1.1", + "https-browserify": "1.0.0", + "os-browserify": "0.3.0", + "path-browserify": "0.0.0", + "process": "0.11.10", + "punycode": "1.4.1", + "querystring-es3": "0.2.1", + "readable-stream": "2.3.4", + "stream-browserify": "2.0.1", + "stream-http": "2.8.0", + "string_decoder": "1.0.3", + "timers-browserify": "2.0.6", + "tty-browserify": "0.0.0", + "url": "0.11.0", + "util": "0.10.3", + "vm-browserify": "0.0.4" + } + }, + "node-modules-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz", + "integrity": "sha1-QAlrCM560OoUaAhjr0ScfHWl0cg=", + "dev": true + }, + "node-sass": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.0.tgz", + "integrity": "sha512-QFHfrZl6lqRU3csypwviz2XLgGNOoWQbo2GOvtsfQqOfL4cy1BtWnhx/XUeAO9LT3ahBzSRXcEO6DdvAH9DzSg==", + "dev": true, + "optional": true, + "requires": { + "async-foreach": "0.1.3", + "chalk": "1.1.3", + "cross-spawn": "3.0.1", + "gaze": "1.1.3", + "get-stdin": "4.0.1", + "glob": "7.1.2", + "in-publish": "2.0.0", + "lodash.assign": "4.2.0", + "lodash.clonedeep": "4.5.0", + "lodash.mergewith": "4.6.1", + "meow": "3.7.0", + "mkdirp": "0.5.1", + "nan": "2.10.0", + "node-gyp": "3.6.2", + "npmlog": "4.1.2", + "request": "2.79.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 + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true, + "optional": 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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "optional": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.14.1", + "is-my-json-valid": "2.17.2", + "pinkie-promise": "2.0.1" + } + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "dev": true, + "optional": true + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true, + "optional": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.11.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "qs": "6.3.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.4.3", + "uuid": "3.2.1" + } + }, + "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 + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true, + "optional": true + } + } + }, + "nodemailer": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-2.7.2.tgz", + "integrity": "sha1-8kLmSa7q45tsftdA73sGHEBNMPk=", + "dev": true, + "optional": true, + "requires": { + "libmime": "3.0.0", + "mailcomposer": "4.0.1", + "nodemailer-direct-transport": "3.3.2", + "nodemailer-shared": "1.1.0", + "nodemailer-smtp-pool": "2.8.2", + "nodemailer-smtp-transport": "2.7.2", + "socks": "1.1.9" + }, + "dependencies": { + "socks": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", + "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", + "dev": true, + "optional": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "1.1.15" + } + } + } + }, + "nodemailer-direct-transport": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", + "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", + "dev": true, + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-fetch": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", + "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=", + "dev": true + }, + "nodemailer-shared": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", + "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", + "dev": true, + "requires": { + "nodemailer-fetch": "1.6.0" + } + }, + "nodemailer-smtp-pool": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz", + "integrity": "sha1-LrlNbPhXgLG0clzoU7nL1ejajHI=", + "dev": true, + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-smtp-transport": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz", + "integrity": "sha1-A9ccdjFPFKx9vHvwM6am0W1n+3c=", + "dev": true, + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-wellknown": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", + "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", + "dev": true + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "requires": { + "abbrev": "1.1.1", + "osenv": "0.1.5" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "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.1.0" + } + }, + "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-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.1.1", + "prepend-http": "1.0.4", + "query-string": "4.3.4", + "sort-keys": "1.1.2" + } + }, + "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.1" + } + }, + "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.5", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "1.0.0" + } + }, + "null-check": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz", + "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=", + "dev": true + }, + "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 + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "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=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "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.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" + }, + "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.6" + } + }, + "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.2.2" + } + }, + "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.2.2" + } + }, + "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.1.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 + } + } + } + } + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "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.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "obuf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.1.tgz", + "integrity": "sha1-EEEktsYCxnlogaBCVB0220OlJk4=", + "dev": true + }, + "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" + } + }, + "on-headers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "opn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", + "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", + "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.8", + "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, + "optional": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "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, + "optional": true + } + } + }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", + "dev": true + }, + "original": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", + "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=", + "dev": true, + "requires": { + "url-parse": "1.0.5" + }, + "dependencies": { + "url-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz", + "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=", + "dev": true, + "requires": { + "querystringify": "0.0.4", + "requires-port": "1.0.0" + } + } + } + }, + "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": "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" + } + }, + "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.2", + "os-tmpdir": "1.0.2" + } + }, + "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-limit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", + "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "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.2.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "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 + }, + "pac-proxy-agent": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz", + "integrity": "sha512-QBELCWyLYPgE2Gj+4wUEiMscHrQ8nRPBzYItQNOHWavwBt25ohZHQC4qnd5IszdVVrFbLsQ+dPkm6eqdjJAmwQ==", + "dev": true, + "optional": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.9", + "extend": "3.0.1", + "get-uri": "2.0.1", + "http-proxy-agent": "1.0.0", + "https-proxy-agent": "1.0.0", + "pac-resolver": "2.0.0", + "raw-body": "2.3.2", + "socks-proxy-agent": "2.1.1" + } + }, + "pac-resolver": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-2.0.0.tgz", + "integrity": "sha1-mbiNLxk/ve78HJpSnB8yYKtSd80=", + "dev": true, + "optional": true, + "requires": { + "co": "3.0.6", + "degenerator": "1.0.4", + "ip": "1.0.1", + "netmask": "1.0.6", + "thunkify": "2.1.2" + }, + "dependencies": { + "co": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/co/-/co-3.0.6.tgz", + "integrity": "sha1-FEXyJsXrlWE45oyawwFn6n0ua9o=", + "dev": true, + "optional": true + }, + "ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.0.1.tgz", + "integrity": "sha1-x+NWzeoiWucbNtcPLnGpK6TkJZA=", + "dev": true, + "optional": true + } + } + }, + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "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.3.4" + } + }, + "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.3.2" + } + }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "dev": true, + "requires": { + "path-platform": "0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", + "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", + "dev": true, + "requires": { + "asn1.js": "4.10.1", + "browserify-aes": "1.1.1", + "create-hash": "1.1.3", + "evp_bytestokey": "1.0.3", + "pbkdf2": "3.0.14" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.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.3.1" + } + }, + "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 + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "1.0.2" + } + }, + "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=", + "dev": true + }, + "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.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", + "dev": true + }, + "path-proxy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", + "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=", + "dev": true, + "optional": true, + "requires": { + "inflection": "1.3.8" + }, + "dependencies": { + "inflection": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz", + "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4=", + "dev": true, + "optional": true + } + } + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "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" + } + }, + "pbkdf2": { + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", + "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "dev": true, + "requires": { + "create-hash": "1.1.3", + "create-hmac": "1.1.6", + "ripemd160": "2.0.1", + "safe-buffer": "5.1.1", + "sha.js": "2.4.10" + } + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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.4" + } + }, + "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" + } + }, + "portfinder": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz", + "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", + "dev": true, + "requires": { + "async": "1.5.2", + "debug": "2.6.9", + "mkdirp": "0.5.1" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, + "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": "6.0.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.18.tgz", + "integrity": "sha512-X8MyLi3OYI1o71u0SsefWLpGBo5xnGiK1Pn+nrZFplc671Ts7L8aPwEbPIO8AWpulK5wuaVzyM9Rw6R8o7hYBw==", + "dev": true, + "requires": { + "chalk": "2.3.1", + "source-map": "0.6.1", + "supports-color": "5.2.0" + }, + "dependencies": { + "chalk": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", + "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "5.2.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 + }, + "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 + }, + "supports-color": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", + "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "dev": true, + "requires": { + "has-flag": "3.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.2.18", + "postcss-message-helpers": "2.0.0", + "reduce-css-calc": "1.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.1.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18", + "uniqs": "2.0.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-filter-plugins": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", + "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "uniqid": "4.1.1" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-import": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-11.1.0.tgz", + "integrity": "sha512-5l327iI75POonjxkXgdRCUS+AlzAdBx4pOvMEhTKTCjb1p8IEeVR9yx3cPbmN7LIWJLbfnIXxAhoB4jpD0c/Cw==", + "dev": true, + "requires": { + "postcss": "6.0.18", + "postcss-value-parser": "3.3.0", + "read-cache": "1.0.0", + "resolve": "1.5.0" + } + }, + "postcss-load-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", + "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1", + "postcss-load-options": "1.2.0", + "postcss-load-plugins": "2.3.0" + } + }, + "postcss-load-options": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", + "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1" + } + }, + "postcss-load-plugins": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", + "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1" + } + }, + "postcss-loader": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.1.0.tgz", + "integrity": "sha512-S/dKzpDwGFmP9g8eyCu9sUIV+/+3UooeTpYlsKf23qKDdrhHuA4pTSfytVu0rEJ0iDqUavXrgtOPq5KhNyNMOw==", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "postcss": "6.0.18", + "postcss-load-config": "1.2.0", + "schema-utils": "0.4.5" + }, + "dependencies": { + "ajv": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", + "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", + "dev": true, + "requires": { + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "schema-utils": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", + "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", + "dev": true, + "requires": { + "ajv": "6.1.1", + "ajv-keywords": "3.1.0" + } + } + } + }, + "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.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.7.7", + "caniuse-api": "1.6.1", + "postcss": "5.2.18", + "postcss-selector-parser": "2.2.3", + "vendors": "1.0.1" + }, + "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 + }, + "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.30000808", + "electron-to-chromium": "1.3.33" + } + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.1.1", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0", + "uniqs": "2.0.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18", + "postcss-selector-parser": "2.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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-modules-extract-imports": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz", + "integrity": "sha1-ZhQOzs447wa/DT41XWm/WdFB6oU=", + "dev": true, + "requires": { + "postcss": "6.0.18" + } + }, + "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.18" + } + }, + "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.18" + } + }, + "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.18" + } + }, + "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.2.18" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.1.0", + "normalize-url": "1.9.1", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2.18", + "postcss-value-parser": "3.3.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.1.0", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0", + "svgo": "0.7.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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-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.2", + "postcss": "5.2.18", + "uniqs": "2.0.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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-url": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-7.3.0.tgz", + "integrity": "sha512-VBP6uf6iL3AZra23nkPkOEkS/5azj1xf/toRrjfkolfFEgg9Gyzg9UhJZeIsz12EGKZTNVeGbPa2XtaZm/iZvg==", + "dev": true, + "requires": { + "mime": "1.6.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "postcss": "6.0.18", + "xxhashjs": "0.2.2" + } + }, + "postcss-value-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", + "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", + "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.2.18", + "uniqs": "2.0.0" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "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 + }, + "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.4.3", + "source-map": "0.5.7", + "supports-color": "3.2.3" + } + }, + "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" + } + } + } + }, + "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 + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "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.0" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "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==", + "dev": true, + "optional": true, + "requires": { + "asap": "2.0.6" + } + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "protractor": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.1.2.tgz", + "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=", + "dev": true, + "requires": { + "@types/node": "6.0.101", + "@types/q": "0.0.32", + "@types/selenium-webdriver": "2.53.43", + "blocking-proxy": "0.0.5", + "chalk": "1.1.3", + "glob": "7.1.2", + "jasmine": "2.99.0", + "jasminewd2": "2.2.0", + "optimist": "0.6.1", + "q": "1.4.1", + "saucelabs": "1.3.0", + "selenium-webdriver": "3.0.1", + "source-map-support": "0.4.18", + "webdriver-js-extender": "1.0.0", + "webdriver-manager": "12.0.6" + }, + "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.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "q": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", + "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true + }, + "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 + }, + "webdriver-manager": { + "version": "12.0.6", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz", + "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=", + "dev": true, + "requires": { + "adm-zip": "0.4.7", + "chalk": "1.1.3", + "del": "2.2.2", + "glob": "7.1.2", + "ini": "1.3.5", + "minimist": "1.2.0", + "q": "1.4.1", + "request": "2.81.0", + "rimraf": "2.6.2", + "semver": "5.5.0", + "xml2js": "0.4.19" + } + } + } + }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "dev": true, + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } + }, + "proxy-agent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-2.0.0.tgz", + "integrity": "sha1-V+tTR6qAXXTsaByyVknbo5yTNJk=", + "dev": true, + "optional": true, + "requires": { + "agent-base": "2.1.1", + "debug": "2.6.9", + "extend": "3.0.1", + "http-proxy-agent": "1.0.0", + "https-proxy-agent": "1.0.0", + "lru-cache": "2.6.5", + "pac-proxy-agent": "1.1.0", + "socks-proxy-agent": "2.1.1" + }, + "dependencies": { + "lru-cache": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz", + "integrity": "sha1-5W1jVBSO3o13B7WNFDIg/QjfD9U=", + "dev": true, + "optional": true + } + } + }, + "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 + }, + "public-encrypt": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", + "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", + "dev": true, + "requires": { + "bn.js": "4.11.8", + "browserify-rsa": "4.0.1", + "create-hash": "1.1.3", + "parse-asn1": "5.1.0", + "randombytes": "2.0.6" + } + }, + "pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "dev": true, + "requires": { + "end-of-stream": "1.4.1", + "once": "1.4.0" + } + }, + "pumpify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.4.0.tgz", + "integrity": "sha512-2kmNR9ry+Pf45opRVirpNuIFotsxUGLaYqxIwuR77AYrYRMuFCz9eryHBS52L360O+NcR383CL4QYlMKPq4zYA==", + "dev": true, + "requires": { + "duplexify": "3.5.3", + "inherits": "2.0.3", + "pump": "2.0.1" + }, + "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.4.1", + "once": "1.4.0" + } + } + } + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=", + "dev": true + }, + "qjobs": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz", + "integrity": "sha1-ZZ3p8s+NzCehSBJ28gU3cnI4LnM=", + "dev": true + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "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.1", + "strict-uri-encode": "1.1.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 + }, + "querystringify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz", + "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=", + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "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.2.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.6" + } + } + } + }, + "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.6" + } + } + } + }, + "randombytes": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", + "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "randomfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.3.tgz", + "integrity": "sha512-YL6GrhrWoic0Eq8rXVbMptH7dAxCs0J+mh5Y0euNekPPYaxEmdVGim6GdoxoRzKW2yJoU8tueifS7mYxvcFDEQ==", + "dev": true, + "requires": { + "randombytes": "2.0.6", + "safe-buffer": "5.1.1" + } + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, + "raw-loader": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", + "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=", + "dev": true + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "dev": true, + "requires": { + "readable-stream": "2.3.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.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + }, + "dependencies": { + "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.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "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.1.2", + "read-pkg": "1.1.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.1.0", + "pinkie-promise": "2.0.1" + } + }, + "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.1" + } + } + } + }, + "readable-stream": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz", + "integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.4", + "set-immediate-shim": "1.0.1" + } + }, + "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" + } + }, + "redis": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", + "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "dev": true, + "optional": true, + "requires": { + "double-ended-queue": "2.1.0-0", + "redis-commands": "1.3.1", + "redis-parser": "2.6.0" + } + }, + "redis-commands": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz", + "integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs=", + "dev": true, + "optional": true + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", + "dev": true, + "optional": true + }, + "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.17", + "reduce-function-call": "1.0.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 + } + } + }, + "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 + } + } + }, + "reflect-metadata": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", + "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==", + "dev": true + }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regex-not": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.0.tgz", + "integrity": "sha1-Qvg+OXcWIt+CawKvF2Ul1qXxV/k=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1" + } + }, + "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.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "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" + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "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.1", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz", + "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-converter": "0.1.4", + "htmlparser2": "3.3.0", + "strip-ansi": "3.0.1", + "utila": "0.3.3" + }, + "dependencies": { + "utila": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", + "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "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.2" + } + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, + "requestretry": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", + "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", + "dev": true, + "optional": true, + "requires": { + "extend": "3.0.1", + "lodash": "4.17.5", + "request": "2.81.0", + "when": "3.7.8" + }, + "dependencies": { + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "dev": true, + "optional": true + } + } + }, + "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": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "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 + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "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-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "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 + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "requires": { + "align-text": "0.1.4" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "ripemd160": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", + "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "dev": true, + "requires": { + "hash-base": "2.0.2", + "inherits": "2.0.3" + } + }, + "roboto-fontface": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.8.0.tgz", + "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ==" + }, + "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.2.0" + } + }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=" + }, + "rxjs": { + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.6.tgz", + "integrity": "sha512-v4Q5HDC0FHAQ7zcBX7T2IL6O5ltl1a2GX4ENjPXg6SjDY69Cmx9v4113C99a4wGF16ClPv5Z8mghuYorVkg/kg==", + "requires": { + "symbol-observable": "1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "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, + "optional": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.5", + "scss-tokenizer": "0.2.3", + "yargs": "7.1.0" + } + }, + "sass-loader": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-6.0.6.tgz", + "integrity": "sha512-c3/Zc+iW+qqDip6kXPYLEgsAu2lf4xz0EZDplB7EmSUMda12U1sGJPetH55B/j9eu0bTtKzKlNPWWyYC7wFNyQ==", + "dev": true, + "requires": { + "async": "2.6.0", + "clone-deep": "0.3.0", + "loader-utils": "1.1.0", + "lodash.tail": "4.1.1", + "pify": "3.0.0" + } + }, + "saucelabs": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz", + "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=", + "dev": true, + "requires": { + "https-proxy-agent": "1.0.0" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", + "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", + "dev": true, + "requires": { + "ajv": "5.5.2" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "optional": true, + "requires": { + "js-base64": "2.4.3", + "source-map": "0.4.4" + }, + "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, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selenium-webdriver": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz", + "integrity": "sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=", + "dev": true, + "requires": { + "adm-zip": "0.4.7", + "rimraf": "2.6.2", + "tmp": "0.0.30", + "xml2js": "0.4.19" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + } + } + }, + "selfsigned": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.2.tgz", + "integrity": "sha1-tESVgNmZKbZbEKSDiTAaZZIIh1g=", + "dev": true, + "requires": { + "node-forge": "0.7.1" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "semver-compare-multi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/semver-compare-multi/-/semver-compare-multi-1.0.3.tgz", + "integrity": "sha1-PhaVtL2MStvQGsHEb6CEZtNp3Ug=" + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "5.5.0" + } + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "1.1.2", + "destroy": "1.0.4", + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + }, + "dependencies": { + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.4.0.tgz", + "integrity": "sha1-fJWFFNtqwkQ6irwGLcn3iGp/YAU=", + "dev": true + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "1.0.3", + "http-errors": "1.6.2", + "mime-types": "2.1.17", + "parseurl": "1.3.2" + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "dev": true, + "requires": { + "encodeurl": "1.0.2", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.1" + } + }, + "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-getter": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", + "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", + "dev": true, + "requires": { + "to-object-path": "0.3.0" + } + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "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.4", + "split-string": "3.1.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "sha.js": { + "version": "2.4.10", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.10.tgz", + "integrity": "sha512-vnwmrFDlOExK4Nm16J2KMWHLrp14lBrjxMxBJpu++EnsuBmpiYaM/MEs46Vxxm/4FvdP5yTwuCTO9it5FSjrqA==", + "dev": true, + "requires": { + "inherits": "2.0.3", + "safe-buffer": "5.1.1" + } + }, + "shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "dev": true, + "requires": { + "is-extendable": "0.1.1", + "kind-of": "2.0.1", + "lazy-cache": "0.2.7", + "mixin-object": "2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=", + "dev": true, + "requires": { + "json-stable-stringify": "0.0.1", + "sha.js": "2.4.10" + }, + "dependencies": { + "json-stable-stringify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=", + "dev": true, + "requires": { + "jsonify": "0.0.0" + } + } + } + }, + "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 + }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "dev": true, + "requires": { + "array-filter": "0.0.1", + "array-map": "0.0.0", + "array-reduce": "0.0.0", + "jsonify": "0.0.0" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "silent-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz", + "integrity": "sha1-IglwbxyFCp8dENDYQJGLRvJuG8k=", + "dev": true, + "requires": { + "debug": "2.6.9" + } + }, + "slack-node": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.2.0.tgz", + "integrity": "sha1-3kuN3aqLeT9h29KTgQT9q/N9+jA=", + "dev": true, + "optional": true, + "requires": { + "requestretry": "1.13.0" + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "smart-buffer": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", + "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=", + "dev": true + }, + "smtp-connection": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", + "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", + "dev": true, + "requires": { + "httpntlm": "1.6.1", + "nodemailer-shared": "1.1.0" + } + }, + "snapdragon": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz", + "integrity": "sha1-4StUh/re0+PeoKyR6UAL91tAE3A=", + "dev": true, + "requires": { + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.1", + "use": "2.0.2" + }, + "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.6" + } + }, + "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.2.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.6" + } + } + } + }, + "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.2.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.6" + } + } + } + }, + "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.1.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 + } + } + }, + "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.1", + "snapdragon-util": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "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.2" + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "socket.io": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", + "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", + "dev": true, + "requires": { + "debug": "2.6.9", + "engine.io": "3.1.4", + "socket.io-adapter": "1.1.1", + "socket.io-client": "2.0.4", + "socket.io-parser": "3.1.2" + } + }, + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", + "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "2.6.9", + "engine.io-client": "3.1.4", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "3.1.2", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.2.tgz", + "integrity": "sha1-28IoIVH8T6675Aru3Ady66YZ9/I=", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "2.6.9", + "has-binary2": "1.0.2", + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } + } + }, + "sockjs": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz", + "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==", + "dev": true, + "requires": { + "faye-websocket": "0.10.0", + "uuid": "3.2.1" + } + }, + "sockjs-client": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz", + "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", + "dev": true, + "requires": { + "debug": "2.6.9", + "eventsource": "0.1.6", + "faye-websocket": "0.11.1", + "inherits": "2.0.3", + "json3": "3.3.2", + "url-parse": "1.2.0" + }, + "dependencies": { + "faye-websocket": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", + "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", + "dev": true, + "requires": { + "websocket-driver": "0.7.0" + } + } + } + }, + "socks": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", + "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", + "dev": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "1.1.15" + } + }, + "socks-proxy-agent": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz", + "integrity": "sha512-sFtmYqdUK5dAMh85H0LEVFUCO7OhJJe1/z2x/Z6mxp3s7/QPf1RkZmpZy+BpuU0bEjcV9npqKjq9Y3kwFUjnxw==", + "dev": true, + "requires": { + "agent-base": "2.1.1", + "extend": "3.0.1", + "socks": "1.1.10" + } + }, + "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.1.0" + } + }, + "source-list-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", + "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "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.1", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", + "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", + "dev": true, + "requires": { + "atob": "2.0.3", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" + } + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "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": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "spdy": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", + "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", + "dev": true, + "requires": { + "debug": "2.6.9", + "handle-thing": "1.2.5", + "http-deceiver": "1.2.7", + "safe-buffer": "5.1.1", + "select-hose": "2.0.0", + "spdy-transport": "2.0.20" + } + }, + "spdy-transport": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.20.tgz", + "integrity": "sha1-c15yBUxIayNU/onnAiVgBKOazk0=", + "dev": true, + "requires": { + "debug": "2.6.9", + "detect-node": "2.0.3", + "hpack.js": "2.1.6", + "obuf": "1.1.1", + "readable-stream": "2.3.4", + "safe-buffer": "5.1.1", + "wbuf": "1.7.2" + } + }, + "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.2" + }, + "dependencies": { + "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" + } + }, + "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" + } + } + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "ssri": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.2.2.tgz", + "integrity": "sha512-hm46mN8YSzjGuJtVocXPjwo0yTRXobXqYuK/tV6gr557/tRck4yWXKPRW8OxyJgRvcL3QgX+5ng/kMHBMco7KA==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "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.6" + } + }, + "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.2.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.6" + } + } + } + }, + "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.2.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.6" + } + } + } + }, + "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.1.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 + } + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "stdout-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", + "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "dev": true, + "optional": true, + "requires": { + "readable-stream": "2.3.4" + } + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.4" + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "dev": true, + "requires": { + "duplexer2": "0.1.4", + "readable-stream": "2.3.4" + } + }, + "stream-each": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", + "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", + "dev": true, + "requires": { + "end-of-stream": "1.4.1", + "stream-shift": "1.0.0" + } + }, + "stream-http": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.0.tgz", + "integrity": "sha512-sZOFxI/5xw058XIRHl4dU3dZ+TTOIGJR78Dvo0oEAejIt4ou27k+3ne1zYmCV+v7UucbxIFQuOgnkTVHh8YPnw==", + "dev": true, + "requires": { + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.4", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" + } + }, + "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 + }, + "stream-splicer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz", + "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.4" + } + }, + "streamroller": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", + "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "dev": true, + "requires": { + "date-format": "1.2.0", + "debug": "3.1.0", + "mkdirp": "0.5.1", + "readable-stream": "2.3.4" + }, + "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" + } + } + } + }, + "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-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.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "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.1.1" + } + }, + "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.1" + } + }, + "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.13.2", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.13.2.tgz", + "integrity": "sha1-dFMzhM9pjHEEx5URULSXF63C87s=", + "dev": true, + "requires": { + "loader-utils": "1.1.0" + } + }, + "stylus": { + "version": "0.54.5", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", + "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", + "dev": true, + "requires": { + "css-parse": "1.7.0", + "debug": "2.6.9", + "glob": "7.0.6", + "mkdirp": "0.5.1", + "sax": "0.5.8", + "source-map": "0.1.43" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "sax": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", + "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=", + "dev": true + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "stylus-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.1.tgz", + "integrity": "sha1-d/SzT9Aw0lsmF7z1UT21sHMMQIk=", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "lodash.clonedeep": "4.5.0", + "when": "3.6.4" + } + }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "dev": true, + "requires": { + "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 + } + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.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.4", + "colors": "1.1.2", + "csso": "2.3.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "sax": "1.2.4", + "whet.extend": "0.9.9" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=" + }, + "syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "dev": true, + "requires": { + "acorn-node": "1.3.0" + } + }, + "tapable": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", + "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "optional": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "2.3.4", + "xtend": "4.0.1" + } + }, + "thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", + "dev": true, + "optional": true + }, + "thunky": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz", + "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=", + "dev": true + }, + "time-stamp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz", + "integrity": "sha1-lcakRTDhW6jW9KPsuMOj+sRto1c=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.6.tgz", + "integrity": "sha512-HQ3nbYRAowdVd0ckGFvmJPPCOH/CHleFN/Y0YQCX1DVaB7t+KFvisuyN09fuP8Jtp1CpfSh8O8bMkHbdbPe6Pw==", + "dev": true, + "requires": { + "setimmediate": "1.0.5" + } + }, + "timespan": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", + "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=", + "dev": true, + "optional": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "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-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "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.2.2" + } + }, + "to-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.1.tgz", + "integrity": "sha1-FTWL7kosg712N3uh3ASdDxiDeq4=", + "dev": true, + "requires": { + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "regex-not": "1.0.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.6" + } + }, + "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.2.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.6" + } + } + } + }, + "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.2.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.6" + } + } + } + }, + "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.1.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 + } + } + }, + "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.2.2" + } + } + } + }, + "toposort": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.6.tgz", + "integrity": "sha1-wxdI5V0hDv/AD9zcfW5o19e7nOw=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tree-kill": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz", + "integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==", + "dev": true + }, + "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.2", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", + "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "dev": true, + "optional": true, + "requires": { + "glob": "6.0.4" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "optional": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "ts-node": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-4.1.0.tgz", + "integrity": "sha512-xcZH12oVg9PShKhy3UHyDmuDLV3y7iKwX25aMVPt1SIXSuAfWkFiGPEkg+th8R4YKW/QCxDoW7lJdb15lx6QWg==", + "dev": true, + "requires": { + "arrify": "1.0.1", + "chalk": "2.3.1", + "diff": "3.4.0", + "make-error": "1.3.4", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "source-map-support": "0.5.3", + "tsconfig": "7.0.0", + "v8flags": "3.0.1", + "yn": "2.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", + "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "5.2.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 + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "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 + }, + "source-map-support": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.3.tgz", + "integrity": "sha512-eKkTgWYeBOQqFGXRfKabMFdnWepo51vWqEdoeikaEPFiJC7MCU5j2h4+6Q8npkZTeLGbSyecZvRxiSoWl3rh+w==", + "dev": true, + "requires": { + "source-map": "0.6.1" + } + }, + "supports-color": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", + "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "requires": { + "@types/strip-bom": "3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1" + }, + "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 + } + } + }, + "tsickle": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.26.0.tgz", + "integrity": "sha512-eWJ2CUfttGK0LqF9iJ/Avnxbj4M+fCyJ50Zag3wm73Fut1hsasPRHKxKdrMWVj4BMHnQNx7TO+DdNmLmJTSuNw==", + "dev": true, + "requires": { + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "source-map": "0.5.7", + "source-map-support": "0.4.18" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "tslib": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==" + }, + "tslint": { + "version": "5.9.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz", + "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "builtin-modules": "1.1.1", + "chalk": "2.3.1", + "commander": "2.14.1", + "diff": "3.4.0", + "glob": "7.1.2", + "js-yaml": "3.7.0", + "minimatch": "3.0.4", + "resolve": "1.5.0", + "semver": "5.5.0", + "tslib": "1.9.0", + "tsutils": "2.21.1" + }, + "dependencies": { + "chalk": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", + "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "5.2.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 + }, + "supports-color": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", + "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "tsscmp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", + "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc=", + "dev": true, + "optional": true + }, + "tsutils": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.21.1.tgz", + "integrity": "sha512-heMkdeQ9iUc90ynfiNo5Y+GXrEEGy86KMvnSTfHO+Q40AuNQ1lZGXcv58fuU9XTUxI0V7YIN9xPN+CO9b1Gn3w==", + "dev": true, + "requires": { + "tslib": "1.9.0" + } + }, + "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.1.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, + "optional": 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.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", + "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", + "dev": true + }, + "uglify-js": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.11.tgz", + "integrity": "sha512-AKLsYcdV+sS5eAE4NtVXF6f2u/DCQynQm0jTGxF261+Vltu1dYNuHzjqDmk11gInj+H/zJIM2EAwXG3MzPb3VA==", + "dev": true, + "requires": { + "commander": "2.14.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 + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "uglifyjs-webpack-plugin": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.1.8.tgz", + "integrity": "sha512-XG8/QmR1pyPeE1kj2aigo5kos8umefB31zW+PMvAAytHSB0T/vQvN6sqt8+Sh+y0b0A7zlmxNi2dzRnj0wcqGA==", + "dev": true, + "requires": { + "cacache": "10.0.2", + "find-cache-dir": "1.0.0", + "schema-utils": "0.4.5", + "serialize-javascript": "1.4.0", + "source-map": "0.6.1", + "uglify-es": "3.3.9", + "webpack-sources": "1.1.0", + "worker-farm": "1.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.1.1.tgz", + "integrity": "sha1-l41Zf7wrfQ5aXD3esUmmgvKr+g4=", + "dev": true, + "requires": { + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "commander": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "dev": true + }, + "schema-utils": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", + "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", + "dev": true, + "requires": { + "ajv": "6.1.1", + "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 + }, + "uglify-es": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", + "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "dev": true, + "requires": { + "commander": "2.13.0", + "source-map": "0.6.1" + } + } + } + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "umd": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.1.tgz", + "integrity": "sha1-iuVW4RAR9jwllnCKiDclnwGz1g4=", + "dev": true + }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "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": { + "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.4", + "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 + }, + "uniqid": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", + "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", + "dev": true, + "requires": { + "macaddress": "0.2.8" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", + "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", + "dev": true, + "requires": { + "unique-slug": "2.0.0" + } + }, + "unique-slug": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", + "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "dev": true, + "requires": { + "imurmurhash": "0.1.4" + } + }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "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.1" + }, + "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.6", + "has-values": "0.1.4", + "isobject": "2.1.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 + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "upath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.2.tgz", + "integrity": "sha512-fCmij7T5LnwUme3dbnVSejvOHHlARjB3ikJFwgZfz386pHmf/gueuTLRFU94FZEaeCLlbQrweiUU700gG41tUw==", + "dev": true, + "requires": { + "lodash.endswith": "4.2.1", + "lodash.isfunction": "3.0.9", + "lodash.isstring": "4.0.1", + "lodash.startswith": "4.2.1" + } + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=", + "dev": true + }, + "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-loader": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz", + "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==", + "dev": true, + "requires": { + "loader-utils": "1.1.0", + "mime": "1.6.0", + "schema-utils": "0.3.0" + } + }, + "url-parse": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.2.0.tgz", + "integrity": "sha512-DT1XbYAfmQP65M/mE6OALxmXzZ/z1+e5zk2TcSKe/KiYbNGZxgtttzC0mR/sjopbpOXcbniq7eIKmocJnUWlEw==", + "dev": true, + "requires": { + "querystringify": "1.0.0", + "requires-port": "1.0.0" + }, + "dependencies": { + "querystringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz", + "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs=", + "dev": true + } + } + }, + "use": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", + "integrity": "sha1-riig1y+TvyJCKhii43mZMRLeyOg=", + "dev": true, + "requires": { + "define-property": "0.2.5", + "isobject": "3.0.1", + "lazy-cache": "2.0.2" + }, + "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.6" + } + }, + "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.2.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.6" + } + } + } + }, + "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.2.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.6" + } + } + } + }, + "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.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "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 + }, + "lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", + "dev": true, + "requires": { + "set-getter": "0.1.0" + } + } + } + }, + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "tmp": "0.0.33" + } + }, + "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" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true + }, + "uws": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/uws/-/uws-0.14.5.tgz", + "integrity": "sha1-Z6rzPEaypYel9mZtAPdpEyjxSdw=", + "dev": true, + "optional": true + }, + "v8flags": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.1.tgz", + "integrity": "sha1-3Oj8N5wX2fLJ6e142JzgAFKxt2s=", + "dev": true, + "requires": { + "homedir-polyfill": "1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", + "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=", + "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.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true + }, + "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" + } + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true + }, + "watchpack": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz", + "integrity": "sha1-ShRyvLuVK9Cpu0A2gB+VTfs5+qw=", + "dev": true, + "requires": { + "async": "2.6.0", + "chokidar": "1.7.0", + "graceful-fs": "4.1.11" + } + }, + "wbuf": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.2.tgz", + "integrity": "sha1-1pe5nx9ZUS3ydRvkJ2nBWAtYAf4=", + "dev": true, + "requires": { + "minimalistic-assert": "1.0.0" + } + }, + "web-animations-js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.1.tgz", + "integrity": "sha1-Om2bwVGWN3qQ+OKAP6UmIWWwRRA=" + }, + "webdriver-js-extender": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz", + "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=", + "dev": true, + "requires": { + "@types/selenium-webdriver": "2.53.43", + "selenium-webdriver": "2.53.3" + }, + "dependencies": { + "adm-zip": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz", + "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=", + "dev": true + }, + "sax": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz", + "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=", + "dev": true + }, + "selenium-webdriver": { + "version": "2.53.3", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz", + "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=", + "dev": true, + "requires": { + "adm-zip": "0.4.4", + "rimraf": "2.6.2", + "tmp": "0.0.24", + "ws": "1.1.5", + "xml2js": "0.4.4" + } + }, + "tmp": { + "version": "0.0.24", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz", + "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=", + "dev": true + }, + "ultron": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", + "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", + "dev": true + }, + "ws": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz", + "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==", + "dev": true, + "requires": { + "options": "0.0.6", + "ultron": "1.0.2" + } + }, + "xml2js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz", + "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=", + "dev": true, + "requires": { + "sax": "0.6.1", + "xmlbuilder": "9.0.7" + } + } + } + }, + "webpack": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz", + "integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==", + "dev": true, + "requires": { + "acorn": "5.4.1", + "acorn-dynamic-import": "2.0.2", + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "async": "2.6.0", + "enhanced-resolve": "3.4.1", + "escope": "3.6.0", + "interpret": "1.1.0", + "json-loader": "0.5.7", + "json5": "0.5.1", + "loader-runner": "2.3.0", + "loader-utils": "1.1.0", + "memory-fs": "0.4.1", + "mkdirp": "0.5.1", + "node-libs-browser": "2.1.0", + "source-map": "0.5.7", + "supports-color": "4.5.0", + "tapable": "0.2.8", + "uglifyjs-webpack-plugin": "0.4.6", + "watchpack": "1.4.0", + "webpack-sources": "1.1.0", + "yargs": "8.0.2" + }, + "dependencies": { + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.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" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglifyjs-webpack-plugin": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", + "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", + "dev": true, + "requires": { + "source-map": "0.5.7", + "uglify-js": "2.8.29", + "webpack-sources": "1.1.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 + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "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.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + }, + "dependencies": { + "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.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } + } + } + }, + "webpack-core": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz", + "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=", + "dev": true, + "requires": { + "source-list-map": "0.1.8", + "source-map": "0.4.4" + }, + "dependencies": { + "source-list-map": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", + "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=", + "dev": true + }, + "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": "1.0.1" + } + } + } + }, + "webpack-dev-middleware": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz", + "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==", + "dev": true, + "requires": { + "memory-fs": "0.4.1", + "mime": "1.6.0", + "path-is-absolute": "1.0.1", + "range-parser": "1.2.0", + "time-stamp": "2.0.0" + } + }, + "webpack-dev-server": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.11.1.tgz", + "integrity": "sha512-ombhu5KsO/85sVshIDTyQ5HF3xjZR3N0sf5Ao6h3vFwpNyzInEzA1GV3QPVjTMLTNckp8PjfG1PFGznzBwS5lg==", + "dev": true, + "requires": { + "ansi-html": "0.0.7", + "array-includes": "3.0.3", + "bonjour": "3.5.0", + "chokidar": "2.0.2", + "compression": "1.7.1", + "connect-history-api-fallback": "1.5.0", + "debug": "3.1.0", + "del": "3.0.0", + "express": "4.16.2", + "html-entities": "1.2.1", + "http-proxy-middleware": "0.17.4", + "import-local": "1.0.0", + "internal-ip": "1.2.0", + "ip": "1.1.5", + "killable": "1.0.0", + "loglevel": "1.6.1", + "opn": "5.1.0", + "portfinder": "1.0.13", + "selfsigned": "1.10.2", + "serve-index": "1.9.1", + "sockjs": "0.3.19", + "sockjs-client": "1.1.4", + "spdy": "3.4.7", + "strip-ansi": "3.0.1", + "supports-color": "5.2.0", + "webpack-dev-middleware": "1.12.2", + "yargs": "6.6.0" + }, + "dependencies": { + "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.5", + "normalize-path": "2.1.1" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.0.tgz", + "integrity": "sha512-P4O8UQRdGiMLWSizsApmXVQDBS6KCt7dSexgLKBmH5Hr1CZq7vsnscFh8oR1sP1ab1Zj0uCHCEzZeV6SfUf3rA==", + "dev": true, + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "define-property": "1.0.0", + "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.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.1" + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "chokidar": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.2.tgz", + "integrity": "sha512-l32Hw3wqB0L2kGVmSbK/a+xXLDrUEsc84pSgMkmwygHvD7ubRsP/vxxHa5BtB6oix1XLLVCHyYMsckRXxThmZw==", + "dev": true, + "requires": { + "anymatch": "2.0.0", + "async-each": "1.0.1", + "braces": "2.3.0", + "fsevents": "1.2.4", + "glob-parent": "3.1.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "4.0.0", + "normalize-path": "2.1.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0", + "upath": "1.0.2" + } + }, + "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" + } + }, + "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.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "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.6" + } + } + } + }, + "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" + } + }, + "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.1" + } + }, + "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.2" + }, + "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.1" + } + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "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.2.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.6" + } + } + } + }, + "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.2.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.6" + } + } + } + }, + "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.1.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-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.2.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.6" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "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 + }, + "micromatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.5.tgz", + "integrity": "sha512-ykttrLPQrz1PUJcXjwsTUjGoPJ64StIGNE2lGVD1c9CuguJ+L7/navsE8IcDNndOoCMvYV0qc/exfVbMHkUhvA==", + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.0", + "define-property": "1.0.0", + "extend-shallow": "2.0.1", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.7", + "object.pick": "1.3.0", + "regex-not": "1.0.0", + "snapdragon": "0.8.1", + "to-regex": "3.0.1" + } + }, + "supports-color": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", + "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "yargs": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", + "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "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": "4.2.1" + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "3.0.0" + } + } + } + }, + "webpack-merge": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.1.tgz", + "integrity": "sha512-geQsZ86YkXOVOjvPC5yv3JSNnL6/X3Kzh935AQ/gJNEYXEfJDQFu/sdFuktS9OW2JcH/SJec8TGfRdrpHshH7A==", + "dev": true, + "requires": { + "lodash": "4.17.5" + } + }, + "webpack-sources": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", + "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", + "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 + } + } + }, + "webpack-subresource-integrity": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.0.4.tgz", + "integrity": "sha1-j6yKfo61n8ahZ2ioXJ2U7n+dDts=", + "dev": true, + "requires": { + "webpack-core": "0.6.9" + } + }, + "websocket-driver": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", + "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", + "dev": true, + "requires": { + "http-parser-js": "0.4.10", + "websocket-extensions": "0.1.3" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "dev": true + }, + "when": { + "version": "3.6.4", + "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", + "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=", + "dev": true + }, + "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.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "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 + }, + "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" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true + }, + "worker-farm": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.5.2.tgz", + "integrity": "sha512-XxiQ9kZN5n6mmnW+mFJ+wXjNNI/Nx4DIdaAKLX1Bn6LYBWlN/zaBhu34DQYPZ1AJobQuu67S2OfDdNSVULvXkQ==", + "dev": true, + "requires": { + "errno": "0.1.7", + "xtend": "4.0.1" + } + }, + "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.2", + "strip-ansi": "3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.1" + } + }, + "xhr2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz", + "integrity": "sha1-f4dliEdxbbUCYyOBL4GMras4el8=" + }, + "xml-char-classes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", + "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=", + "dev": true + }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.7" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=" + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true, + "optional": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "xxhashjs": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.2.tgz", + "integrity": "sha512-AkTuIuVTET12tpsVIQo+ZU6f/qDmKuRUcjaqR+OIvm+aCBsZ95i7UVY5WJ9TMsSaZ0DA2WxoZ4acu0sPH+OKAw==", + "dev": true, + "requires": { + "cuint": "0.2.2" + } + }, + "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 + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "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" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "optional": true + } + } + }, + "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, + "optional": true, + "requires": { + "camelcase": "3.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, + "optional": true + } + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "dev": true + }, + "zone.js": { + "version": "0.8.20", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.20.tgz", + "integrity": "sha512-FXlA37ErSXCMy5RNBcGFgCI/Zivqzr0D19GuvDxhcYIJc7xkFp6c29DKyODJu0Zo+EMyur/WPPgcBh1EHjB9jA==" + } + } +} diff --git a/ui/package.json b/ui/package.json index dbe33230b7a..66212b71331 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,82 +1,82 @@ -{ - "name": "openems-ui", - "version": "2018.8.0", - "license": "AGPL", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build", - "build-edge": "ng build -prod --env=edge --base-href / --output-path=target/edge", - "build-backend": "ng build -prod --env=backend --base-href /m/ --output-path=target/backend", - "test": "ng test", - "lint": "ng lint", - "e2e": "ng e2e" - }, - "private": true, - "dependencies": { - "@angular/animations": "^5.2.0", - "@angular/cdk": "^5.2.0", - "@angular/common": "^5.2.0", - "@angular/compiler": "^5.2.0", - "@angular/core": "^5.2.0", - "@angular/flex-layout": "2.0.0-beta.12", - "@angular/forms": "^5.2.0", - "@angular/http": "^5.2.0", - "@angular/material": "^5.2.0", - "@angular/platform-browser": "^5.2.0", - "@angular/platform-browser-dynamic": "^5.2.0", - "@angular/platform-server": "^5.2.0", - "@angular/router": "^5.2.0", - "@ngx-translate/core": "^9.1.1", - "@types/d3": "4.12.0", - "angular2-toaster": "5.0.0-alpha.1", - "angular2-uuid": "^1.1.1", - "chart.js": "2.7.1", - "classlist.js": "^1.1.20150312", - "core-js": "^2.4.1", - "d3": "4.13.0", - "d3-array": "1.2.1", - "d3-brush": "1.0.4", - "d3-color": "1.0.3", - "d3-force": "1.1.0", - "d3-format": "1.2.2", - "d3-hierarchy": "1.1.5", - "d3-interpolate": "1.1.6", - "d3-scale": "2.0.0", - "d3-selection": "1.3.0", - "d3-shape": "1.2.0", - "date-fns": "^2.0.0-alpha.7", - "hammerjs": "2.0.8", - "intl": "^1.2.5", - "material-design-icons-iconfont": "3.0.3", - "mydaterangepicker": "^4.2.1", - "ng2-charts": "^1.6.0", - "ng2-cookies": "^1.0.12", - "ngx-loading": "^1.0.14", - "roboto-fontface": "0.8.0", - "rxjs": "^5.5.6", - "semver-compare-multi": "^1.0.3", - "web-animations-js": "^2.3.1", - "zone.js": "^0.8.19" - }, - "devDependencies": { - "@angular/cli": "1.6.7", - "@angular/compiler-cli": "^5.2.0", - "@angular/language-service": "^5.2.0", - "@types/jasmine": "~2.8.3", - "@types/jasminewd2": "~2.0.2", - "@types/node": "~6.0.60", - "codelyzer": "^4.0.1", - "jasmine-core": "~2.8.0", - "jasmine-spec-reporter": "~4.2.1", - "karma": "~2.0.0", - "karma-chrome-launcher": "~2.2.0", - "karma-coverage-istanbul-reporter": "^1.2.1", - "karma-jasmine": "~1.1.0", - "karma-jasmine-html-reporter": "^0.2.2", - "protractor": "~5.1.2", - "ts-node": "~4.1.0", - "tslint": "~5.9.1", - "typescript": "~2.5.3" - } -} +{ + "name": "openems-ui", + "version": "2018.9.0", + "license": "AGPL", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build", + "build-edge": "ng build -prod --env=edge --base-href / --output-path=target/edge", + "build-backend": "ng build -prod --env=backend --base-href /m/ --output-path=target/backend", + "test": "ng test", + "lint": "ng lint", + "e2e": "ng e2e" + }, + "private": true, + "dependencies": { + "@angular/animations": "^5.2.0", + "@angular/cdk": "^5.2.0", + "@angular/common": "^5.2.0", + "@angular/compiler": "^5.2.0", + "@angular/core": "^5.2.0", + "@angular/flex-layout": "2.0.0-beta.12", + "@angular/forms": "^5.2.0", + "@angular/http": "^5.2.0", + "@angular/material": "^5.2.0", + "@angular/platform-browser": "^5.2.0", + "@angular/platform-browser-dynamic": "^5.2.0", + "@angular/platform-server": "^5.2.0", + "@angular/router": "^5.2.0", + "@ngx-translate/core": "^9.1.1", + "@types/d3": "4.12.0", + "angular2-toaster": "5.0.0-alpha.1", + "angular2-uuid": "^1.1.1", + "chart.js": "2.7.1", + "classlist.js": "^1.1.20150312", + "core-js": "^2.4.1", + "d3": "4.13.0", + "d3-array": "1.2.1", + "d3-brush": "1.0.4", + "d3-color": "1.0.3", + "d3-force": "1.1.0", + "d3-format": "1.2.2", + "d3-hierarchy": "1.1.5", + "d3-interpolate": "1.1.6", + "d3-scale": "2.0.0", + "d3-selection": "1.3.0", + "d3-shape": "1.2.0", + "date-fns": "^2.0.0-alpha.7", + "hammerjs": "2.0.8", + "intl": "^1.2.5", + "material-design-icons-iconfont": "3.0.3", + "mydaterangepicker": "^4.2.1", + "ng2-charts": "^1.6.0", + "ng2-cookies": "^1.0.12", + "ngx-loading": "^1.0.14", + "roboto-fontface": "0.8.0", + "rxjs": "^5.5.6", + "semver-compare-multi": "^1.0.3", + "web-animations-js": "^2.3.1", + "zone.js": "^0.8.19" + }, + "devDependencies": { + "@angular/cli": "1.6.7", + "@angular/compiler-cli": "^5.2.0", + "@angular/language-service": "^5.2.0", + "@types/jasmine": "~2.8.3", + "@types/jasminewd2": "~2.0.2", + "@types/node": "~6.0.60", + "codelyzer": "^4.0.1", + "jasmine-core": "~2.8.0", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~2.0.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "^1.2.1", + "karma-jasmine": "~1.1.0", + "karma-jasmine-html-reporter": "^0.2.2", + "protractor": "~5.1.2", + "ts-node": "~4.1.0", + "tslint": "~5.9.1", + "typescript": "~2.5.3" + } +} diff --git a/ui/src/app/about/about.component.html b/ui/src/app/about/about.component.html index 33ca7e9d0c3..e2605086eb0 100644 --- a/ui/src/app/about/about.component.html +++ b/ui/src/app/about/about.component.html @@ -11,14 +11,14 @@ About.Fenecon
      • - About.Fems + About.Fems
      • - About.Sourcecode + About.OpenEMS
      • - - About.Build: 2018.8.0 (2018-06-12) + + About.Build: 2018.8.0 (2018-07-20)
      • + + + R{{rel}} +
        + + radio_button_checked + + + + R{{rel}} +
        + + radio_button_unchecked + + +
        + + + + + + \ No newline at end of file diff --git a/ui/src/app/edge/overview/channelthreshold/channelthreshold.component.ts b/ui/src/app/edge/overview/channelthreshold/channelthreshold.component.ts new file mode 100644 index 00000000000..19abced9477 --- /dev/null +++ b/ui/src/app/edge/overview/channelthreshold/channelthreshold.component.ts @@ -0,0 +1,47 @@ +import { Component, Input, OnDestroy, ViewChildren, QueryList } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + +import { Utils } from '../../../shared/service/utils'; +import { DefaultTypes } from '../../../shared/service/defaulttypes'; +import { CurrentDataAndSummary } from '../../../shared/edge/currentdata'; +import { Edge } from '../../../shared/edge/edge'; +import { ChannelComponent } from '../../../shared/config/channel.component'; + +@Component({ + selector: 'channelthreshold', + templateUrl: './channelthreshold.component.html' +}) +export class ChannelthresholdComponent { + + @Input() + public currentData: CurrentDataAndSummary; + + @Input() + public config: DefaultTypes.Config; + + @Input() + public edge: Edge; + + + + constructor(public utils: Utils) { } + + /*use an object inside an *ngFor loop*/ + + private keys(object: {}) { + return Object.keys(object); + } + + /** + * Receive messages from Channel + * + * @param message + * @param channelId + */ + private onChannelChange(message) { + if (message != null) { + this.edge.send(message); + } + } +} diff --git a/ui/src/app/edge/overview/energymonitor/chart/section/abstractsection.component.ts b/ui/src/app/edge/overview/energymonitor/chart/section/abstractsection.component.ts index dad42ead6ab..73d5058aafa 100644 --- a/ui/src/app/edge/overview/energymonitor/chart/section/abstractsection.component.ts +++ b/ui/src/app/edge/overview/energymonitor/chart/section/abstractsection.component.ts @@ -2,9 +2,6 @@ import { Component, Input, trigger, state, style, transition, animate } from '@a import { TranslateService } from '@ngx-translate/core'; import * as d3 from 'd3'; -import { EnergytableComponent } from '../../../energytable/energytable.component'; -import { Edge } from '../../../../../shared/edge/edge'; - export class SectionValue { absolute: number; ratio: number; diff --git a/ui/src/app/edge/overview/energytable/energytable.component.html b/ui/src/app/edge/overview/energytable.2018.7/energytable.2018.7.component.html similarity index 75% rename from ui/src/app/edge/overview/energytable/energytable.component.html rename to ui/src/app/edge/overview/energytable.2018.7/energytable.2018.7.component.html index cb4342315a2..5a51ec76ddd 100644 --- a/ui/src/app/edge/overview/energytable/energytable.component.html +++ b/ui/src/app/edge/overview/energytable.2018.7/energytable.2018.7.component.html @@ -32,7 +32,7 @@ - {{ sum.chargeActivePowerAC }} + {{ sum.chargeActivePowerAC | number:'1.0-0' }} W @@ -46,7 +46,7 @@ - {{ sum.dischargeActivePowerAC }} + {{ sum.dischargeActivePowerAC | number:'1.0-0' }} W @@ -62,19 +62,19 @@ AC L1 - {{ sum.chargeActivePowerACL1 }} + {{ sum.chargeActivePowerACL1 | number:'1.0-0' }} W L2 - {{ sum.chargeActivePowerACL2 }} + {{ sum.chargeActivePowerACL2 | number:'1.0-0' }} W L3 - {{ sum.chargeActivePowerACL3 }} + {{ sum.chargeActivePowerACL3 | number:'1.0-0' }} W @@ -82,19 +82,19 @@ AC L1 - {{ sum.dischargeActivePowerACL1 }} + {{ sum.dischargeActivePowerACL1 | number:'1.0-0' }} W L2 - {{ sum.dischargeActivePowerACL2 }} + {{ sum.dischargeActivePowerACL2 | number:'1.0-0' }} W L3 - {{ sum.dischargeActivePowerACL3 }} + {{ sum.dischargeActivePowerACL3 | number:'1.0-0' }} W @@ -103,16 +103,16 @@ Beladung DC - {{ sum.chargeActivePowerDC }} + {{ sum.chargeActivePowerDC | number:'1.0-0' }} W - + - + {{ config.things[thing].alias }} @@ -130,14 +130,14 @@ General.ChargePower - {{ data.ActivePower | sign }} + {{ data.ActivePower | sign | number:'1.0-0' }} 0 W General.DischargePower - {{ data.ActivePower }} + {{ data.ActivePower | number:'1.0-0' }} 0 W @@ -147,42 +147,42 @@ General.ChargePower L1 - {{ data.ActivePowerL1 | sign }} + {{ data.ActivePowerL1 | sign | number:'1.0-0' }} 0 W L2 - {{ data.ActivePowerL2 | sign }} + {{ data.ActivePowerL2 | sign | number:'1.0-0' }} 0 W L3 - {{ data.ActivePowerL3 | sign }} + {{ data.ActivePowerL3 | sign | number:'1.0-0' }} 0 W General.DischargePower L1 - {{ data.ActivePowerL1 }} + {{ data.ActivePowerL1 | number:'1.0-0' }} 0 W L2 - {{ data.ActivePowerL2 }} + {{ data.ActivePowerL2 | number:'1.0-0' }} 0 W L3 - {{ data.ActivePowerL3 }} + {{ data.ActivePowerL3 | number:'1.0-0' }} 0 W @@ -208,14 +208,14 @@ General.GridBuy - {{ data.ActivePower }} + {{ data.ActivePower | number:'1.0-0' }} 0 W General.GridSell - {{ data.ActivePower | sign }} + {{ data.ActivePower | sign | number:'1.0-0' }} 0 W @@ -225,42 +225,42 @@ General.GridBuy L1 - {{ data.ActivePowerL1 }} + {{ data.ActivePowerL1 | number:'1.0-0' }} 0 W L2 - {{ data.ActivePowerL2 }} + {{ data.ActivePowerL2 | number:'1.0-0' }} 0 W L3 - {{ data.ActivePowerL3 }} + {{ data.ActivePowerL3 | number:'1.0-0' }} 0 W General.GridSell L1 - {{ data.ActivePowerL1 | sign }} + {{ data.ActivePowerL1 | sign | number:'1.0-0' }} 0 W L2 - {{ data.ActivePowerL2 | sign }} + {{ data.ActivePowerL2 | sign | number:'1.0-0' }} 0 W L3 - {{ data.ActivePowerL3 | sign }} + {{ data.ActivePowerL3 | sign | number:'1.0-0' }} 0 W @@ -285,10 +285,12 @@ AC - {{ sum.activePowerAC }} + + {{ sum.activePowerAC | number:'1.0-0' }} W + - @@ -301,7 +303,7 @@ AC L1 - {{ sum.activePowerACL1 }} + {{ sum.activePowerACL1 | number:'1.0-0' }} W @@ -309,7 +311,7 @@ AC L2 - {{ sum.activePowerACL2 }} + {{ sum.activePowerACL2 | number:'1.0-0' }} W @@ -317,7 +319,7 @@ AC L3 - {{ sum.activePowerACL3 }} + {{ sum.activePowerACL3 | number:'1.0-0' }} W @@ -326,7 +328,7 @@ Erzeugung DC - {{ sum.activePowerDC }} + {{ sum.activePowerDC | number:'1.0-0' }} W @@ -346,7 +348,7 @@ General.Production - {{ data.ActualPower }} + {{ data.ActualPower | number:'1.0-0' }} W @@ -354,7 +356,7 @@ General.Production - {{ data.ActivePower }} + {{ data.ActivePower | number:'1.0-0' }} W @@ -362,19 +364,19 @@ General.Production L1 - {{ data.ActivePowerL1 }} + {{ data.ActivePowerL1 | number:'1.0-0' }} W L2 - {{ data.ActivePowerL2 }} + {{ data.ActivePowerL2 | number:'1.0-0' }} W L3 - {{ data.ActivePowerL3 }} + {{ data.ActivePowerL3 | number:'1.0-0' }} W @@ -397,7 +399,7 @@ General.Power - {{ data.activePower }} + {{ data.activePower | number:'1.0-0' }} W @@ -405,95 +407,5 @@ - - - - - - - {{ config.things[thing].alias }} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        General.Consumption{{ data.ActivePower }}W
        General.ConsumptionL1{{ data.ActivePowerL1 }}W
        L2{{ data.ActivePowerL2 }}W
        L3{{ data.ActivePowerL3 }}W
        -
        -
        -
        -
        - - - - - - - Andere - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        {{ config.things[thing].alias }}{{ data.ActivePower }}W
        {{ config.things[thing].alias }}L1{{ data.ActivePowerL1 }}W
        L2{{ data.ActivePowerL2 }}W
        L3{{ data.ActivePowerL3 }}W
        -
        -
        -
        \ No newline at end of file diff --git a/ui/src/app/edge/overview/energytable.2018.7/energytable.2018.7.component.ts b/ui/src/app/edge/overview/energytable.2018.7/energytable.2018.7.component.ts new file mode 100644 index 00000000000..8d42040643f --- /dev/null +++ b/ui/src/app/edge/overview/energytable.2018.7/energytable.2018.7.component.ts @@ -0,0 +1,23 @@ +import { Component, Input, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +import { Utils } from '../../../shared/service/utils'; +import { DefaultTypes } from '../../../shared/service/defaulttypes'; +import { CurrentDataAndSummary } from '../../../shared/edge/currentdata'; +import { Edge } from '../../../shared/edge/edge'; +import { CurrentDataAndSummary_2018_7 } from '../../../shared/edge/currentdata.2018.7'; + +@Component({ + selector: 'energytable-2018-7', + templateUrl: './energytable.2018.7.component.html' +}) +export class EnergytableComponent_2018_7 { + + @Input() + public currentData: CurrentDataAndSummary_2018_7; + + @Input() + public config: DefaultTypes.Config_2018_7; + + constructor(public utils: Utils) { } +} diff --git a/ui/src/app/edge/overview/energytable.2018.8/energytable.2018.8.component.html b/ui/src/app/edge/overview/energytable.2018.8/energytable.2018.8.component.html new file mode 100644 index 00000000000..13b6a98603e --- /dev/null +++ b/ui/src/app/edge/overview/energytable.2018.8/energytable.2018.8.component.html @@ -0,0 +1,208 @@ +
        + + + + + format_list_bulleted + Edge.Overview.Energytable.Title + + + + + + + + + + General.StorageSystem + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        General.Soc{{ sum.soc }}%
        + General.ChargePower DC{{ sum.chargeActivePowerDC | number:'1.0-0' }}W
        General.ChargePower + AC + {{ sum.chargeActivePowerAC | number:'1.0-0' }}W-
        General.DischargePower + AC + {{ sum.dischargeActivePowerAC | number:'1.0-0' }}W-
        General.ChargePower + AC + L1{{ sum.chargeActivePowerACL1 }}W
        L2{{ sum.chargeActivePowerACL2 }}W
        L3{{ sum.chargeActivePowerACL3 }}W
        General.DischargePower + AC + L1{{ sum.dischargeActivePowerACL1 }}W
        L2{{ sum.dischargeActivePowerACL2 }}W
        L3{{ sum.dischargeActivePowerACL3 }}W
        +
        +
        + + + + + + General.Grid + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        General.GridBuy{{ sum.buyActivePower | number:'1.0-0' }}W-
        General.GridSell{{ sum.sellActivePower | number:'1.0-0' }}W-
        +
        +
        + + + + + + General.Production + + + + + + + + + + + + + + + + + + + + + + + +
        + General.Production DC{{ sum.activePowerDC | number:'1.0-0' }}W
        General.Production + AC + {{ sum.activePowerAC | number:'1.0-0' }}W-
        +
        +
        + + + + + + General.Consumption + + + + + + + + + + + + + + +
        General.Power{{ sum.activePower | number:'1.0-0' }}W-
        +
        +
        +
        +
        \ No newline at end of file diff --git a/ui/src/app/edge/overview/energytable.2018.8/energytable.2018.8.component.ts b/ui/src/app/edge/overview/energytable.2018.8/energytable.2018.8.component.ts new file mode 100644 index 00000000000..a4522e1b74f --- /dev/null +++ b/ui/src/app/edge/overview/energytable.2018.8/energytable.2018.8.component.ts @@ -0,0 +1,23 @@ +import { Component, Input, OnDestroy } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +import { Utils } from '../../../shared/service/utils'; +import { DefaultTypes } from '../../../shared/service/defaulttypes'; +import { CurrentDataAndSummary } from '../../../shared/edge/currentdata'; +import { Edge } from '../../../shared/edge/edge'; +import { CurrentDataAndSummary_2018_8 } from '../../../shared/edge/currentdata.2018.8'; + +@Component({ + selector: 'energytable-2018-8', + templateUrl: './energytable.2018.8.component.html' +}) +export class EnergytableComponent_2018_8 { + + @Input() + public currentData: CurrentDataAndSummary_2018_8; + + @Input() + public config: DefaultTypes.Config_2018_8; + + constructor(public utils: Utils) { } +} diff --git a/ui/src/app/edge/overview/energytable/energytable.component.ts b/ui/src/app/edge/overview/energytable/energytable.component.ts deleted file mode 100644 index 4de96985f0f..00000000000 --- a/ui/src/app/edge/overview/energytable/energytable.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Component, Input, OnDestroy } from '@angular/core'; -import { Subject } from 'rxjs/Subject'; - -import { Utils } from '../../../shared/service/utils'; -import { DefaultTypes } from '../../../shared/service/defaulttypes'; -import { CurrentDataAndSummary } from '../../../shared/edge/currentdata'; - -@Component({ - selector: 'energytable', - templateUrl: './energytable.component.html' -}) -export class EnergytableComponent { - - @Input() - public currentData: CurrentDataAndSummary; - - @Input() - public config: DefaultTypes.Config; - - constructor(public utils: Utils) { } -} diff --git a/ui/src/app/edge/overview/history/history.component.html b/ui/src/app/edge/overview/history/history.component.html index eee193cf084..7009be3800e 100644 --- a/ui/src/app/edge/overview/history/history.component.html +++ b/ui/src/app/edge/overview/history/history.component.html @@ -5,7 +5,12 @@
        - + + + + + +
        diff --git a/ui/src/app/edge/overview/overview.component.html b/ui/src/app/edge/overview/overview.component.html index 56bf0a485d1..ed5f76a50bf 100644 --- a/ui/src/app/edge/overview/overview.component.html +++ b/ui/src/app/edge/overview/overview.component.html @@ -1,13 +1,22 @@
        - + + + + + +
        +
        +
        \ No newline at end of file diff --git a/ui/src/app/edge/overview/overview.module.ts b/ui/src/app/edge/overview/overview.module.ts index 691bb8f1df6..d7aa38f897e 100644 --- a/ui/src/app/edge/overview/overview.module.ts +++ b/ui/src/app/edge/overview/overview.module.ts @@ -2,12 +2,14 @@ import { NgModule } from '@angular/core'; import { SharedModule } from './../../shared/shared.module'; import { EnergymonitorModule } from './energymonitor/energymonitor.module'; -import { EnergytableComponent } from './energytable/energytable.component'; import { EvcsComponent } from './evcs/evcs.component'; import { HistoryComponent } from './history/history.component'; import { FieldstatusComponent } from './fieldstatus/fieldstatus.component'; import { OverviewComponent } from './overview.component'; import { StateComponent } from './state/state.component'; +import { ChannelthresholdComponent } from './channelthreshold/channelthreshold.component'; +import { EnergytableComponent_2018_7 } from './energytable.2018.7/energytable.2018.7.component'; +import { EnergytableComponent_2018_8 } from './energytable.2018.8/energytable.2018.8.component'; @NgModule({ imports: [ @@ -17,10 +19,12 @@ import { StateComponent } from './state/state.component'; declarations: [ OverviewComponent, EvcsComponent, - EnergytableComponent, + EnergytableComponent_2018_8, + EnergytableComponent_2018_7, HistoryComponent, FieldstatusComponent, - StateComponent + StateComponent, + ChannelthresholdComponent ] }) export class OverviewModule { } diff --git a/ui/src/app/edge/overview/state/state.component.ts b/ui/src/app/edge/overview/state/state.component.ts index 838bee47dc3..9a8f0b8c124 100644 --- a/ui/src/app/edge/overview/state/state.component.ts +++ b/ui/src/app/edge/overview/state/state.component.ts @@ -7,6 +7,7 @@ import { DefaultTypes } from '../../../shared/service/defaulttypes'; import { CurrentDataAndSummary } from '../../../shared/edge/currentdata'; import { THING_STATES } from './thingstates'; import { ConfigImpl } from '../../../shared/edge/config'; +import { ConfigImpl_2018_7 } from '../../../shared/edge/config.2018.7'; interface WarningOrFault { channelId: string, @@ -29,7 +30,7 @@ interface WarningsAndFaults { export class StateComponent { @Input() - public config: ConfigImpl; + public config: ConfigImpl_2018_7; @Input() set currentData(currentData: CurrentDataAndSummary) { @@ -109,7 +110,7 @@ export class StateComponent { if (faults.length > 0 || warnings.length > 0) { // get Thing name let name = null; - if (this.config.storageThings.includes(thingId)) { + if (this.config.esss.includes(thingId)) { name = "Speichersystem" } warningsAndFaultss.push({ diff --git a/ui/src/app/shared/config/abstractconfig.component.ts b/ui/src/app/shared/config/abstractconfig.component.ts index d64a2a08665..931912a4fb9 100644 --- a/ui/src/app/shared/config/abstractconfig.component.ts +++ b/ui/src/app/shared/config/abstractconfig.component.ts @@ -8,6 +8,7 @@ import { Edge } from '../edge/edge'; import { Websocket } from '../shared'; import { DefaultTypes } from '../service/defaulttypes'; import { ConfigImpl } from '../edge/config'; +import { ConfigImpl_2018_7 } from '../edge/config.2018.7'; @Component({ selector: 'abstractconfig', @@ -17,7 +18,7 @@ export class AbstractConfigComponent implements OnInit { public showSubThings: boolean = false; public edge: Edge = null; - public config: ConfigImpl = null; + public config: ConfigImpl_2018_7 = null; public things: string[] = []; private stopOnDestroy: Subject = new Subject(); @@ -36,8 +37,14 @@ export class AbstractConfigComponent implements OnInit { edge.config .filter(edge => edge != null) .takeUntil(this.stopOnDestroy).subscribe(config => { - this.config = config; - this.things = this.filterThings(config); + if (edge.isVersionAtLeast('2018.8')) { + console.error("AbstractConfigComponent is not compatible with version > 2018.8"); + this.config = null; + this.things = []; + } else { + this.config = config; + this.things = this.filterThings(config); + } }); }); } diff --git a/ui/src/app/shared/config/channel.component.ts b/ui/src/app/shared/config/channel.component.ts index 56df4f63b6a..c158b6825d5 100644 --- a/ui/src/app/shared/config/channel.component.ts +++ b/ui/src/app/shared/config/channel.component.ts @@ -9,6 +9,7 @@ import { Edge } from '../edge/edge'; import { DefaultTypes } from '../service/defaulttypes'; import { Role } from '../type/role'; import { EdgeModule } from '../../edge/edge.module'; +import { ConfigImpl_2018_7 } from '../edge/config.2018.7'; @Component({ selector: 'channel', @@ -29,7 +30,7 @@ export class ChannelComponent implements OnChanges, OnDestroy { @Input() public thingId: string = null; @Input() public channelId: string = null; - @Input() public config: ConfigImpl = null; + @Input() public config: ConfigImpl_2018_7 = null; @Input() public role: Role = "guest"; // TODO in edge @Input() public edge: Edge = null; @Input() public showThings: boolean = false; diff --git a/ui/src/app/shared/config/existingthing.component.ts b/ui/src/app/shared/config/existingthing.component.ts index ab80539433d..6bca63c9bc2 100644 --- a/ui/src/app/shared/config/existingthing.component.ts +++ b/ui/src/app/shared/config/existingthing.component.ts @@ -8,6 +8,7 @@ import { ConfigImpl } from '../edge/config'; import { Edge } from '../edge/edge'; import { DefaultTypes } from '../service/defaulttypes'; import { Role } from '../type/role'; +import { ConfigImpl_2018_7 } from '../edge/config.2018.7'; @Component({ selector: 'existingthing', @@ -19,7 +20,7 @@ export class ExistingThingComponent implements OnChanges { public thing = null; public meta = null; public role: Role = "guest"; - public config: ConfigImpl = null; + public config: ConfigImpl_2018_7 = null; public formPristine: boolean = true; public messages: { [channelId: string]: DefaultTypes.ConfigUpdate } = {}; @@ -34,7 +35,12 @@ export class ExistingThingComponent implements OnChanges { edge.config.takeUntil(this.stopOnDestroy) .filter(edge => edge != null) .takeUntil(this.stopOnDestroy).subscribe(config => { - this.config = config; + if (edge.isVersionAtLeast('2018.8')) { + console.error("ExistingThingComponent is not compatible with version > 2018.8"); + this.config = null; + } else { + this.config = config; + } }); } get edge(): Edge { diff --git a/ui/src/app/shared/edge/config.2018.7.ts b/ui/src/app/shared/edge/config.2018.7.ts new file mode 100644 index 00000000000..201431935d9 --- /dev/null +++ b/ui/src/app/shared/edge/config.2018.7.ts @@ -0,0 +1,311 @@ +import { DefaultTypes } from '../service/defaulttypes' +import { Role } from '../type/role' +import { Widget } from '../type/widget' +import { Edge } from './edge'; +import { ConfigImpl } from './config'; + +export class ConfigImpl_2018_7 extends ConfigImpl implements DefaultTypes.Config_2018_7 { + + public readonly things?: { + [id: string]: { + id: string, + alias: string, + class: string | string[], + [channel: string]: any + } + }; + + public readonly meta: { + [factoryPid: string]: { + implements: string[], + channels?: { + [channel: string]: { + name: string, + title: string, + type: string | string[], + optional: boolean, + array: boolean, + readRoles: Role[], + writeRoles: Role[], + defaultValue: string + } + } + } + }; + + // A list of thing ids which are matching Natures. (e.g. ["ess0", "ess1"]) + public readonly bridges: string[] = []; + public readonly gridMeters: string[] = []; + public readonly productionMeters: string[] = []; + public readonly consumptionMeters: string[] = []; + public readonly otherMeters: string[] = []; // TODO show otherMeters in Energymonitor + public readonly scheduler: string = null; + public readonly controllers: string[] = []; + public readonly persistences: string[] = []; + public readonly simulatorDevices: string[] = []; + public readonly evcsDevices: string[] = []; + public readonly thresholdDevices: string[] = []; + + constructor(private readonly edge: Edge, private readonly config: DefaultTypes.Config_2018_7) { + super(); + + let esss: string[] = [] + let chargers: string[] = []; + + // convert role-strings to Role-objects + for (let clazz in config.meta) { + for (let channel in config.meta[clazz].channels) { + let roles: Role[] = []; + for (let roleString of config.meta[clazz].channels[channel].readRoles) { + roles.push(Role.getRole("" + roleString /* convert to string */)); + } + config.meta[clazz].channels[channel].readRoles = roles; + } + } + + Object.assign(this, config); + + let gridMeters: string[] = []; + let productionMeters: string[] = []; + let consumptionMeters: string[] = []; + let otherMeters: string[] = []; + let bridges: string[] = []; + let scheduler: string = null; + let controllers: string[] = []; + let persistences: string[] = []; + let simulatorDevices: string[] = []; + let evcsDevices: string[] = []; + let thresholdDevices: string[] = []; + + for (let thingId in config.things) { + let thing = config.things[thingId]; + let i = this.getImplements(thing); + + /* + * Natures + */ + // Ess + if (i.includes("EssNature") + && !i.includes("EssClusterNature") /* ignore cluster */ + && !i.includes("AsymmetricSymmetricCombinationEssNature") /* ignore symmetric Ess of Pro 9-12 */) { + esss.push(thingId); + } + // Meter + if (i.includes("MeterNature") + && !i.includes("FeneconMiniConsumptionMeter") /* ignore Mini consumption meter */) { + if ("type" in thing) { + if (thing.type == 'grid') { + gridMeters.push(thingId); + } else if (thing.type === "production") { + productionMeters.push(thingId); + } else if (thing.type === "consumption") { + consumptionMeters.push(thingId); + } else { + otherMeters.push(thingId); + } + } + } + // Charger + if (i.includes("ChargerNature")) { + productionMeters.push(thingId); + chargers.push(thingId); + } + /* + * Other Things + */ + // Bridge + if (i.includes("io.openems.api.bridge.Bridge")) { + bridges.push(thingId); + } + // Scheduler + if (i.includes("io.openems.api.scheduler.Scheduler")) { + scheduler = thingId; + } + // Controller + if (i.includes("io.openems.api.controller.Controller")) { + controllers.push(thingId); + } + // Persistence + if (i.includes("io.openems.api.persistence.Persistence")) { + persistences.push(thingId); + } + // Simulator Devices + if (i.includes("io.openems.impl.device.simulator.Simulator")) { + simulatorDevices.push(thingId); + } + // Simulator Devices + if (i.includes("KebaDeviceNature")) { + evcsDevices.push(thingId); + } + + // Channelthreshold + if (thing.class == "io.openems.impl.controller.channelthreshold.ChannelThresholdController") { + thresholdDevices.push(thingId); + } + } + + this.gridMeters = gridMeters.sort(); + this.productionMeters = productionMeters.sort(); + this.consumptionMeters = consumptionMeters.sort(); + this.otherMeters = otherMeters.sort(); + this.bridges = bridges.sort(); + this.scheduler = scheduler; + this.controllers = controllers; + this.persistences = persistences; + this.simulatorDevices = simulatorDevices; + this.evcsDevices = evcsDevices; + this.esss = esss.sort(); + this.chargers = chargers.sort(); + this.thresholdDevices = thresholdDevices; + } + + public getStateChannels(): DefaultTypes.ChannelAddresses { + let result: DefaultTypes.ChannelAddresses = {} + + // Set "ignoreNatures" + for (let thingId in this.config.things) { + result[thingId] = ["State"]; + } + return result; + } + + + /** + * Return ChannelAddresses of power channels + */ + public getPowerChannels(): DefaultTypes.ChannelAddresses { + let result: DefaultTypes.ChannelAddresses = {} + + let ignoreNatures = { EssClusterNature: true }; + + // Set "ignoreNatures" + for (let thingId of this.esss) { + let i = this.getImplements(this.config.things[thingId]); + + if (i.includes("FeneconCommercialEss")) { // workaround to ignore asymmetric meter for commercial + ignoreNatures["AsymmetricMeterNature"] = true; + } + } + // Parse all things + for (let thingId in this.config.things) { + let clazz = this.config.things[thingId].class; // TODO casting + let i = this.getImplements(this.config.things[thingId]); + let channels = []; + // ESS + if (i.includes("EssNature") + && !i.includes("EssClusterNature") /* ignore cluster */ + && !i.includes("AsymmetricSymmetricCombinationEssNature") /* ignore symmetric Ess of Pro 9-12 */) { + if (i.includes("FeneconMiniEss")) { + channels.push("ActivePowerL1"); + } else if (i.includes("AsymmetricEssNature")) { + channels.push("ActivePowerL1", "ActivePowerL2", "ActivePowerL3"); + } else if (i.includes("SymmetricEssNature")) { + channels.push("ActivePower"); + } + } + // Meter + if (i.includes("MeterNature") + && !i.includes("FeneconMiniConsumptionMeter") /* ignore Mini consumption meter */) { + if (i.includes("AsymmetricMeterNature") && !ignoreNatures["AsymmetricMeterNature"]) { + channels.push("ActivePowerL1", "ActivePowerL2", "ActivePowerL3"); + } else if (i.includes("SymmetricMeterNature")) { + channels.push("ActivePower"); + } + } + // Charger + if (i.includes("ChargerNature")) { + channels.push("ActualPower"); + } + // store result + if (channels.length > 0) { + result[thingId] = channels; + } + } + return result; + } + + /** + * Returns ChannelAddresses of ESS Soc channels + */ + public getEssSocChannels(): DefaultTypes.ChannelAddresses { + let result: DefaultTypes.ChannelAddresses = {} + for (let thingId of this.esss) { + let channels = []; + // ESS + channels.push("Soc"); + // store result + if (channels.length > 0) { + result[thingId] = channels; + } + } + return result; + } + + /** + * Returns ChannelAddresses required by EVCS widget + */ + private getEvcsWidgetChannels(): DefaultTypes.ChannelAddresses { + let result: DefaultTypes.ChannelAddresses = {} + for (let thingId of this.evcsDevices) { + result[thingId] = ["State", "Plug", "CurrUser", "ActualPower", "EnergySession", "EnergyTotal"]; + } + return result; + } + + public getThresholdWidgetChannels(): DefaultTypes.ChannelAddresses { + let result: DefaultTypes.ChannelAddresses = {} + for (let thingId of this.thresholdDevices) { + let address = this.config.things[thingId]['outputChannelAddress'].split("/"); + if (!(address[0] in result)) { + result[address[0]] = [] + }; + result[address[0]].push(address[1]); + } + return result; + } + + /** + * Return ChannelAddresses of power and soc channels + */ + public getImportantChannels(): DefaultTypes.ChannelAddresses { + let channels: DefaultTypes.ChannelAddresses = {}; + function merge(obj: DefaultTypes.ChannelAddresses) { + for (let thing in obj) { + if (thing in channels) { + channels[thing] = channels[thing].concat(obj[thing]); + } else { + channels[thing] = obj[thing]; + } + } + } + // basic channels + merge(this.getStateChannels()); + merge(this.getPowerChannels()); + merge(this.getEssSocChannels()); + // widget channels + merge(this.getEvcsWidgetChannels()); + merge(this.getThresholdWidgetChannels()); + return channels; + } + + public getWidgets(): Widget[] { + let widgets: Widget[] = []; + if (this.evcsDevices.length > 0) { + widgets.push("EVCS"); + } + if (this.thresholdDevices.length > 0) { + widgets.push("CHANNELTHRESHOLD"); + } + return widgets; + } + + private getImplements(thing: DefaultTypes.ThingConfig): string | string[] { + if (thing.class in this.meta) { // TODO casting + // get implements from meta + return this.meta[thing.class].implements; + } else { + // use class + return thing.class; + } + } +} \ No newline at end of file diff --git a/ui/src/app/shared/edge/config.2018.8.ts b/ui/src/app/shared/edge/config.2018.8.ts new file mode 100644 index 00000000000..5905d5968da --- /dev/null +++ b/ui/src/app/shared/edge/config.2018.8.ts @@ -0,0 +1,151 @@ +import { DefaultTypes } from '../service/defaulttypes' +import { Role } from '../type/role' +import { Widget } from '../type/widget' +import { Edge } from './edge'; +import { ConfigImpl } from './config'; + +export class ConfigImpl_2018_8 extends ConfigImpl implements DefaultTypes.Config_2018_8 { + + public readonly components: { + [id: string]: { + 'service.pid': string, // unique pid of configuration + 'service.factoryPid': string, // link to 'meta' + enabled: boolean, + [channel: string]: string | number | boolean + } + } + + public readonly meta: { + [factoryPid: string]: { + implements: string[], + channels?: { + [channel: string]: { + name: string, + title: string, + type: string | string[], + optional: boolean, + array: boolean, + readRoles: Role[], + writeRoles: Role[], + defaultValue: string + } + } + } + }; + + // A list of thing ids which are matching Natures. (e.g. ["ess0", "ess1"]) + public readonly gridMeters: string[] = []; + public readonly productionMeters: string[] = []; + public readonly consumptionMeters: string[] = []; + public readonly otherMeters: string[] = []; // TODO show otherMeters in Energymonitor + public readonly bridges: string[] = []; + public readonly scheduler: string = null; + public readonly controllers: string[] = []; + public readonly persistences: string[] = []; + public readonly simulatorDevices: string[] = []; + public readonly evcsDevices: string[] = []; + + constructor(private readonly edge: Edge, private readonly config: DefaultTypes.Config_2018_8) { + super(); + + let esss: string[] = [] + let chargers: string[] = []; + + Object.assign(this, config); + + for (let componentId in config.components) { + const i = this.getImplements(componentId); + + // Ess + if (i.includes("Ess")) { + esss.push(componentId); + } + if (i.includes("EssDcCharger")) { + chargers.push(componentId); + } + } + this.esss = esss.sort(); + this.chargers = chargers.sort(); + } + + public getStateChannels(): DefaultTypes.ChannelAddresses { + let result: DefaultTypes.ChannelAddresses = {} + + // Set "ignoreNatures" + // TODO + // for (let thingId in this.config.things) { + // result[thingId] = ["State"]; + // } + return result; + } + + /** + * Return ChannelAddresses of power channels + */ + public getPowerChannels(): DefaultTypes.ChannelAddresses { + return { + "_sum": [ + 'EssActivePower', 'GridActivePower', 'ProductionActivePower', 'ConsumptionActivePower' + ] + } + } + + /** + * Returns ChannelAddresses of ESS Soc channels + */ + public getEssSocChannels(): DefaultTypes.ChannelAddresses { + return { + "_sum": [ + 'EssSoc' + ] + } + } + + /** + * Returns ChannelAddresses required by EVCS widget + */ + private getEvcsWidgetChannels(): DefaultTypes.ChannelAddresses { + let result: DefaultTypes.ChannelAddresses = {} + for (let thingId of this.evcsDevices) { + result[thingId] = ["State", "Plug", "CurrUser", "ActualPower", "EnergySession", "EnergyTotal"]; + } + return result; + } + + /** + * Return ChannelAddresses of power and soc channels + */ + public getImportantChannels(): DefaultTypes.ChannelAddresses { + return { + '_sum': [ + // Ess + 'EssSoc', 'EssActivePower', 'EssChargeActivePower', 'EssDischargeActivePower', + // Grid + 'GridActivePower', 'GridMinActivePower', 'GridMaxActivePower', + // Production + 'ProductionActivePower', 'ProductionDcActualPower', 'ProductionAcActivePower', 'ProductionMaxActivePower', + // Consumption + 'ConsumptionActivePower', 'ConsumptionMaxActivePower' + ] + } + } + + public getWidgets(): Widget[] { + let widgets: Widget[] = []; + if (this.evcsDevices.length > 0) { + widgets.push("EVCS"); + } + return widgets; + } + + private getImplements(componentId: string): string[] { + let component = this.config.components[componentId]; + let i; + if (component["service.factoryPid"] in this.meta) { + i = this.meta[component["service.factoryPid"]].implements; + } else { + i = []; + } + return i; + } +} \ No newline at end of file diff --git a/ui/src/app/shared/edge/config.ts b/ui/src/app/shared/edge/config.ts index d0a9cbb7fbd..7b522c106d4 100644 --- a/ui/src/app/shared/edge/config.ts +++ b/ui/src/app/shared/edge/config.ts @@ -1,31 +1,13 @@ import { DefaultTypes } from '../service/defaulttypes' import { Role } from '../type/role' -import { Widget } from '../type/widget' -import { Edge } from './edge'; +import { Widget } from '../type/widget'; -export class ConfigImpl implements DefaultTypes.Config { +export abstract class ConfigImpl implements DefaultTypes.Config { - // FROM VERSION 2018.8 - public readonly components?: { - [id: string]: { - 'service.pid': string, // unique pid of configuration - 'service.factoryPid': string, // link to 'meta' - enabled: boolean, - [channel: string]: string | number | boolean - } - } + public esss: string[] = []; + public chargers: string[] = []; - // BEVORE VERSION 2018.8 - public readonly things?: { - [id: string]: { - id: string, - alias: string, - class: string | string[], - [channel: string]: any - } - }; - - public readonly meta: { + public meta: { [factoryPid: string]: { implements: string[], channels?: { @@ -43,348 +25,12 @@ export class ConfigImpl implements DefaultTypes.Config { } }; - // A list of thing ids which are matching Natures. (e.g. ["ess0", "ess1"]) - public readonly storageThings: string[] = []; - public readonly chargers: string[] = []; - public readonly gridMeters: string[] = []; - public readonly productionMeters: string[] = []; - public readonly consumptionMeters: string[] = []; - public readonly otherMeters: string[] = []; // TODO show otherMeters in Energymonitor - public readonly bridges: string[] = []; - public readonly scheduler: string = null; - public readonly controllers: string[] = []; - public readonly persistences: string[] = []; - public readonly simulatorDevices: string[] = []; - public readonly evcsDevices: string[] = []; - - constructor(private readonly edge: Edge, private readonly config: DefaultTypes.Config) { - let storageThings: string[] = [] - let chargers: string[] = []; - - if (edge.isVersionAtLeast("2018.8")) { - /* - * FROM VERSION 2018.8 - */ - Object.assign(this, config); - - for (let componentId in config.components) { - const i = this.getImplements2(componentId); - - // Ess - if (i.includes("Ess")) { - storageThings.push(componentId); - } - if (i.includes("EssDcCharger")) { - chargers.push(componentId); - } - } - - } else { - /* - * VERSION BEFORE 2018.8 - */ - - // convert role-strings to Role-objects - for (let clazz in config.meta) { - for (let channel in config.meta[clazz].channels) { - let roles: Role[] = []; - for (let roleString of config.meta[clazz].channels[channel].readRoles) { - roles.push(Role.getRole("" + roleString /* convert to string */)); - } - config.meta[clazz].channels[channel].readRoles = roles; - } - } - - Object.assign(this, config); - - let gridMeters: string[] = []; - let productionMeters: string[] = []; - let consumptionMeters: string[] = []; - let otherMeters: string[] = []; - let bridges: string[] = []; - let scheduler: string = null; - let controllers: string[] = []; - let persistences: string[] = []; - let simulatorDevices: string[] = []; - let evcsDevices: string[] = []; - - for (let thingId in config.things) { - let thing = config.things[thingId]; - let i = this.getImplements(thing); - - /* - * Natures - */ - // Ess - if (i.includes("EssNature") - && !i.includes("EssClusterNature") /* ignore cluster */ - && !i.includes("AsymmetricSymmetricCombinationEssNature") /* ignore symmetric Ess of Pro 9-12 */) { - storageThings.push(thingId); - } - // Meter - if (i.includes("MeterNature")) { - if ("type" in thing) { - if (thing.type == 'grid') { - gridMeters.push(thingId); - } else if (thing.type === "production") { - productionMeters.push(thingId); - } else if (thing.type === "consumption") { - consumptionMeters.push(thingId); - } else { - otherMeters.push(thingId); - } - } - } - // Charger - if (i.includes("ChargerNature")) { - productionMeters.push(thingId); - chargers.push(thingId); - } - /* - * Other Things - */ - // Bridge - if (i.includes("io.openems.api.bridge.Bridge")) { - bridges.push(thingId); - } - // Scheduler - if (i.includes("io.openems.api.scheduler.Scheduler")) { - scheduler = thingId; - } - // Controller - if (i.includes("io.openems.api.controller.Controller")) { - controllers.push(thingId); - } - // Persistence - if (i.includes("io.openems.api.persistence.Persistence")) { - persistences.push(thingId); - } - // Simulator Devices - if (i.includes("io.openems.impl.device.simulator.Simulator")) { - simulatorDevices.push(thingId); - } - // Simulator Devices - if (i.includes("KebaDeviceNature")) { - evcsDevices.push(thingId); - } - } - - this.gridMeters = gridMeters.sort(); - this.productionMeters = productionMeters.sort(); - this.consumptionMeters = consumptionMeters.sort(); - this.otherMeters = otherMeters.sort(); - this.bridges = bridges.sort(); - this.scheduler = scheduler; - this.controllers = controllers; - this.persistences = persistences; - this.simulatorDevices = simulatorDevices; - this.evcsDevices = evcsDevices; - } - - this.storageThings = storageThings.sort(); - this.chargers = chargers.sort(); - } - - public getStateChannels(): DefaultTypes.ChannelAddresses { - let result: DefaultTypes.ChannelAddresses = {} - - // Set "ignoreNatures" - for (let thingId in this.config.things) { - result[thingId] = ["State"]; - } - return result; - } - - - /** - * Return ChannelAddresses of power channels - */ - public getPowerChannels(): DefaultTypes.ChannelAddresses { - let result: DefaultTypes.ChannelAddresses = {} - - if (this.edge.isVersionAtLeast("2018.8")) { - /* - * FROM VERSION 2018.8 - */ - return { - "_sum": [ - 'EssActivePower', 'GridActivePower', 'ProductionActivePower', 'ConsumptionActivePower' - ] - } - - // for (let componentId of this.storageThings) { - // const i = this.getImplements2(componentId); - // let channels = []; - - // // Ess - // if (i.includes("SymmetricEss")) { - // channels.push("ActivePower"); - // } - - // // store result - // if (channels.length > 0) { - // result[componentId] = channels; - // } - // } - - } else { - /* - * VERSION BEFORE 2018.8 - */ - let ignoreNatures = { EssClusterNature: true }; - - // Set "ignoreNatures" - for (let thingId of this.storageThings) { - let i = this.getImplements(this.config.things[thingId]); - - if (i.includes("FeneconCommercialEss")) { // workaround to ignore asymmetric meter for commercial - ignoreNatures["AsymmetricMeterNature"] = true; - } - } - // Parse all things - for (let thingId in this.config.things) { - let clazz = this.config.things[thingId].class; // TODO casting - let i = this.getImplements(this.config.things[thingId]); - let channels = []; - // ESS - if (i.includes("EssNature") - && !i.includes("EssClusterNature") /* ignore cluster */ - && !i.includes("AsymmetricSymmetricCombinationEssNature") /* ignore symmetric Ess of Pro 9-12 */) { - if (i.includes("FeneconMiniEss")) { - channels.push("ActivePowerL1"); - } else if (i.includes("AsymmetricEssNature")) { - channels.push("ActivePowerL1", "ActivePowerL2", "ActivePowerL3"); - } else if (i.includes("SymmetricEssNature")) { - channels.push("ActivePower"); - } - } - // Meter - if (i.includes("MeterNature")) { - if (i.includes("AsymmetricMeterNature") && !ignoreNatures["AsymmetricMeterNature"]) { - channels.push("ActivePowerL1", "ActivePowerL2", "ActivePowerL3"); - } else if (i.includes("SymmetricMeterNature")) { - channels.push("ActivePower"); - } - } - // Charger - if (i.includes("ChargerNature")) { - channels.push("ActualPower"); - } - // store result - if (channels.length > 0) { - result[thingId] = channels; - } - } - } - return result; - } + public abstract getImportantChannels(): DefaultTypes.ChannelAddresses; - /** - * Returns ChannelAddresses of ESS Soc channels - */ - public getEssSocChannels(): DefaultTypes.ChannelAddresses { - if (this.edge.isVersionAtLeast("2018.8")) { - /* - * FROM VERSION 2018.8 - */ - return { - "_sum": [ - 'EssSoc' - ] - } - } else { - /* - * VERSION BEFORE 2018.8 - */ - let result: DefaultTypes.ChannelAddresses = {} - for (let thingId of this.storageThings) { - let channels = []; - // ESS - channels.push("Soc"); - // store result - if (channels.length > 0) { - result[thingId] = channels; - } - } - return result; - } - } + public abstract getEssSocChannels(): DefaultTypes.ChannelAddresses; - /** - * Returns ChannelAddresses required by EVCS widget - */ - private getEvcsWidgetChannels(): DefaultTypes.ChannelAddresses { - let result: DefaultTypes.ChannelAddresses = {} - for (let thingId of this.evcsDevices) { - result[thingId] = ["State", "Plug", "CurrUser", "ActualPower", "EnergySession", "EnergyTotal"]; - } - return result; - } + public abstract getPowerChannels(): DefaultTypes.ChannelAddresses; - /** - * Return ChannelAddresses of power and soc channels - */ - public getImportantChannels(): DefaultTypes.ChannelAddresses { - let channels: DefaultTypes.ChannelAddresses = {}; - function merge(obj: DefaultTypes.ChannelAddresses) { - for (let thing in obj) { - if (thing in channels) { - channels[thing] = channels[thing].concat(obj[thing]); - } else { - channels[thing] = obj[thing]; - } - } - } - if (this.edge.isVersionAtLeast("2018.8")) { - return { - '_sum': [ - // Ess - 'EssSoc', 'EssActivePower', 'EssChargeActivePower', 'EssDischargeActivePower', - // Grid - 'GridActivePower', 'GridMinActivePower', 'GridMaxActivePower', - // Production - 'ProductionActivePower', 'ProductionMaxActivePower', - // Consumption - 'ConsumptionActivePower', 'ConsumptionMaxActivePower' - ] - } - } else { - // basic channels - merge(this.getStateChannels()); - merge(this.getPowerChannels()); - merge(this.getEssSocChannels()); - // widget channels - merge(this.getEvcsWidgetChannels()); - } - return channels; - } - - public getWidgets(): Widget[] { - let widgets: Widget[] = []; - if (this.evcsDevices.length > 0) { - widgets.push("EVCS"); - } - return widgets; - } - - private getImplements2(componentId: string): string[] { - let component = this.config.components[componentId]; - let i; - if (component["service.factoryPid"] in this.meta) { - i = this.meta[component["service.factoryPid"]].implements; - } else { - i = []; - } - return i; - } + public abstract getWidgets(): Widget[]; - private getImplements(thing: DefaultTypes.ThingConfig): string | string[] { - if (thing.class in this.meta) { // TODO casting - // get implements from meta - return this.meta[thing.class].implements; - } else { - // use class - return thing.class; - } - } } \ No newline at end of file diff --git a/ui/src/app/shared/edge/currentdata.2018.7.ts b/ui/src/app/shared/edge/currentdata.2018.7.ts new file mode 100644 index 00000000000..c5a59e6867e --- /dev/null +++ b/ui/src/app/shared/edge/currentdata.2018.7.ts @@ -0,0 +1,315 @@ +import { DefaultTypes } from '../service/defaulttypes'; +import { ConfigImpl } from './config'; +import { Utils } from '../service/utils'; +import { Edge } from './edge'; +import { CurrentDataAndSummary } from './currentdata'; +import { ConfigImpl_2018_7 } from './config.2018.7'; + +export class CurrentDataAndSummary_2018_7 extends CurrentDataAndSummary { + + constructor(private edge: Edge, data: DefaultTypes.Data, config: ConfigImpl_2018_7) { + super(data); + this.summary = this.calculateSummary(data, config); + } + + private calculateSummary(currentData: DefaultTypes.Data, config: ConfigImpl_2018_7): DefaultTypes.Summary { + let result: DefaultTypes.Summary = { + storage: { + soc: null, + isAsymmetric: false, + hasDC: false, + chargeActivePower: null, // sum of chargeActivePowerAC and chargeActivePowerDC + chargeActivePowerAC: null, + chargeActivePowerACL1: null, + chargeActivePowerACL2: null, + chargeActivePowerACL3: null, + chargeActivePowerDC: null, + maxChargeActivePower: null, + dischargeActivePower: null, // sum of dischargeActivePowerAC and dischargeActivePowerDC + dischargeActivePowerAC: null, + dischargeActivePowerACL1: null, + dischargeActivePowerACL2: null, + dischargeActivePowerACL3: null, + dischargeActivePowerDC: null, + maxDischargeActivePower: null + }, production: { + isAsymmetric: false, + hasDC: false, + powerRatio: null, + activePower: null, // sum of activePowerAC and activePowerDC + activePowerAC: null, + activePowerACL1: null, + activePowerACL2: null, + activePowerACL3: null, + activePowerDC: null, + maxActivePower: null + }, grid: { + powerRatio: null, + buyActivePower: null, + maxBuyActivePower: null, + sellActivePower: null, + maxSellActivePower: null + }, consumption: { + powerRatio: null, + activePower: null + } + }; + + { + /* + * Storage + * > 0 => Discharge + * < 0 => Charge + */ + let soc = null; + let isAsymmetric = false; + let activePowerAC = null; + let activePowerACL1 = null; + let activePowerACL2 = null; + let activePowerACL3 = null; + let activePowerDC = null; + let countSoc = 0; + for (let thing of config.esss) { + if (thing in currentData) { + let essData = currentData[thing]; + if ("Soc" in essData) { + soc = Utils.addSafely(soc, essData.Soc); + countSoc += 1; + } + let thisActivePowerAC = this.getActivePower(essData); + let thisActivePowerACL = Utils.divideSafely(thisActivePowerAC, 3); + activePowerAC = Utils.addSafely(activePowerAC, thisActivePowerAC); + if ("ActivePowerL1" in essData) { + isAsymmetric = true; + activePowerACL1 = Utils.addSafely(activePowerACL1, essData.ActivePowerL1); + } else { + activePowerACL1 = Utils.addSafely(activePowerACL1, thisActivePowerACL); + } + if ("ActivePowerL2" in essData) { + isAsymmetric = true; + activePowerACL2 = Utils.addSafely(activePowerACL2, essData.ActivePowerL2); + } else { + activePowerACL2 = Utils.addSafely(activePowerACL2, thisActivePowerACL); + } + if ("ActivePowerL3" in essData) { + isAsymmetric = true; + activePowerACL3 = Utils.addSafely(activePowerACL3, essData.ActivePowerL3); + } else { + activePowerACL3 = Utils.addSafely(activePowerACL3, thisActivePowerACL); + } + } + } + for (let thing of config.chargers) { + if (thing in currentData) { + let essData = currentData[thing]; + activePowerDC = Utils.subtractSafely(activePowerDC, essData.ActualPower); + } + } + result.storage.soc = Utils.divideSafely(soc, countSoc); + result.storage.isAsymmetric = isAsymmetric; + result.storage.hasDC = config.chargers.length > 0; + if (result.storage.soc > 100 || result.storage.soc < 0) { + result.storage.soc = null; + } + if (isAsymmetric) { + activePowerAC = Utils.addSafely(Utils.addSafely(activePowerACL1, activePowerACL2), activePowerACL3) + } + if (activePowerAC != null) { + if (activePowerAC > 0) { + result.storage.chargeActivePowerAC = 0; + result.storage.dischargeActivePowerAC = activePowerAC; + } else { + result.storage.chargeActivePowerAC = activePowerAC * -1; + result.storage.dischargeActivePowerAC = 0; + } + } + if (activePowerACL1 != null) { + if (activePowerACL1 > 0) { + result.storage.chargeActivePowerACL1 = 0; + result.storage.dischargeActivePowerACL1 = activePowerACL1; + } else { + result.storage.chargeActivePowerACL1 = activePowerACL1 * -1; + result.storage.dischargeActivePowerACL1 = 0; + } + } + if (activePowerACL2 != null) { + if (activePowerACL2 > 0) { + result.storage.chargeActivePowerACL2 = 0; + result.storage.dischargeActivePowerACL2 = activePowerACL2; + } else { + result.storage.chargeActivePowerACL2 = activePowerACL2 * -1; + result.storage.dischargeActivePowerACL2 = 0; + } + } + if (activePowerACL3 != null) { + if (activePowerACL3 > 0) { + result.storage.chargeActivePowerACL3 = 0; + result.storage.dischargeActivePowerACL3 = activePowerACL3; + } else { + result.storage.chargeActivePowerACL3 = activePowerACL3 * -1; + result.storage.dischargeActivePowerACL3 = 0; + } + } + if (activePowerDC != null) { + if (activePowerDC > 0) { + result.storage.chargeActivePowerDC = activePowerDC; + result.storage.dischargeActivePowerDC = 0; + } else { + result.storage.chargeActivePowerDC = 0; + result.storage.dischargeActivePowerDC = activePowerDC * -1; + } + } + let activePower = Utils.subtractSafely( + Utils.addSafely(result.storage.chargeActivePowerAC, result.storage.chargeActivePowerDC), + Utils.addSafely(result.storage.dischargeActivePowerAC, result.storage.dischargeActivePowerDC)); + if (activePower != null) { + if (activePower > 0) { + result.storage.chargeActivePower = activePower; + result.storage.dischargeActivePower = 0; + } else { + result.storage.chargeActivePower = 0; + result.storage.dischargeActivePower = activePower * -1; + } + } + } + + { + /* + * Grid + * > 0 => Buy from grid + * < 0 => Sell to grid + */ + let activePower = null; + let ratio = 0; + let maxSell = 0; + let maxBuy = 0; + for (let thing of config.gridMeters) { + let meterData = currentData[thing]; + let meterConfig = config.things[thing]; + activePower = Utils.addSafely(activePower, this.getActivePower(meterData)); + if ("maxActivePower" in meterConfig) { + maxBuy += meterConfig.maxActivePower; + } + if ("minActivePower" in meterConfig) { + maxSell += meterConfig.minActivePower; + } + } + // set GridBuy and GridSell + result.grid.maxSellActivePower = maxSell * -1; + result.grid.maxBuyActivePower = maxBuy; + if (activePower != null) { + if (activePower > 0) { + result.grid.sellActivePower = 0; + result.grid.buyActivePower = activePower; + ratio = result.grid.buyActivePower / maxSell * 100; + } else { + result.grid.sellActivePower = activePower * -1; + result.grid.buyActivePower = 0; + ratio = result.grid.sellActivePower / maxSell * -100; + } + } + result.grid.powerRatio = ratio; + } + + { + /* + * Production + */ + let powerRatio = 0; + let isAsymmetric = false; + let activePowerAC = null; + let activePowerACL1 = null; + let activePowerACL2 = null; + let activePowerACL3 = null; + let activePowerDC = null; + let maxActivePower = 0; + for (let thing of config.productionMeters) { + let meterData = currentData[thing]; + let meterConfig = config.things[thing]; + let thisActivePowerAC = this.getActivePower(meterData); + let thisActivePowerACL = Utils.divideSafely(thisActivePowerAC, 3); + activePowerAC = Utils.addSafely(activePowerAC, thisActivePowerAC); + if ("ActivePowerL1" in meterData) { + isAsymmetric = true; + activePowerACL1 = Utils.addSafely(activePowerACL1, meterData.ActivePowerL1); + } else { + activePowerACL1 = Utils.addSafely(activePowerACL1, thisActivePowerACL); + } + if ("ActivePowerL2" in meterData) { + isAsymmetric = true; + activePowerACL2 = Utils.addSafely(activePowerACL2, meterData.ActivePowerL2); + } else { + activePowerACL2 = Utils.addSafely(activePowerACL2, thisActivePowerACL); + } + if ("ActivePowerL3" in meterData) { + isAsymmetric = true; + activePowerACL3 = Utils.addSafely(activePowerACL3, meterData.ActivePowerL3); + } else { + activePowerACL3 = Utils.addSafely(activePowerACL3, thisActivePowerACL); + } + if ("ActualPower" in meterData && meterData.ActualPower != null) { + activePowerDC = Utils.addSafely(activePowerDC, meterData.ActualPower); + } + if ("maxActivePower" in meterConfig) { + maxActivePower += meterConfig.maxActivePower; + } + if ("maxActualPower" in meterConfig) { + maxActivePower += meterConfig.maxActualPower; + } + } + if (isAsymmetric) { + activePowerAC = Utils.addSafely(Utils.addSafely(activePowerACL1, activePowerACL2), activePowerACL3) + } + // correct negative production + if (activePowerAC < 0) { + console.warn("negative production? ", config.productionMeters, activePowerAC) + // TODO activePowerAC = 0; + } + if (maxActivePower < 0) { maxActivePower = 0; } + if (maxActivePower == 0) { + powerRatio = 100; + } else { + let activePowerACDC = Utils.addSafely(activePowerAC, activePowerDC); + powerRatio = Utils.divideSafely(activePowerACDC, (maxActivePower / 100)); + } + + result.production.powerRatio = powerRatio; + result.production.isAsymmetric = isAsymmetric; + result.production.hasDC = config.chargers.length > 0; + result.production.activePowerAC = activePowerAC; + result.production.activePowerACL1 = activePowerACL1; + result.production.activePowerACL2 = activePowerACL2; + result.production.activePowerACL3 = activePowerACL3; + result.production.activePowerDC = activePowerDC; + result.production.activePower = Utils.addSafely(activePowerAC, activePowerDC); + result.production.maxActivePower = maxActivePower; + } + + { + /* + * Consumption + */ + // Consumption = GridBuy + Production + ESS-Discharge - GridSell - ESS-Charge + let minus = Utils.addSafely(result.grid.sellActivePower, result.storage.chargeActivePowerAC); + let plus = Utils.addSafely(Utils.addSafely(result.grid.buyActivePower, result.production.activePowerAC), result.storage.dischargeActivePowerAC); + let activePower = Utils.subtractSafely(plus, minus); + + let maxActivePower = result.grid.maxBuyActivePower - result.grid.maxSellActivePower // + + result.production.maxActivePower // + + result.storage.maxChargeActivePower - result.storage.maxDischargeActivePower; + result.consumption.powerRatio = Utils.divideSafely(activePower, (maxActivePower / 100)); + result.consumption.activePower = activePower; + } + return result; + } + + private getActivePower(o: any): number { + if ("ActivePowerL1" in o && o.ActivePowerL1 != null && "ActivePowerL2" in o && o.ActivePowerL2 != null && "ActivePowerL3" in o && o.ActivePowerL3 != null) { + return o.ActivePowerL1 + o.ActivePowerL2 + o.ActivePowerL3; + } else if ("ActivePower" in o && o.ActivePower != null) { + return o.ActivePower; + } else { + return null; + } + } +} \ No newline at end of file diff --git a/ui/src/app/shared/edge/currentdata.2018.8.ts b/ui/src/app/shared/edge/currentdata.2018.8.ts new file mode 100644 index 00000000000..7d84f0cc5b6 --- /dev/null +++ b/ui/src/app/shared/edge/currentdata.2018.8.ts @@ -0,0 +1,119 @@ +import { DefaultTypes } from '../service/defaulttypes'; +import { ConfigImpl } from './config'; +import { Utils } from '../service/utils'; +import { Edge } from './edge'; +import { CurrentDataAndSummary } from './currentdata'; + +export class CurrentDataAndSummary_2018_8 extends CurrentDataAndSummary { + constructor(private edge: Edge, data: DefaultTypes.Data, config: ConfigImpl) { + super(data); + this.summary = this.getSummary(data, config); + } + + private getSummary(d: DefaultTypes.Data, config: ConfigImpl): DefaultTypes.Summary { + let result: DefaultTypes.Summary = { + storage: { + soc: null, + isAsymmetric: false, + hasDC: false, + chargeActivePower: null, // sum of chargeActivePowerAC and chargeActivePowerDC + chargeActivePowerAC: null, + chargeActivePowerACL1: null, + chargeActivePowerACL2: null, + chargeActivePowerACL3: null, + chargeActivePowerDC: null, + maxChargeActivePower: null, + dischargeActivePower: null, // sum of dischargeActivePowerAC and dischargeActivePowerDC + dischargeActivePowerAC: null, + dischargeActivePowerACL1: null, + dischargeActivePowerACL2: null, + dischargeActivePowerACL3: null, + dischargeActivePowerDC: null, + maxDischargeActivePower: null + }, production: { + isAsymmetric: false, + hasDC: false, + powerRatio: null, + activePower: null, // sum of activePowerAC and activePowerDC + activePowerAC: null, + activePowerACL1: null, + activePowerACL2: null, + activePowerACL3: null, + activePowerDC: null, // TODO rename to actualPower + maxActivePower: null + }, grid: { + powerRatio: null, + buyActivePower: null, + maxBuyActivePower: null, + sellActivePower: null, + maxSellActivePower: null + }, consumption: { + powerRatio: null, + activePower: null + } + }; + + const sum = d['_sum']; + { + /* + * Storage + * > 0 => Discharge + * < 0 => Charge + */ + result.storage.soc = sum['EssSoc']; + const essActivePower: number = sum['EssActivePower']; + result.storage.chargeActivePowerAC = essActivePower < 0 ? essActivePower * -1 : 0; + result.storage.chargeActivePower = result.storage.chargeActivePowerAC; // TODO + result.storage.dischargeActivePowerAC = essActivePower > 0 ? essActivePower : 0; + result.storage.dischargeActivePower = result.storage.dischargeActivePowerAC; // TODO + if (sum['ProductionDcActualPower'] != null) { + result.storage.chargeActivePowerDC = sum['ProductionDcActualPower']; + result.storage.hasDC = true; + } + } + + { + /* + * Grid + * > 0 => Buy from grid + * < 0 => Sell to grid + */ + const gridActivePower: number = sum['GridActivePower']; + result.grid.maxBuyActivePower = sum['GridMaxActivePower']; + result.grid.maxSellActivePower = sum['GridMinActivePower'] * -1; + if (gridActivePower > 0) { + result.grid.sellActivePower = 0; + result.grid.buyActivePower = gridActivePower; + result.grid.powerRatio = Math.round(result.grid.buyActivePower / result.grid.maxBuyActivePower * 100); + } else { + result.grid.sellActivePower = gridActivePower * -1; + result.grid.buyActivePower = 0; + result.grid.powerRatio = Math.round(result.grid.buyActivePower / result.grid.maxSellActivePower * -100); + } + } + + { + /* + * Production + */ + result.production.activePowerAC = sum['ProductionAcActivePower']; + result.production.activePower = sum['ProductionActivePower']; // TODO + result.production.maxActivePower = sum['ProductionMaxActivePower']; + result.production.powerRatio = Math.round(result.production.activePower / result.production.maxActivePower * 100); + if (sum['ProductionDcActualPower'] != null) { + result.production.activePowerDC = sum['ProductionDcActualPower']; + result.production.hasDC = true; + } + } + + { + /* + * Consumption + */ + result.consumption.activePower = sum['ConsumptionActivePower']; + const consumptionMaxActivePower = sum['ConsumptionMaxActivePower']; + result.consumption.powerRatio = Math.round(result.consumption.activePower / consumptionMaxActivePower * 100); + } + return result; + } +} \ No newline at end of file diff --git a/ui/src/app/shared/edge/currentdata.ts b/ui/src/app/shared/edge/currentdata.ts index 58f2f717ab5..72d6b824d3e 100644 --- a/ui/src/app/shared/edge/currentdata.ts +++ b/ui/src/app/shared/edge/currentdata.ts @@ -4,415 +4,9 @@ import { Utils } from '../service/utils'; import { Edge } from './edge'; export class CurrentDataAndSummary { - public readonly summary: DefaultTypes.Summary; + public summary: DefaultTypes.Summary; - constructor(private edge: Edge, public data: DefaultTypes.Data, config: ConfigImpl) { - if (edge.isVersionAtLeast('2018.8')) { - this.summary = this.getSummary(data, config); - } else { - this.summary = this.calculateSummaryBefore2018_8(data, config); - } - } - - private getSummary(d: DefaultTypes.Data, config: ConfigImpl): DefaultTypes.Summary { - let result: DefaultTypes.Summary = { - storage: { - soc: null, - isAsymmetric: false, - hasDC: false, - chargeActivePower: null, // sum of chargeActivePowerAC and chargeActivePowerDC - chargeActivePowerAC: null, - chargeActivePowerACL1: null, - chargeActivePowerACL2: null, - chargeActivePowerACL3: null, - chargeActivePowerDC: null, - maxChargeActivePower: null, - dischargeActivePower: null, // sum of dischargeActivePowerAC and dischargeActivePowerDC - dischargeActivePowerAC: null, - dischargeActivePowerACL1: null, - dischargeActivePowerACL2: null, - dischargeActivePowerACL3: null, - dischargeActivePowerDC: null, - maxDischargeActivePower: null - }, production: { - isAsymmetric: false, - hasDC: false, - powerRatio: null, - activePower: null, // sum of activePowerAC and activePowerDC - activePowerAC: null, - activePowerACL1: null, - activePowerACL2: null, - activePowerACL3: null, - activePowerDC: null, - maxActivePower: null - }, grid: { - powerRatio: null, - buyActivePower: null, - maxBuyActivePower: null, - sellActivePower: null, - maxSellActivePower: null - }, consumption: { - powerRatio: null, - activePower: null - } - }; - - const sum = d['_sum']; - { - /* - * Storage - * > 0 => Discharge - * < 0 => Charge - */ - result.storage.soc = sum['EssSoc']; - const essActivePower: number = sum['EssActivePower']; - result.storage.chargeActivePowerAC = essActivePower < 0 ? essActivePower * -1 : 0; - result.storage.chargeActivePower = result.storage.chargeActivePowerAC; // TODO - result.storage.dischargeActivePowerAC = essActivePower > 0 ? essActivePower : 0; - result.storage.dischargeActivePower = result.storage.dischargeActivePowerAC; // TODO - } - - { - /* - * Grid - * > 0 => Buy from grid - * < 0 => Sell to grid - */ - const gridActivePower: number = sum['GridActivePower']; - result.grid.maxBuyActivePower = sum['GridMaxActivePower']; - result.grid.maxSellActivePower = sum['GridMinActivePower'] * -1; - if (gridActivePower > 0) { - result.grid.sellActivePower = 0; - result.grid.buyActivePower = gridActivePower; - result.grid.powerRatio = Math.round(result.grid.buyActivePower / result.grid.maxBuyActivePower * 100); - } else { - result.grid.sellActivePower = gridActivePower * -1; - result.grid.buyActivePower = 0; - result.grid.powerRatio = Math.round(result.grid.buyActivePower / result.grid.maxSellActivePower * -100); - } - } - - { - /* - * Production - */ - const productionActivePower: number = sum['ProductionActivePower']; - result.production.activePowerAC = productionActivePower; - result.production.activePower = result.production.activePowerAC; // TODO - result.production.maxActivePower = sum['ProductionMaxActivePower']; - result.production.powerRatio = Math.round(result.production.activePower / result.production.maxActivePower * 100); - } - - { - /* - * Consumption - */ - const consumptionActivePower: number = sum['ConsumptionActivePower']; - result.consumption.activePower = consumptionActivePower; - const consumptionMaxActivePower = sum['ConsumptionMaxActivePower']; - result.consumption.powerRatio = Math.round(result.consumption.activePower / consumptionMaxActivePower * 100); - } - return result; - } - - private calculateSummaryBefore2018_8(currentData: DefaultTypes.Data, config: ConfigImpl): DefaultTypes.Summary { - let result: DefaultTypes.Summary = { - storage: { - soc: null, - isAsymmetric: false, - hasDC: false, - chargeActivePower: null, // sum of chargeActivePowerAC and chargeActivePowerDC - chargeActivePowerAC: null, - chargeActivePowerACL1: null, - chargeActivePowerACL2: null, - chargeActivePowerACL3: null, - chargeActivePowerDC: null, - maxChargeActivePower: null, - dischargeActivePower: null, // sum of dischargeActivePowerAC and dischargeActivePowerDC - dischargeActivePowerAC: null, - dischargeActivePowerACL1: null, - dischargeActivePowerACL2: null, - dischargeActivePowerACL3: null, - dischargeActivePowerDC: null, - maxDischargeActivePower: null - }, production: { - isAsymmetric: false, - hasDC: false, - powerRatio: null, - activePower: null, // sum of activePowerAC and activePowerDC - activePowerAC: null, - activePowerACL1: null, - activePowerACL2: null, - activePowerACL3: null, - activePowerDC: null, - maxActivePower: null - }, grid: { - powerRatio: null, - buyActivePower: null, - maxBuyActivePower: null, - sellActivePower: null, - maxSellActivePower: null - }, consumption: { - powerRatio: null, - activePower: null - } - }; - - { - /* - * Storage - * > 0 => Discharge - * < 0 => Charge - */ - let soc = null; - let isAsymmetric = false; - let activePowerAC = null; - let activePowerACL1 = null; - let activePowerACL2 = null; - let activePowerACL3 = null; - let activePowerDC = null; - let countSoc = 0; - for (let thing of config.storageThings) { - if (thing in currentData) { - let essData = currentData[thing]; - if ("Soc" in essData) { - soc = Utils.addSafely(soc, essData.Soc); - countSoc += 1; - } - let thisActivePowerAC = this.getActivePower(essData); - let thisActivePowerACL = Utils.divideSafely(thisActivePowerAC, 3); - activePowerAC = Utils.addSafely(activePowerAC, thisActivePowerAC); - if ("ActivePowerL1" in essData) { - isAsymmetric = true; - activePowerACL1 = Utils.addSafely(activePowerACL1, essData.ActivePowerL1); - } else { - activePowerACL1 = Utils.addSafely(activePowerACL1, thisActivePowerACL); - } - if ("ActivePowerL2" in essData) { - isAsymmetric = true; - activePowerACL2 = Utils.addSafely(activePowerACL2, essData.ActivePowerL2); - } else { - activePowerACL2 = Utils.addSafely(activePowerACL2, thisActivePowerACL); - } - if ("ActivePowerL3" in essData) { - isAsymmetric = true; - activePowerACL3 = Utils.addSafely(activePowerACL3, essData.ActivePowerL3); - } else { - activePowerACL3 = Utils.addSafely(activePowerACL3, thisActivePowerACL); - } - } - } - for (let thing of config.chargers) { - if (thing in currentData) { - let essData = currentData[thing]; - activePowerDC = Utils.subtractSafely(activePowerDC, essData.ActualPower); - } - } - result.storage.soc = Utils.divideSafely(soc, countSoc); - result.storage.isAsymmetric = isAsymmetric; - result.storage.hasDC = config.chargers.length > 0; - if (result.storage.soc > 100 || result.storage.soc < 0) { - result.storage.soc = null; - } - if (isAsymmetric) { - activePowerAC = Utils.addSafely(Utils.addSafely(activePowerACL1, activePowerACL2), activePowerACL3) - } - if (activePowerAC != null) { - if (activePowerAC > 0) { - result.storage.chargeActivePowerAC = 0; - result.storage.dischargeActivePowerAC = activePowerAC; - } else { - result.storage.chargeActivePowerAC = activePowerAC * -1; - result.storage.dischargeActivePowerAC = 0; - } - } - if (activePowerACL1 != null) { - if (activePowerACL1 > 0) { - result.storage.chargeActivePowerACL1 = 0; - result.storage.dischargeActivePowerACL1 = activePowerACL1; - } else { - result.storage.chargeActivePowerACL1 = activePowerACL1 * -1; - result.storage.dischargeActivePowerACL1 = 0; - } - } - if (activePowerACL2 != null) { - if (activePowerACL2 > 0) { - result.storage.chargeActivePowerACL2 = 0; - result.storage.dischargeActivePowerACL2 = activePowerACL2; - } else { - result.storage.chargeActivePowerACL2 = activePowerACL2 * -1; - result.storage.dischargeActivePowerACL2 = 0; - } - } - if (activePowerACL3 != null) { - if (activePowerACL3 > 0) { - result.storage.chargeActivePowerACL3 = 0; - result.storage.dischargeActivePowerACL3 = activePowerACL3; - } else { - result.storage.chargeActivePowerACL3 = activePowerACL3 * -1; - result.storage.dischargeActivePowerACL3 = 0; - } - } - if (activePowerDC != null) { - if (activePowerDC > 0) { - result.storage.chargeActivePowerDC = activePowerDC; - result.storage.dischargeActivePowerDC = 0; - } else { - result.storage.chargeActivePowerDC = 0; - result.storage.dischargeActivePowerDC = activePowerDC * -1; - } - } - let activePower = Utils.subtractSafely( - Utils.addSafely(result.storage.chargeActivePowerAC, result.storage.chargeActivePowerDC), - Utils.addSafely(result.storage.dischargeActivePowerAC, result.storage.dischargeActivePowerDC)); - if (activePower != null) { - if (activePower > 0) { - result.storage.chargeActivePower = activePower; - result.storage.dischargeActivePower = 0; - } else { - result.storage.chargeActivePower = 0; - result.storage.dischargeActivePower = activePower * -1; - } - } - } - - { - /* - * Grid - * > 0 => Buy from grid - * < 0 => Sell to grid - */ - let activePower = null; - let ratio = 0; - let maxSell = 0; - let maxBuy = 0; - for (let thing of config.gridMeters) { - let meterData = currentData[thing]; - let meterConfig = config.things[thing]; - activePower = Utils.addSafely(activePower, this.getActivePower(meterData)); - if ("maxActivePower" in meterConfig) { - maxBuy += meterConfig.maxActivePower; - } - if ("minActivePower" in meterConfig) { - maxSell += meterConfig.minActivePower; - } - } - // set GridBuy and GridSell - result.grid.maxSellActivePower = maxSell * -1; - result.grid.maxBuyActivePower = maxBuy; - if (activePower != null) { - if (activePower > 0) { - result.grid.sellActivePower = 0; - result.grid.buyActivePower = activePower; - ratio = result.grid.buyActivePower / maxSell * 100; - } else { - result.grid.sellActivePower = activePower * -1; - result.grid.buyActivePower = 0; - ratio = result.grid.sellActivePower / maxSell * -100; - } - } - result.grid.powerRatio = ratio; - } - - { - /* - * Production - */ - let powerRatio = 0; - let isAsymmetric = false; - let activePowerAC = null; - let activePowerACL1 = null; - let activePowerACL2 = null; - let activePowerACL3 = null; - let activePowerDC = null; - let maxActivePower = 0; - for (let thing of config.productionMeters) { - let meterData = currentData[thing]; - let meterConfig = config.things[thing]; - let thisActivePowerAC = this.getActivePower(meterData); - let thisActivePowerACL = Utils.divideSafely(thisActivePowerAC, 3); - activePowerAC = Utils.addSafely(activePowerAC, thisActivePowerAC); - if ("ActivePowerL1" in meterData) { - isAsymmetric = true; - activePowerACL1 = Utils.addSafely(activePowerACL1, meterData.ActivePowerL1); - } else { - activePowerACL1 = Utils.addSafely(activePowerACL1, thisActivePowerACL); - } - if ("ActivePowerL2" in meterData) { - isAsymmetric = true; - activePowerACL2 = Utils.addSafely(activePowerACL2, meterData.ActivePowerL2); - } else { - activePowerACL2 = Utils.addSafely(activePowerACL2, thisActivePowerACL); - } - if ("ActivePowerL3" in meterData) { - isAsymmetric = true; - activePowerACL3 = Utils.addSafely(activePowerACL3, meterData.ActivePowerL3); - } else { - activePowerACL3 = Utils.addSafely(activePowerACL3, thisActivePowerACL); - } - if ("ActualPower" in meterData && meterData.ActualPower != null) { - activePowerDC = Utils.addSafely(activePowerDC, meterData.ActualPower); - } - if ("maxActivePower" in meterConfig) { - maxActivePower += meterConfig.maxActivePower; - } - if ("maxActualPower" in meterConfig) { - maxActivePower += meterConfig.maxActualPower; - } - } - if (isAsymmetric) { - activePowerAC = Utils.addSafely(Utils.addSafely(activePowerACL1, activePowerACL2), activePowerACL3) - } - // correct negative production - if (activePowerAC < 0) { - console.warn("negative production? ", config.productionMeters, activePowerAC) - // TODO activePowerAC = 0; - } - if (maxActivePower < 0) { maxActivePower = 0; } - if (maxActivePower == 0) { - powerRatio = 100; - } else { - let activePowerACDC = Utils.addSafely(activePowerAC, activePowerDC); - powerRatio = Utils.divideSafely(activePowerACDC, (maxActivePower / 100)); - } - - result.production.powerRatio = powerRatio; - result.production.isAsymmetric = isAsymmetric; - result.production.hasDC = config.chargers.length > 0; - result.production.activePowerAC = activePowerAC; - result.production.activePowerACL1 = activePowerACL1; - result.production.activePowerACL2 = activePowerACL2; - result.production.activePowerACL3 = activePowerACL3; - result.production.activePowerDC = activePowerDC; - result.production.activePower = Utils.addSafely(activePowerAC, activePowerDC); - result.production.maxActivePower = maxActivePower; - } - - { - /* - * Consumption - */ - // Consumption = GridBuy + Production + ESS-Discharge - GridSell - ESS-Charge - let minus = Utils.addSafely(result.grid.sellActivePower, result.storage.chargeActivePowerAC); - let plus = Utils.addSafely(Utils.addSafely(result.grid.buyActivePower, result.production.activePowerAC), result.storage.dischargeActivePowerAC); - let activePower = Utils.subtractSafely(plus, minus); - - let maxActivePower = result.grid.maxBuyActivePower - result.grid.maxSellActivePower // - + result.production.maxActivePower // - + result.storage.maxChargeActivePower - result.storage.maxDischargeActivePower; - result.consumption.powerRatio = Utils.divideSafely(activePower, (maxActivePower / 100)); - result.consumption.activePower = activePower; - } - return result; - } + constructor(public data: DefaultTypes.Data) { - private getActivePower(o: any): number { - if ("ActivePowerL1" in o && o.ActivePowerL1 != null && "ActivePowerL2" in o && o.ActivePowerL2 != null && "ActivePowerL3" in o && o.ActivePowerL3 != null) { - return o.ActivePowerL1 + o.ActivePowerL2 + o.ActivePowerL3; - } else if ("ActivePower" in o && o.ActivePower != null) { - return o.ActivePower; - } else { - return null; - } } } \ No newline at end of file diff --git a/ui/src/app/shared/edge/edge.ts b/ui/src/app/shared/edge/edge.ts index 90b5e8537e0..36096d4c075 100644 --- a/ui/src/app/shared/edge/edge.ts +++ b/ui/src/app/shared/edge/edge.ts @@ -10,10 +10,14 @@ import { cmp } from 'semver-compare-multi'; import { Websocket } from '../shared'; import { ConfigImpl } from './config'; import { CurrentDataAndSummary } from './currentdata'; +import { CurrentDataAndSummary_2018_7 } from './currentdata.2018.7'; import { DefaultMessages } from '../service/defaultmessages'; import { DefaultTypes } from '../service/defaulttypes'; import { Utils } from '../service/utils'; import { Role } from '../type/role'; +import { ConfigImpl_2018_8 } from './config.2018.8'; +import { ConfigImpl_2018_7 } from './config.2018.7'; +import { CurrentDataAndSummary_2018_8 } from './currentdata.2018.8'; export class Log { timestamp: number; @@ -80,7 +84,12 @@ export class Edge { // wait for reply this.replyStreams[messageId].first().subscribe(reply => { let config = (reply).config; - let configImpl = new ConfigImpl(this, config) + let configImpl + if (this.isVersionAtLeast('2018.8')) { + configImpl = new ConfigImpl_2018_8(this, config); + } else { + configImpl = new ConfigImpl_2018_7(this, config); + } this.config.next(configImpl); this.replyStreams[messageId].unsubscribe(); delete this.replyStreams[messageId]; @@ -117,7 +126,13 @@ export class Edge { let replyStream = this.sendMessageWithReply(DefaultMessages.currentDataSubscribe(this.edgeId, channels)); let obs = replyStream .map(message => (message as DefaultMessages.CurrentDataReply).currentData) - .combineLatest(this.config, (currentData, config) => new CurrentDataAndSummary(this, currentData, config)); + .combineLatest(this.config, (currentData, config) => { + if (this.isVersionAtLeast('2018.8')) { + return new CurrentDataAndSummary_2018_8(this, currentData, config); + } else { + return new CurrentDataAndSummary_2018_7(this, currentData, config); + } + }); // TODO send "unsubscribe" to websocket when nobody is subscribed on this observable anymore return obs; } diff --git a/ui/src/app/shared/service/defaulttypes.ts b/ui/src/app/shared/service/defaulttypes.ts index 28ddb034a1d..47cf90f3254 100644 --- a/ui/src/app/shared/service/defaulttypes.ts +++ b/ui/src/app/shared/service/defaulttypes.ts @@ -25,12 +25,6 @@ export module DefaultTypes { } export interface Config { - components?: { // FROM VERSION 2018.8 - [id: string]: ComponentConfig - }, - things?: { // BEVORE VERSION 2018.8 - [id: string]: ThingConfig - }, meta: { [factoryPid: string]: { implements: string[], @@ -49,6 +43,18 @@ export module DefaultTypes { } } + export interface Config_2018_8 extends Config { + components?: { + [id: string]: ComponentConfig + }, + } + + export interface Config_2018_7 extends Config { + things?: { + [id: string]: ThingConfig + }, + } + export interface Data { [thing: string]: { [channel: string]: any diff --git a/ui/src/app/shared/shared.module.ts b/ui/src/app/shared/shared.module.ts index 3620fc92b8e..afe1424a8f8 100644 --- a/ui/src/app/shared/shared.module.ts +++ b/ui/src/app/shared/shared.module.ts @@ -36,10 +36,11 @@ import { HasclassPipe } from './pipe/hasclass/hasclass.pipe'; /* * Components */ -import { SocChartComponent } from './../edge/history/chart/socchart/socchart.component'; import { AbstractConfigComponent } from './config/abstractconfig.component'; import { ExistingThingComponent } from './config/existingthing.component'; import { ChannelComponent } from './config/channel.component'; +import { SocChartComponent_2018_7 } from '../edge/history/chart/socchart.2018.7/socchart.2018.7.component'; +import { SocChartComponent_2018_8 } from '../edge/history/chart/socchart.2018.8/socchart.2018.8.component'; @NgModule({ imports: [ @@ -64,7 +65,8 @@ import { ChannelComponent } from './config/channel.component'; IsclassPipe, HasclassPipe, // components - SocChartComponent, + SocChartComponent_2018_8, + SocChartComponent_2018_7, AbstractConfigComponent, ChannelComponent, ExistingThingComponent @@ -89,7 +91,8 @@ import { ChannelComponent } from './config/channel.component'; MyDateRangePickerModule, ToasterModule, // components - SocChartComponent, + SocChartComponent_2018_7, + SocChartComponent_2018_8, LoadingModule, AbstractConfigComponent, ChannelComponent, diff --git a/ui/src/app/shared/translate/de.ts b/ui/src/app/shared/translate/de.ts index b24eff99781..7e66b671d68 100644 --- a/ui/src/app/shared/translate/de.ts +++ b/ui/src/app/shared/translate/de.ts @@ -118,7 +118,7 @@ export const TRANSLATION = { Developed: "Diese Benutzeroberfläche wird von FENECON als Open-Source-Software entwickelt.", Fenecon: "Mehr zu FENECON", Fems: "Mehr zu FEMS", - Sourcecode: "Quellcode", + OpenEMS: "Mehr zu OpenEMS", CurrentDevelopments: "Aktuelle Entwicklungen", Build: "Dieser Build", Contact: "Für Rückfragen und Anregungen zum System, wenden Sie sich bitte an unser FEMS-Team unter {{value}}.", // value = Mail from FEMS-Team diff --git a/ui/src/app/shared/translate/en.ts b/ui/src/app/shared/translate/en.ts index 9ae96debff9..69451336648 100644 --- a/ui/src/app/shared/translate/en.ts +++ b/ui/src/app/shared/translate/en.ts @@ -118,7 +118,7 @@ export const TRANSLATION = { Developed: "This user interface is developed by FENECON as open-source software.", Fenecon: "More about FENECON", Fems: "More about FEMS", - Sourcecode: "Source code", + OpenEMS: "More about OpenEMS", CurrentDevelopments: "Current developments", Build: "This build", Contact: "Please contact our FEMS team for further information or suggestions about the system at {{value}}.", // value = Mail from FEMS-Team diff --git a/ui/src/app/shared/type/widget.ts b/ui/src/app/shared/type/widget.ts index bb7fa63cce6..f68bc2ef9d5 100644 --- a/ui/src/app/shared/type/widget.ts +++ b/ui/src/app/shared/type/widget.ts @@ -1 +1 @@ -export type Widget = "EVCS"; \ No newline at end of file +export type Widget = "EVCS" | "CHANNELTHRESHOLD" diff --git a/ui/src/theme.scss b/ui/src/theme.scss index 1d12803029c..05b71440549 100644 --- a/ui/src/theme.scss +++ b/ui/src/theme.scss @@ -6,4 +6,6 @@ $accent: mat-palette($mat-blue-grey, A200, A100, A400); $theme: mat-light-theme($primary, $accent); -@include angular-material-theme($theme); \ No newline at end of file +@include angular-material-theme($theme); + +.material-icons.orange600 { color: #FB8C00; } \ No newline at end of file