@ospin/fct-graph
Advanced tools
Comparing version 2.16.0 to 2.17.0
{ | ||
"name": "@ospin/fct-graph", | ||
"author": "danielseehausen", | ||
"version": "2.16.0", | ||
"version": "2.17.0", | ||
"description": "Graph data structure with conditional edges via 'slots' on nodes. Intended to represent physical and virtual functionalities on a device.", | ||
@@ -6,0 +6,0 @@ "main": "index.js", |
@@ -130,3 +130,9 @@ [![codecov](https://codecov.io/gh/ospin-web-dev/FCTGraph/branch/main/graph/badge.svg?token=RXXLX0HDAR)](https://codecov.io/gh/ospin-web-dev/FCTGraph) | ||
├── Actuator (virtual) | ||
│ └── HeaterActuator | ||
│ ├── HeaterActuator | ||
│ ├── StirrerActuator | ||
│ │ ├── HeidolphOverheadStirrer | ||
│ │ └── HeidolphMagneticStirrer | ||
│ ├── PumpActuator | ||
│ │ └── HeidolphPump | ||
│ └── UnknownActuator | ||
├── Controller (virtual) | ||
@@ -140,3 +146,4 @@ │ └── PIDController | ||
└── Sensor (virtual) | ||
└── TemperatureSensor | ||
├── TemperatureSensor | ||
└── UnknownSensor | ||
@@ -204,3 +211,3 @@ // a Functionality has many Slots | ||
The package comes with seeders which have the same class hierarchy as the primary models: | ||
The package comes with seeders which have the same class hierarchy as the primary models. A seeder exists for every [non-virtual functionality and slot](#ClassStructureAndHierarchies). The seeder modules are named after the classes, e.g. `PIDControllerSeeder` or `BooleanInSlotSeeder`. Refer to the [Class Structure and Hierarchies](#ClassStructureAndHierarchies) above for the full list of functionalities and slots. Following is an example of the seeder heirarchy: | ||
```js | ||
@@ -212,13 +219,7 @@ FCTGraphSeeder | ||
│ ├── HeaterActuatorSeeder | ||
│ └── UnknownActuatorSeeder | ||
├── ControllerSeeder (virtual) | ||
│ └── PIDControllerSeeder | ||
├── InputNodeSeeder (virtual) | ||
│ └── PushInSeeder | ||
├── OutputNodeSeeder (virtual) | ||
│ ├── PushOutSeeder | ||
│ └── IntervalOutSeeder | ||
└── SensorSeeder (virtual) | ||
├── TemperatureSensorSeeder | ||
└── UnknownSensorSeeder | ||
│ ├── StirrerActuatorSeeder | ||
│ │ ├── HeidolphOverheadStirrerSeeder | ||
│ │ └── ... | ||
│ └── ... | ||
└── ... | ||
@@ -229,18 +230,27 @@ SlotSeeder (virtual) | ||
│ └── IntegerInSlotSeeder | ||
│ └── FloatInSlotSeeder | ||
│ └── BooleanInSlotSeeder | ||
│ └── OneOfInSlotSeeder | ||
│ ├── FloatInSlotSeeder | ||
│ └── ... | ||
└── OutSlotSeeder (virtual) | ||
└── IntegerOutSlotSeeder | ||
└── FloatOutSlotSeeder | ||
└── BooleanOutSlotSeeder | ||
└── OneOfOutSlotSeeder | ||
├── IntegerOutSlotSeeder | ||
└── ... | ||
``` | ||
...accessing seeders from the public interface: | ||
```js | ||
const { | ||
functionalitySeeders: { StirrerActuatorSeeder }, | ||
slotSeeders: { FloatInSlotSeeder }, | ||
} = require('@ospin/fct-graph') // or import | ||
const stirrerActuator = StirrerActuatorSeeder.seedOne() // <- instance | ||
stirrerActuator.isPhysical() // -> true | ||
``` | ||
All virtual seeders (e.g. HeaterActuatorSeeder, InSlotSeeder etc.) compose the **FactorySeeder** module, which provides the following static methods (which extend to their children): | ||
- **static get SEED_METHOD** (abstract) - blows up - informing the user that the class that composed FactorySeeder needs a static `.SEED_METHOD` getter. This method should be used to call a constructor/factory's creation method | ||
- **static generate** (abstract) - blows up - informing the user that the class that composed FactorySeeder needs a static `.generate` method. This method should be used to create fake data which matches the class SCHEMA | ||
- **.seedOne** - expects a data object. delegates to `generate` and `SEED_METHOD` | ||
- **.seedMany** - expects an array of data objects | ||
- **.seedN** - expects an object and a count | ||
- **static seedOne** - expects a data object. delegates to `generate` and `SEED_METHOD` | ||
- **static seedMany** - expects an array of data objects | ||
- **static seedN** - expects an object and a count | ||
@@ -271,3 +281,2 @@ --- | ||
## Upcoming: | ||
- reject setting properties on the core classes that should not change throughout the lifetime of an object (`type`, `subType`, `name`, etc.) | ||
- reject setting properties on the core classes that should not change throughout the lifetime of an object (`name`, `anything else that is missing`.) |
@@ -57,5 +57,3 @@ const Joi = require('joi') | ||
_populateConnections(functionalitiesData) { | ||
const dataStreamsData = FCTGraph._collectUniqueDataStreamsData(functionalitiesData) | ||
_addManyConnectionsViaDataStreamsData(dataStreamsData) { | ||
dataStreamsData.forEach(dataStreamData => ( | ||
@@ -66,2 +64,8 @@ this._addConnectionViaDataStreamData(dataStreamData) | ||
_populateConnections(functionalitiesData) { | ||
const dataStreamsData = FCTGraph._collectUniqueDataStreamsData(functionalitiesData) | ||
this._addManyConnectionsViaDataStreamsData(dataStreamsData) | ||
} | ||
constructor({ | ||
@@ -68,0 +72,0 @@ id, |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const Functionality = require('./Functionality') | ||
@@ -11,8 +9,2 @@ | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
type: Joi.string().allow(Actuator.TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(functionalityData) { | ||
@@ -23,14 +15,6 @@ super({ | ||
}) | ||
this.type = Actuator.TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
type: this.type, | ||
} | ||
} | ||
} | ||
module.exports = Actuator |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const Functionality = require('./Functionality') | ||
@@ -11,8 +9,2 @@ | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
type: Joi.string().allow(Controller.TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(functionalityData) { | ||
@@ -23,14 +15,6 @@ super({ | ||
}) | ||
this.type = Controller.TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
type: this.type, | ||
} | ||
} | ||
} | ||
module.exports = Controller |
@@ -9,2 +9,7 @@ const { v4: uuidv4 } = require('uuid') | ||
const IntervalOut = require('../IntervalOut') | ||
const PumpActuator = require('../PumpActuator') | ||
const HeidolphPump = require('../HeidolphPump') | ||
const StirrerActuator = require('../StirrerActuator') | ||
const HeidolphMagneticStirrer = require('../HeidolphMagneticStirrer') | ||
const HeidolphOverheadStirrer = require('../HeidolphOverheadStirrer') | ||
const PushOut = require('../PushOut') | ||
@@ -23,2 +28,7 @@ const PushIn = require('../PushIn') | ||
IntervalOut, | ||
PumpActuator, | ||
HeidolphPump, | ||
StirrerActuator, | ||
HeidolphMagneticStirrer, | ||
HeidolphOverheadStirrer, | ||
PushOut, | ||
@@ -56,3 +66,3 @@ PushIn, | ||
const json = JSON.stringify(funcData) | ||
throw new Error(`Functionality type not supported ${type || 'FALSEY'}\n${json}`) | ||
throw new Error(`Functionality type not supported: ${type || 'FALSEY'}\n${json}`) | ||
} | ||
@@ -62,3 +72,3 @@ | ||
const json = JSON.stringify(funcData) | ||
throw new Error(`Functionality subType not supported ${subType || 'FALSEY'}\n${json}`) | ||
throw new Error(`Functionality subType not supported: ${subType || 'FALSEY'}\n${json}`) | ||
} | ||
@@ -65,0 +75,0 @@ } |
@@ -7,6 +7,11 @@ const Joi = require('joi') | ||
const SlotFactory = require('../slots/factories/SlotFactory') | ||
const AddSlotError = require('./AddSlotError') | ||
const AddSlotError = require('./FCTErrors/AddSlotError') | ||
const SetProtectedPropertyError = require('./FCTErrors/SetProtectedPropertyError') | ||
class Functionality { | ||
static get TYPE() { return null } | ||
static get SUB_TYPE() { return null } | ||
static get SCHEMA() { | ||
@@ -16,6 +21,7 @@ return Joi.object({ | ||
name: Joi.string().required(), | ||
type: Joi.string().allow(this.TYPE).required(), | ||
subType: Joi.string().allow(this.SUB_TYPE).required(), | ||
slots: Joi.array().items(Joi.alternatives().try( | ||
...SlotFactory.SUPPORTED_CLASSES_SCHEMAS, | ||
)).required(), | ||
controllerName: Joi.string().allow(''), // this is used to support the old devices: https://github.com/ospin-web-dev/hambda/issues/913 | ||
isVirtual: Joi.boolean().required(), | ||
@@ -29,2 +35,14 @@ }) | ||
get subType() { return this.constructor.SUB_TYPE } | ||
set subType(val) { | ||
throw new SetProtectedPropertyError(this, 'subType', val) | ||
} | ||
get type() { return this.constructor.TYPE } | ||
set type(val) { | ||
throw new SetProtectedPropertyError(this, 'type', val) | ||
} | ||
_assertSlotNameUnique(slot) { | ||
@@ -67,2 +85,3 @@ if (this.slotNames.includes(slot.name)) { | ||
this.slots = [] | ||
if (slotsData) this._addSlotsByDataOrThrow(slotsData) | ||
@@ -75,2 +94,4 @@ } | ||
name: this.name, | ||
type: this.type, | ||
subType: this.subType, | ||
isVirtual: this.isVirtual, | ||
@@ -175,4 +196,6 @@ slots: this.slots.map(slot => slot.serialize()), | ||
isSubType(subType) { return this.subType === subType } | ||
} | ||
module.exports = Functionality |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const JOIous = require('../mixins/instanceMixins/JOIous') | ||
@@ -12,20 +10,2 @@ const Actuator = require('./Actuator') | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
subType: Joi.string().allow(HeaterActuator.SUB_TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(actuatorData) { | ||
super(actuatorData) | ||
this.subType = HeaterActuator.SUB_TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
subType: this.subType, | ||
} | ||
} | ||
} | ||
@@ -32,0 +12,0 @@ |
const FunctionalityFactory = require('./factories/FunctionalityFactory') | ||
// base type | ||
const Functionality = require('./Functionality') | ||
// types inherit from Functionality | ||
const Sensor = require('./Sensor') | ||
const Actuator = require('./Actuator') | ||
const Controller = require('./Controller') | ||
const InputNode = require('./InputNode') | ||
const OutputNode = require('./OutputNode') | ||
// sub-types which inherit from types | ||
const UnknownSensor = require('./UnknownSensor') | ||
const UnknownActuator = require('./UnknownActuator') | ||
const TemperatureSensor = require('./TemperatureSensor') | ||
const StirrerActuator = require('./StirrerActuator') | ||
const PumpActuator = require('./PumpActuator') | ||
const HeaterActuator = require('./HeaterActuator') | ||
@@ -14,7 +25,22 @@ const IntervalOut = require('./IntervalOut') | ||
// sub-types which inherit from other sub-types | ||
const HeidolphOverheadStirrer = require('./HeidolphOverheadStirrer') | ||
const HeidolphMagneticStirrer = require('./HeidolphMagneticStirrer') | ||
const HeidolphPump = require('./HeidolphPump') | ||
module.exports = { | ||
FunctionalityFactory, | ||
// base type | ||
Functionality, | ||
// types inherit from Functionality (invalid fcts) | ||
Sensor, | ||
Actuator, | ||
Controller, | ||
InputNode, | ||
OutputNode, | ||
// sub-types which inherit from types (valid fcts) | ||
StirrerActuator, | ||
PumpActuator, | ||
TemperatureSensor, | ||
@@ -28,2 +54,7 @@ UnknownSensor, | ||
PushIn, | ||
// sub-types which inherit from other sub-types (valid fcts) | ||
HeidolphOverheadStirrer, | ||
HeidolphMagneticStirrer, | ||
HeidolphPump, | ||
} |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const Functionality = require('./Functionality') | ||
@@ -11,8 +9,2 @@ | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
type: Joi.string().allow(InputNode.TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(functionalityData) { | ||
@@ -23,3 +15,2 @@ super({ | ||
}) | ||
this.type = InputNode.TYPE | ||
} | ||
@@ -29,9 +20,2 @@ | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
type: this.type, | ||
} | ||
} | ||
getSinkFct() { | ||
@@ -38,0 +22,0 @@ return super.sinks[0] |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const JOIous = require('../mixins/instanceMixins/JOIous') | ||
@@ -12,20 +10,2 @@ const OutputNode = require('./OutputNode') | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
subType: Joi.string().allow(IntervalOut.SUB_TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(outputNodeData) { | ||
super(outputNodeData) | ||
this.subType = IntervalOut.SUB_TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
subType: this.subType, | ||
} | ||
} | ||
} | ||
@@ -32,0 +12,0 @@ |
@@ -28,3 +28,2 @@ const Joi = require('joi') | ||
return Joi.object({ | ||
type: Joi.string().allow(OutputNode.TYPE).required(), | ||
destination: Joi.object({ | ||
@@ -41,3 +40,2 @@ name: Joi.string().allow(...OutputNode.VALID_DESTINATION_NAMES).required(), | ||
super({ isVirtual: true, ...functionalityData }) | ||
this.type = OutputNode.TYPE | ||
this.destination = destination | ||
@@ -51,3 +49,2 @@ } | ||
...super.serialize(), | ||
type: this.type, | ||
destination: this.destination, | ||
@@ -54,0 +51,0 @@ } |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const JOIous = require('../mixins/instanceMixins/JOIous') | ||
@@ -12,20 +10,2 @@ const Controller = require('./Controller') | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
subType: Joi.string().allow(PIDController.SUB_TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(controllerData) { | ||
super(controllerData) | ||
this.subType = PIDController.SUB_TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
subType: this.subType, | ||
} | ||
} | ||
} | ||
@@ -32,0 +12,0 @@ |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const JOIous = require('../mixins/instanceMixins/JOIous') | ||
@@ -12,20 +10,2 @@ const InputNode = require('./InputNode') | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
subType: Joi.string().allow(PushIn.SUB_TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(inputNodeData) { | ||
super(inputNodeData) | ||
this.subType = PushIn.SUB_TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
subType: this.subType, | ||
} | ||
} | ||
} | ||
@@ -32,0 +12,0 @@ |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const JOIous = require('../mixins/instanceMixins/JOIous') | ||
@@ -12,20 +10,2 @@ const OutputNode = require('./OutputNode') | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
subType: Joi.string().allow(PushOut.SUB_TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(outputNodeData) { | ||
super(outputNodeData) | ||
this.subType = PushOut.SUB_TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
subType: this.subType, | ||
} | ||
} | ||
} | ||
@@ -32,0 +12,0 @@ |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const Functionality = require('./Functionality') | ||
@@ -11,8 +9,2 @@ | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
type: Joi.string().allow(Sensor.TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(functionalityData) { | ||
@@ -23,14 +15,6 @@ super({ | ||
}) | ||
this.type = Sensor.TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
type: this.type, | ||
} | ||
} | ||
} | ||
module.exports = Sensor |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const JOIous = require('../mixins/instanceMixins/JOIous') | ||
@@ -12,20 +10,2 @@ const Sensor = require('./Sensor') | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
subType: Joi.string().allow(TemperatureSensor.TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(sensorData) { | ||
super(sensorData) | ||
this.subType = TemperatureSensor.SUB_TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
subType: this.subType, | ||
} | ||
} | ||
} | ||
@@ -32,0 +12,0 @@ |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const JOIous = require('../mixins/instanceMixins/JOIous') | ||
@@ -12,20 +10,2 @@ const Actuator = require('./Actuator') | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
subType: Joi.string().allow(UnknownActuator.TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(actuatorData) { | ||
super(actuatorData) | ||
this.subType = UnknownActuator.SUB_TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
subType: this.subType, | ||
} | ||
} | ||
} | ||
@@ -32,0 +12,0 @@ |
@@ -1,3 +0,1 @@ | ||
const Joi = require('joi') | ||
const JOIous = require('../mixins/instanceMixins/JOIous') | ||
@@ -12,20 +10,2 @@ const Sensor = require('./Sensor') | ||
static get SCHEMA() { | ||
return Joi.object({ | ||
subType: Joi.string().allow(UnknownSensor.TYPE).required(), | ||
}).concat(super.SCHEMA) | ||
} | ||
constructor(sensorData) { | ||
super(sensorData) | ||
this.subType = UnknownSensor.SUB_TYPE | ||
} | ||
serialize() { | ||
return { | ||
...super.serialize(), | ||
subType: this.subType, | ||
} | ||
} | ||
} | ||
@@ -32,0 +12,0 @@ |
@@ -19,3 +19,3 @@ const util = require('util') | ||
* - a Class.SCHEMA method which returns a JOI schema | ||
* - a .serialize method which returns an object | ||
* - a .serialize method which returns a plain old js object | ||
*/ | ||
@@ -22,0 +22,0 @@ |
@@ -0,2 +1,7 @@ | ||
// sub-types which inherit from types | ||
const UnknownSensorSeeder = require('./UnknownSensorSeeder') | ||
const UnknownActuatorSeeder = require('./UnknownActuatorSeeder') | ||
const TemperatureSensorSeeder = require('./TemperatureSensorSeeder') | ||
const StirrerActuatorSeeder = require('./StirrerActuatorSeeder') | ||
const PumpActuatorSeeder = require('./PumpActuatorSeeder') | ||
const HeaterActuatorSeeder = require('./HeaterActuatorSeeder') | ||
@@ -7,7 +12,15 @@ const IntervalOutSeeder = require('./IntervalOutSeeder') | ||
const PushInSeeder = require('./PushInSeeder') | ||
const UnknownSensorSeeder = require('./UnknownSensorSeeder') | ||
const UnknownActuatorSeeder = require('./UnknownActuatorSeeder') | ||
// sub-types which inherit from other sub-types | ||
const HeidolphOverheadStirrerSeeder = require('./HeidolphOverheadStirrerSeeder') | ||
const HeidolphMagneticStirrerSeeder = require('./HeidolphMagneticStirrerSeeder') | ||
const HeidolphPumpSeeder = require('./HeidolphPumpSeeder') | ||
module.exports = { | ||
// sub-types which inherit from types (valid fcts) | ||
StirrerActuatorSeeder, | ||
PumpActuatorSeeder, | ||
TemperatureSensorSeeder, | ||
UnknownSensorSeeder, | ||
UnknownActuatorSeeder, | ||
HeaterActuatorSeeder, | ||
@@ -18,4 +31,7 @@ IntervalOutSeeder, | ||
PushInSeeder, | ||
UnknownSensorSeeder, | ||
UnknownActuatorSeeder, | ||
// sub-types which inherit from other sub-types (valid fcts) | ||
HeidolphOverheadStirrerSeeder, | ||
HeidolphMagneticStirrerSeeder, | ||
HeidolphPumpSeeder, | ||
} |
@@ -11,2 +11,11 @@ const faker = require('faker') | ||
static get DISPLAY_TYPES() { | ||
return [ | ||
'temperature', | ||
'switch', | ||
'flow', | ||
'controller parameter', | ||
] | ||
} | ||
static get SEED_METHOD() { return SlotFactory.new } | ||
@@ -25,3 +34,3 @@ | ||
name: faker.animal.lion(), | ||
displayType: faker.random.arrayElement(Object.values(Slot.DISPLAY_TYPES)), | ||
displayType: faker.random.arrayElement(SlotSeeder.DISPLAY_TYPES), | ||
dataStreams: [], | ||
@@ -28,0 +37,0 @@ unit: faker.random.arrayElement(Slot.ALL_UNIT_VALUES), |
@@ -41,11 +41,2 @@ const Joi = require('joi') | ||
static get DISPLAY_TYPES() { | ||
return { | ||
TEMPERATURE: 'temperature', | ||
SWITCH: 'switch', | ||
FLOW: 'flow', | ||
CONTROLLER_PARAMETER: 'controller parameter', | ||
} | ||
} | ||
static _assertSlotDataTypesCompatible(slotA, slotB) { | ||
@@ -104,5 +95,5 @@ if (slotA.dataType !== slotB.dataType) { | ||
name: Joi.string().required(), | ||
displayType: Joi.string().allow(...Object.values(Slot.DISPLAY_TYPES), null).required(), | ||
displayType: Joi.string().allow(null).required(), | ||
dataStreams: Joi.array().items(DataStream.SCHEMA).required(), | ||
unit: Joi.string().allow(...this.ALL_UNIT_VALUES).required(), // inherited | ||
unit: Joi.string().allow(...this.ALL_UNIT_VALUES).required(), | ||
}) | ||
@@ -119,3 +110,3 @@ } | ||
this.functionality = functionality | ||
this.displayType = displayType | ||
this.displayType = displayType || null | ||
this.unit = unit | ||
@@ -122,0 +113,0 @@ this.dataStreams = [] |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
135041
95
2706
277