From dbc36c2f57fa108bd33511f6153c99292f4bdc79 Mon Sep 17 00:00:00 2001 From: znetsixe <73483679+znetsixe@users.noreply.github.com> Date: Thu, 12 Jun 2025 17:04:02 +0200 Subject: [PATCH] cleaned up method --- helper/assetUtils.js | 3 - helper/childRegistrationUtils.js | 243 -------- helper/configUtils.js | 94 ---- helper/logger.js | 57 -- helper/measurements/Measurement.js | 187 ------- helper/measurements/MeasurementBuilder.js | 56 -- helper/measurements/MeasurementContainer.js | 200 ------- helper/measurements/README.md | 89 --- helper/measurements/examples.js | 58 -- helper/measurements/index.js | 9 - helper/menuUtils.js | 489 ---------------- helper/nodeTemplates.js | 56 -- helper/nrmse/errorMetric.test.js | 297 ---------- helper/nrmse/errorMetrics.js | 154 ----- helper/nrmse/nrmseConfig.json | 138 ----- helper/outliers/outlierDetection.js | 89 --- helper/outputUtils.js | 132 ----- helper/state/movementManager.js | 277 --------- helper/state/state.js | 131 ----- helper/state/stateConfig.json | 331 ----------- helper/state/stateManager.js | 164 ------ helper/validationUtils.js | 528 ------------------ index.js | 8 +- src/convert/definitions/angle.js | 49 ++ src/convert/definitions/apparentPower.js | 49 ++ src/convert/definitions/area.js | 93 +++ src/convert/definitions/current.js | 35 ++ src/convert/definitions/digital.js | 93 +++ src/convert/definitions/each.js | 30 + src/convert/definitions/energy.js | 63 +++ src/convert/definitions/frequency.js | 78 +++ src/convert/definitions/illuminance.js | 37 ++ src/convert/definitions/length.js | 86 +++ src/convert/definitions/mass.js | 78 +++ src/convert/definitions/pace.js | 51 ++ src/convert/definitions/partsPer.js | 44 ++ src/convert/definitions/power.js | 49 ++ src/convert/definitions/pressure.js | 86 +++ src/convert/definitions/reactiveEnergy.js | 49 ++ src/convert/definitions/reactivePower.js | 49 ++ src/convert/definitions/speed.js | 58 ++ src/convert/definitions/temperature.js | 55 ++ src/convert/definitions/time.js | 86 +++ src/convert/definitions/voltage.js | 35 ++ src/convert/definitions/volume.js | 200 +++++++ src/convert/definitions/volumeFlowRate.js | 282 ++++++++++ src/convert/fysics.js | 160 ++++++ src/convert/index.js | 304 ++++++++++ .../lodash/lodash._basebind/LICENSE.txt | 22 + src/convert/lodash/lodash._basebind/README.md | 15 + src/convert/lodash/lodash._basebind/index.js | 58 ++ .../lodash/lodash._basebind/package.json | 21 + .../lodash/lodash._basecreate/LICENSE.txt | 22 + .../lodash/lodash._basecreate/README.md | 15 + .../lodash/lodash._basecreate/index.js | 42 ++ .../lodash/lodash._basecreate/package.json | 21 + .../lodash._basecreatecallback/LICENSE.txt | 22 + .../lodash._basecreatecallback/README.md | 15 + .../lodash._basecreatecallback/index.js | 80 +++ .../lodash._basecreatecallback/package.json | 22 + .../lodash._basecreatewrapper/LICENSE.txt | 22 + .../lodash._basecreatewrapper/README.md | 15 + .../lodash/lodash._basecreatewrapper/index.js | 78 +++ .../lodash._basecreatewrapper/package.json | 22 + .../lodash/lodash._createwrapper/LICENSE.txt | 22 + .../lodash/lodash._createwrapper/README.md | 15 + .../lodash/lodash._createwrapper/index.js | 98 ++++ .../lodash/lodash._createwrapper/package.json | 21 + .../lodash/lodash._objecttypes/LICENSE.txt | 22 + .../lodash/lodash._objecttypes/README.md | 15 + .../lodash/lodash._objecttypes/index.js | 20 + .../lodash/lodash._objecttypes/package.json | 16 + .../lodash/lodash._renative/LICENSE.txt | 22 + src/convert/lodash/lodash._renative/README.md | 15 + src/convert/lodash/lodash._renative/index.js | 23 + .../lodash/lodash._renative/package.json | 16 + .../lodash/lodash._setbinddata/LICENSE.txt | 22 + .../lodash/lodash._setbinddata/README.md | 15 + .../lodash/lodash._setbinddata/index.js | 43 ++ .../lodash/lodash._setbinddata/package.json | 20 + .../lodash/lodash._shimkeys/LICENSE.txt | 22 + src/convert/lodash/lodash._shimkeys/README.md | 15 + src/convert/lodash/lodash._shimkeys/index.js | 38 ++ .../lodash/lodash._shimkeys/package.json | 19 + src/convert/lodash/lodash._slice/LICENSE.txt | 22 + src/convert/lodash/lodash._slice/README.md | 15 + src/convert/lodash/lodash._slice/index.js | 38 ++ src/convert/lodash/lodash._slice/package.json | 16 + src/convert/lodash/lodash.bind/LICENSE.txt | 22 + src/convert/lodash/lodash.bind/README.md | 15 + src/convert/lodash/lodash.bind/index.js | 41 ++ src/convert/lodash/lodash.bind/package.json | 22 + src/convert/lodash/lodash.foreach/LICENSE.txt | 22 + src/convert/lodash/lodash.foreach/README.md | 15 + src/convert/lodash/lodash.foreach/index.js | 55 ++ .../lodash/lodash.foreach/package.json | 21 + src/convert/lodash/lodash.forown/LICENSE.txt | 22 + src/convert/lodash/lodash.forown/README.md | 15 + src/convert/lodash/lodash.forown/index.js | 50 ++ src/convert/lodash/lodash.forown/package.json | 22 + .../lodash/lodash.identity/LICENSE.txt | 22 + src/convert/lodash/lodash.identity/README.md | 15 + src/convert/lodash/lodash.identity/index.js | 28 + .../lodash/lodash.identity/package.json | 17 + .../lodash/lodash.isfunction/LICENSE.txt | 22 + .../lodash/lodash.isfunction/README.md | 15 + src/convert/lodash/lodash.isfunction/index.js | 27 + .../lodash/lodash.isfunction/package.json | 17 + .../lodash/lodash.isobject/LICENSE.txt | 22 + src/convert/lodash/lodash.isobject/README.md | 15 + src/convert/lodash/lodash.isobject/index.js | 39 ++ .../lodash/lodash.isobject/package.json | 20 + src/convert/lodash/lodash.keys/LICENSE.txt | 22 + src/convert/lodash/lodash.keys/README.md | 15 + src/convert/lodash/lodash.keys/index.js | 36 ++ src/convert/lodash/lodash.keys/package.json | 22 + src/convert/lodash/lodash.noop/LICENSE.txt | 22 + src/convert/lodash/lodash.noop/README.md | 15 + src/convert/lodash/lodash.noop/index.js | 26 + src/convert/lodash/lodash.noop/package.json | 17 + src/convert/lodash/lodash.support/LICENSE.txt | 22 + src/convert/lodash/lodash.support/README.md | 15 + src/convert/lodash/lodash.support/index.js | 40 ++ .../lodash/lodash.support/package.json | 20 + src/convert/percentError.js | 3 + src/helper/menuUtils.js | 166 ++++-- src/measurements/Measurement.js | 2 +- src/nrmse/errorMetrics.js | 2 +- src/state/state.js | 2 +- 129 files changed, 4258 insertions(+), 3841 deletions(-) delete mode 100644 helper/assetUtils.js delete mode 100644 helper/childRegistrationUtils.js delete mode 100644 helper/configUtils.js delete mode 100644 helper/logger.js delete mode 100644 helper/measurements/Measurement.js delete mode 100644 helper/measurements/MeasurementBuilder.js delete mode 100644 helper/measurements/MeasurementContainer.js delete mode 100644 helper/measurements/README.md delete mode 100644 helper/measurements/examples.js delete mode 100644 helper/measurements/index.js delete mode 100644 helper/menuUtils.js delete mode 100644 helper/nodeTemplates.js delete mode 100644 helper/nrmse/errorMetric.test.js delete mode 100644 helper/nrmse/errorMetrics.js delete mode 100644 helper/nrmse/nrmseConfig.json delete mode 100644 helper/outliers/outlierDetection.js delete mode 100644 helper/outputUtils.js delete mode 100644 helper/state/movementManager.js delete mode 100644 helper/state/state.js delete mode 100644 helper/state/stateConfig.json delete mode 100644 helper/state/stateManager.js delete mode 100644 helper/validationUtils.js create mode 100644 src/convert/definitions/angle.js create mode 100644 src/convert/definitions/apparentPower.js create mode 100644 src/convert/definitions/area.js create mode 100644 src/convert/definitions/current.js create mode 100644 src/convert/definitions/digital.js create mode 100644 src/convert/definitions/each.js create mode 100644 src/convert/definitions/energy.js create mode 100644 src/convert/definitions/frequency.js create mode 100644 src/convert/definitions/illuminance.js create mode 100644 src/convert/definitions/length.js create mode 100644 src/convert/definitions/mass.js create mode 100644 src/convert/definitions/pace.js create mode 100644 src/convert/definitions/partsPer.js create mode 100644 src/convert/definitions/power.js create mode 100644 src/convert/definitions/pressure.js create mode 100644 src/convert/definitions/reactiveEnergy.js create mode 100644 src/convert/definitions/reactivePower.js create mode 100644 src/convert/definitions/speed.js create mode 100644 src/convert/definitions/temperature.js create mode 100644 src/convert/definitions/time.js create mode 100644 src/convert/definitions/voltage.js create mode 100644 src/convert/definitions/volume.js create mode 100644 src/convert/definitions/volumeFlowRate.js create mode 100644 src/convert/fysics.js create mode 100644 src/convert/index.js create mode 100644 src/convert/lodash/lodash._basebind/LICENSE.txt create mode 100644 src/convert/lodash/lodash._basebind/README.md create mode 100644 src/convert/lodash/lodash._basebind/index.js create mode 100644 src/convert/lodash/lodash._basebind/package.json create mode 100644 src/convert/lodash/lodash._basecreate/LICENSE.txt create mode 100644 src/convert/lodash/lodash._basecreate/README.md create mode 100644 src/convert/lodash/lodash._basecreate/index.js create mode 100644 src/convert/lodash/lodash._basecreate/package.json create mode 100644 src/convert/lodash/lodash._basecreatecallback/LICENSE.txt create mode 100644 src/convert/lodash/lodash._basecreatecallback/README.md create mode 100644 src/convert/lodash/lodash._basecreatecallback/index.js create mode 100644 src/convert/lodash/lodash._basecreatecallback/package.json create mode 100644 src/convert/lodash/lodash._basecreatewrapper/LICENSE.txt create mode 100644 src/convert/lodash/lodash._basecreatewrapper/README.md create mode 100644 src/convert/lodash/lodash._basecreatewrapper/index.js create mode 100644 src/convert/lodash/lodash._basecreatewrapper/package.json create mode 100644 src/convert/lodash/lodash._createwrapper/LICENSE.txt create mode 100644 src/convert/lodash/lodash._createwrapper/README.md create mode 100644 src/convert/lodash/lodash._createwrapper/index.js create mode 100644 src/convert/lodash/lodash._createwrapper/package.json create mode 100644 src/convert/lodash/lodash._objecttypes/LICENSE.txt create mode 100644 src/convert/lodash/lodash._objecttypes/README.md create mode 100644 src/convert/lodash/lodash._objecttypes/index.js create mode 100644 src/convert/lodash/lodash._objecttypes/package.json create mode 100644 src/convert/lodash/lodash._renative/LICENSE.txt create mode 100644 src/convert/lodash/lodash._renative/README.md create mode 100644 src/convert/lodash/lodash._renative/index.js create mode 100644 src/convert/lodash/lodash._renative/package.json create mode 100644 src/convert/lodash/lodash._setbinddata/LICENSE.txt create mode 100644 src/convert/lodash/lodash._setbinddata/README.md create mode 100644 src/convert/lodash/lodash._setbinddata/index.js create mode 100644 src/convert/lodash/lodash._setbinddata/package.json create mode 100644 src/convert/lodash/lodash._shimkeys/LICENSE.txt create mode 100644 src/convert/lodash/lodash._shimkeys/README.md create mode 100644 src/convert/lodash/lodash._shimkeys/index.js create mode 100644 src/convert/lodash/lodash._shimkeys/package.json create mode 100644 src/convert/lodash/lodash._slice/LICENSE.txt create mode 100644 src/convert/lodash/lodash._slice/README.md create mode 100644 src/convert/lodash/lodash._slice/index.js create mode 100644 src/convert/lodash/lodash._slice/package.json create mode 100644 src/convert/lodash/lodash.bind/LICENSE.txt create mode 100644 src/convert/lodash/lodash.bind/README.md create mode 100644 src/convert/lodash/lodash.bind/index.js create mode 100644 src/convert/lodash/lodash.bind/package.json create mode 100644 src/convert/lodash/lodash.foreach/LICENSE.txt create mode 100644 src/convert/lodash/lodash.foreach/README.md create mode 100644 src/convert/lodash/lodash.foreach/index.js create mode 100644 src/convert/lodash/lodash.foreach/package.json create mode 100644 src/convert/lodash/lodash.forown/LICENSE.txt create mode 100644 src/convert/lodash/lodash.forown/README.md create mode 100644 src/convert/lodash/lodash.forown/index.js create mode 100644 src/convert/lodash/lodash.forown/package.json create mode 100644 src/convert/lodash/lodash.identity/LICENSE.txt create mode 100644 src/convert/lodash/lodash.identity/README.md create mode 100644 src/convert/lodash/lodash.identity/index.js create mode 100644 src/convert/lodash/lodash.identity/package.json create mode 100644 src/convert/lodash/lodash.isfunction/LICENSE.txt create mode 100644 src/convert/lodash/lodash.isfunction/README.md create mode 100644 src/convert/lodash/lodash.isfunction/index.js create mode 100644 src/convert/lodash/lodash.isfunction/package.json create mode 100644 src/convert/lodash/lodash.isobject/LICENSE.txt create mode 100644 src/convert/lodash/lodash.isobject/README.md create mode 100644 src/convert/lodash/lodash.isobject/index.js create mode 100644 src/convert/lodash/lodash.isobject/package.json create mode 100644 src/convert/lodash/lodash.keys/LICENSE.txt create mode 100644 src/convert/lodash/lodash.keys/README.md create mode 100644 src/convert/lodash/lodash.keys/index.js create mode 100644 src/convert/lodash/lodash.keys/package.json create mode 100644 src/convert/lodash/lodash.noop/LICENSE.txt create mode 100644 src/convert/lodash/lodash.noop/README.md create mode 100644 src/convert/lodash/lodash.noop/index.js create mode 100644 src/convert/lodash/lodash.noop/package.json create mode 100644 src/convert/lodash/lodash.support/LICENSE.txt create mode 100644 src/convert/lodash/lodash.support/README.md create mode 100644 src/convert/lodash/lodash.support/index.js create mode 100644 src/convert/lodash/lodash.support/package.json create mode 100644 src/convert/percentError.js diff --git a/helper/assetUtils.js b/helper/assetUtils.js deleted file mode 100644 index 2155549..0000000 --- a/helper/assetUtils.js +++ /dev/null @@ -1,3 +0,0 @@ -export function getAssetVariables() { - -} \ No newline at end of file diff --git a/helper/childRegistrationUtils.js b/helper/childRegistrationUtils.js deleted file mode 100644 index a7181a0..0000000 --- a/helper/childRegistrationUtils.js +++ /dev/null @@ -1,243 +0,0 @@ -// ChildRegistrationUtils.js -class ChildRegistrationUtils { - constructor(mainClass) { - this.mainClass = mainClass; // Reference to the main class - this.logger = mainClass.logger; - } - - async registerChild(child, positionVsParent) { - const { softwareType } = child.config.functionality; - const { name, id, unit } = child.config.general; - const { type = "", subType = "" } = child.config.asset || {}; - const emitter = child.emitter; - - //define position vs parent in child - child.positionVsParent = positionVsParent; - child.parent = this.mainClass; - - if (!this.mainClass.child) this.mainClass.child = {}; - if (!this.mainClass.child[softwareType]) - this.mainClass.child[softwareType] = {}; - if (!this.mainClass.child[softwareType][type]) - this.mainClass.child[softwareType][type] = {}; - if (!this.mainClass.child[softwareType][type][subType]) - this.mainClass.child[softwareType][type][subType] = {}; - - // Use an array to handle multiple subtypes - if (!Array.isArray(this.mainClass.child[softwareType][type][subType])) { - this.mainClass.child[softwareType][type][subType] = []; - } - - // Update the child in the cloud when available and supply the new child on base of tagcode OLIFANT WE NEED TO FIX THIS SO ITS DYNAMIC! - /* - try{ - const url = "https://pimmoerman.nl/rdlab/tagcode.app/v2.1/api/asset/create_asset.php?"; - const TagCode = child.config.asset.tagCode; - //console.log(`Register child => ${TagCode}`); - const completeURL = url + `asset_product_model_id=1&asset_product_model_uuid=123456789&asset_name=AssetNaam&asset_description=Beschrijving&asset_status=actief&asset_profile_id=1&asset_location_id=1&asset_process_id=11&asset_tag_number=${TagCode}&child_assets=[L6616]`; - - await fetch(completeURL, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - } - }); - - }catch(e){ - console.log("Error saving assetID and tagnumber", e); - }*/ - - // Push the new child to the array of the mainclass so we can track the childs - this.mainClass.child[softwareType][type][subType].push({ - name, - id, - unit, - emitter, - }); - - //then connect the child depending on the type subtype etc.. - this.connectChild( - id, - softwareType, - emitter, - type, - child, - subType, - positionVsParent - ); - } - - connectChild( - id, - softwareType, - emitter, - type, - child, - subType, - positionVsParent - ) { - this.logger.debug( - `Connecting child id=${id}: desc=${softwareType}, type=${type},subType=${subType}, position=${positionVsParent}` - ); - - switch (softwareType) { - case "measurement": - this.logger.debug( - `Registering measurement child: ${id} with type=${type}` - ); - this.connectMeasurement(child, subType, positionVsParent); - break; - - case "machine": - this.logger.debug(`Registering complete machine child: ${id}`); - this.connectMachine(child); - break; - - case "valve": - this.logger.debug(`Registering complete valve child: ${id}`); - this.connectValve(child); - break; - - case "actuator": - this.logger.debug(`Registering linear actuator child: ${id}`); - this.connectActuator(child,positionVsParent); - break; - - default: - this.logger.error(`Child registration unrecognized desc: ${desc}`); - this.logger.error(`Unrecognized softwareType: ${softwareType}`); - } - } - - connectMeasurement(child, subType, position) { - this.logger.debug( - `Connecting measurement child: ${subType} with position=${position}` - ); - - // Check if subType is valid - if (!subType) { - this.logger.error(`Invalid subType for measurement: ${subType}`); - return; - } - - // initialize the measurement to a number - logging each step for debugging - try { - this.logger.debug( - `Initializing measurement: ${subType}, position: ${position} value: 0` - ); - const typeResult = this.mainClass.measurements.type(subType); - const variantResult = typeResult.variant("measured"); - const positionResult = variantResult.position(position); - positionResult.value(0); - - this.logger.debug( - `Subscribing on mAbs event for measurement: ${subType}, position: ${position}` - ); - // Listen for the mAbs event and update the measurement - - this.logger.debug( - `Successfully initialized measurement: ${subType}, position: ${position}` - ); - } catch (error) { - this.logger.error(`Failed to initialize measurement: ${error.message}`); - return; - } - - child.emitter.on("mAbs", (value) => { - // Use the same method chaining approach that worked during initialization - this.mainClass.measurements - .type(subType) - .variant("measured") - .position(position) - .value(value); - this.mainClass.updateMeasurement("measured", subType, value, position); - //this.logger.debug(`--------->>>>>>>>>Updated measurement: ${subType}, value: ${value}, position: ${position}`); - }); - } - - connectMachine(machine) { - if (!machine) { - this.logger.error("Invalid machine provided."); - return; - } - - const machineId = Object.keys(this.mainClass.machines).length + 1; - this.mainClass.machines[machineId] = machine; - - this.logger.info( - `Setting up pressureChange listener for machine ${machineId}` - ); - - machine.emitter.on("pressureChange", () => - this.mainClass.handlePressureChange(machine) - ); - - //update of child triggers the handler - this.mainClass.handleChildChange(); - - this.logger.info(`Machine ${machineId} registered successfully.`); - } - - connectValve(valve) { - if (!valve) { - this.logger.warn("Invalid valve provided."); - return; - } - const valveId = Object.keys(this.mainClass.valves).length + 1; - this.mainClass.valves[valveId] = valve; // Gooit valve object in de valves attribute met valve objects - - valve.state.emitter.on("positionChange", (data) => { - //ValveGroupController abboneren op klepstand verandering - this.mainClass.logger.debug(`Position change of valve detected: ${data}`); - this.mainClass.calcValveFlows(); - }); //bepaal nieuwe flow per valve - valve.emitter.on("deltaPChange", () => { - this.mainClass.logger.debug("DeltaP change of valve detected"); - this.mainClass.calcMaxDeltaP(); - }); //bepaal nieuwe max deltaP - - this.logger.info(`Valve ${valveId} registered successfully.`); - } - - connectActuator(actuator, positionVsParent) { - if (!actuator) { - this.logger.warn("Invalid actuator provided."); - return; - } - - //Special case gateGroupControl - if ( - this.mainClass.config.functionality.softwareType == "gateGroupControl" - ) { - if (Object.keys(this.mainClass.actuators).length < 2) { - if (positionVsParent == "downstream") { - this.mainClass.actuators[0] = actuator; - } - - if (positionVsParent == "upstream") { - this.mainClass.actuators[1] = actuator; - } - //define emitters - actuator.state.emitter.on("positionChange", (data) => { - this.mainClass.logger.debug(`Position change of actuator detected: ${data}`); - this.mainClass.eventUpdate(); - }); - - //define emitters - actuator.state.emitter.on("stateChange", (data) => { - this.mainClass.logger.debug(`State change of actuator detected: ${data}`); - this.mainClass.eventUpdate(); - }); - - } else { - this.logger.error( - "Too many actuators registered. Only two are allowed." - ); - } - } - } - - //wanneer hij deze ontvangt is deltaP van een van de valves veranderd (kan ook zijn niet child zijn, maar dat maakt niet uit) -} - -module.exports = ChildRegistrationUtils; diff --git a/helper/configUtils.js b/helper/configUtils.js deleted file mode 100644 index e81d1d5..0000000 --- a/helper/configUtils.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @file configUtils.js - * - * Permission is hereby granted to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to use it for personal - * or non-commercial purposes, with the following restrictions: - * - * 1. **No Copying or Redistribution**: The Software or any of its parts may not - * be copied, merged, distributed, sublicensed, or sold without explicit - * prior written permission from the author. - * - * 2. **Commercial Use**: Any use of the Software for commercial purposes requires - * a valid license, obtainable only with the explicit consent of the author. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, - * OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Ownership of this code remains solely with the original author. Unauthorized - * use of this Software is strictly prohibited. - * - * @summary Utility for managing and validating configuration values. - * @description Utility for managing and validating configuration values. - * @module ConfigUtils - * @requires ValidationUtils - * @requires Logger - * @exports ConfigUtils - * @version 0.1.0 - * @since 0.1.0 - */ - - -const ValidationUtils = require("./validationUtils"); -const Logger = require("./logger"); - -class ConfigUtils { - constructor(defaultConfig, IloggerEnabled , IloggerLevel) { - const loggerEnabled = IloggerEnabled || true; - const loggerLevel = IloggerLevel || "warn"; - this.logger = new Logger(loggerEnabled, loggerLevel, 'ConfigUtils'); - this.defaultConfig = defaultConfig; - this.validationUtils = new ValidationUtils(loggerEnabled, loggerLevel); - } - - // Initialize configuration - initConfig(config) { - this.logger.info("Initializing configuration..."); - - // Validate the provided configuration - const validatedConfig = this.validationUtils.validateSchema(config, this.defaultConfig, this.defaultConfig.functionality.softwareType.default); - - this.logger.info("Configuration initialized successfully."); - - return validatedConfig; - } - - - // Update configuration - updateConfig(currentConfig, newConfig) { - this.logger.info("Updating configuration..."); - - // Merge 2 configs and validate the result - const mergedConfig = this.mergeObjects(currentConfig, newConfig); - - // Merge current configuration with new values - const updatedConfig = this.validationUtils.validateSchema(mergedConfig, this.defaultConfig, this.defaultConfig.functionality.softwareType.default); - - this.logger.info("Configuration updated successfully."); - return updatedConfig; - } - - // loop through objects and merge them obj1 will be updated with obj2 values - mergeObjects(obj1, obj2) { - for (let key in obj2) { - if (obj2.hasOwnProperty(key)) { - if (typeof obj2[key] === 'object') { - if (!obj1[key]) { - obj1[key] = {}; - } - this.mergeObjects(obj1[key], obj2[key]); - } else { - obj1[key] = obj2[key]; - } - } - } - return obj1; - } -} - -module.exports = ConfigUtils; diff --git a/helper/logger.js b/helper/logger.js deleted file mode 100644 index 8b4f696..0000000 --- a/helper/logger.js +++ /dev/null @@ -1,57 +0,0 @@ -class Logger { - constructor(logging = true, logLevel = 'debug', nameModule = 'N/A') { - this.logging = logging; // Boolean flag to enable/disable logging - this.logLevel = logLevel; // Default log level: 'debug', 'info', 'warn', 'error' - this.levels = ['debug', 'info', 'warn', 'error']; // Log levels in order of severity - this.nameModule = nameModule; // Name of the module that uses the logger - } - - // Helper function to check if a log message should be displayed based on current log level - shouldLog(level) { - return this.levels.indexOf(level) >= this.levels.indexOf(this.logLevel); - } - - // Log a debug message - debug(message) { - if (this.logging && this.shouldLog('debug')) { - console.debug(`[DEBUG] -> ${this.nameModule}: ${message}`); - } - } - - // Log an info message - info(message) { - if (this.logging && this.shouldLog('info')) { - console.info(`[INFO] -> ${this.nameModule}: ${message}`); - } - } - - // Log a warning message - warn(message) { - if (this.logging && this.shouldLog('warn')) { - console.warn(`[WARN] -> ${this.nameModule}: ${message}`); - } - } - - // Log an error message - error(message) { - if (this.logging && this.shouldLog('error')) { - console.error(`[ERROR] -> ${this.nameModule}: ${message}`); - } - } - - // Set the log level dynamically - setLogLevel(level) { - if (this.levels.includes(level)) { - this.logLevel = level; - } else { - console.error(`[ERROR ${nameModule}]: Invalid log level: ${level}`); - } - } - - // Toggle the logging on or off - toggleLogging() { - this.logging = !this.logging; - } - } - - module.exports = Logger; \ No newline at end of file diff --git a/helper/measurements/Measurement.js b/helper/measurements/Measurement.js deleted file mode 100644 index f9882b5..0000000 --- a/helper/measurements/Measurement.js +++ /dev/null @@ -1,187 +0,0 @@ -// Add unit conversion support -const convertModule = require('../../../convert/dependencies/index'); - -class Measurement { - constructor(type, variant, position, windowSize) { - this.type = type; // e.g. 'pressure', 'flow', etc. - this.variant = variant; // e.g. 'predicted' or 'measured', etc.. - this.position = position; // Downstream or upstream of parent object - this.windowSize = windowSize; // Rolling window size - - // Place all data inside an array - this.values = []; // Array to store all values - this.timestamps = []; // Array to store all timestamps - - // Unit tracking - this.unit = null; // Current unit of measurement - - // For tracking differences if this is a calculated difference measurement - this.isDifference = false; - this.sourcePositions = []; - } - - // -- Updater methods -- - setType(type) { - this.type = type; - return this; - } - - setVariant(variant) { - this.variant = variant; - return this; - } - - setPosition(position) { - this.position = position; - return this; - } - - setValue(value, timestamp = Date.now()) { - /* - if (value === undefined || value === null) { - value = null ; - //throw new Error('Value cannot be null or undefined'); - } - */ - - //shift the oldest value - if(this.values.length >= this.windowSize){ - this.values.shift(); - this.timestamps.shift(); - } - - //push the new value - this.values.push(value); - this.timestamps.push(timestamp); - - return this; - } - - setUnit(unit) { - this.unit = unit; - return this; - } - - // -- Getter methods -- - getCurrentValue() { - if (this.values.length === 0) return null; - return this.values[this.values.length - 1]; - } - - getAverage() { - if (this.values.length === 0) return null; - const sum = this.values.reduce((acc, val) => acc + val, 0); - return sum / this.values.length; - } - - getMin() { - if (this.values.length === 0) return null; - return Math.min(...this.values); - } - - getMax() { - if (this.values.length === 0) return null; - return Math.max(...this.values); - } - - getAllValues() { - return { - values: [...this.values], - timestamps: [...this.timestamps], - unit: this.unit - }; - } - - // -- Position-based methods -- - - // Create a new measurement that is the difference between two positions - static createDifference(upstreamMeasurement, downstreamMeasurement) { - console.log('hello:'); - if (upstreamMeasurement.type !== downstreamMeasurement.type || - upstreamMeasurement.variant !== downstreamMeasurement.variant) { - throw new Error('Cannot calculate difference between different measurement types or variants'); - } - - // Ensure units match - let downstream = downstreamMeasurement; - if (upstreamMeasurement.unit && downstream.unit && - upstreamMeasurement.unit !== downstream.unit) { - downstream = downstream.convertTo(upstreamMeasurement.unit); - } - - // Create a new difference measurement - const diffMeasurement = new Measurement( - upstreamMeasurement.type, - upstreamMeasurement.variant, - 'difference', - Math.min(upstreamMeasurement.windowSize, downstream.windowSize) - ); - - // Mark as a difference measurement and keep track of sources - diffMeasurement.isDifference = true; - diffMeasurement.sourcePositions = ['upstream', 'downstream']; - - // Calculate all differences where timestamps match - const upValues = upstreamMeasurement.getAllValues(); - const downValues = downstream.getAllValues(); - - // Match timestamps and calculate differences - for (let i = 0; i < upValues.timestamps.length; i++) { - const upTimestamp = upValues.timestamps[i]; - const downIndex = downValues.timestamps.indexOf(upTimestamp); - - if (downIndex !== -1) { - - const diff = upValues.values[i] - downValues.values[downIndex]; - diffMeasurement.setValue(diff, upTimestamp); - } - } - - diffMeasurement.setUnit(upstreamMeasurement.unit); - - return diffMeasurement; - } - - // -- Additional getter methods -- - getLatestTimestamp() { - if (this.timestamps.length === 0) return null; - return this.timestamps[this.timestamps.length - 1]; - } - - getValueAtTimestamp(timestamp) { - const index = this.timestamps.indexOf(timestamp); - if (index === -1) return null; - return this.values[index]; - } - - // -- Unit conversion methods -- - convertTo(targetUnit) { - if (!this.unit) { - throw new Error('Current unit not set, cannot convert'); - } - - try { - const convertedValues = this.values.map(value => - convertModule.convert(value).from(this.unit).to(targetUnit) - ); - - const newMeasurement = new Measurement( - this.type, - this.variant, - this.position, - this.windowSize - ); - - // Copy values and timestamps - newMeasurement.values = convertedValues; - newMeasurement.timestamps = [...this.timestamps]; - newMeasurement.unit = targetUnit; - - return newMeasurement; - } catch (error) { - throw new Error(`Unit conversion failed: ${error.message}`); - } - } -} - -module.exports = Measurement; diff --git a/helper/measurements/MeasurementBuilder.js b/helper/measurements/MeasurementBuilder.js deleted file mode 100644 index af95d05..0000000 --- a/helper/measurements/MeasurementBuilder.js +++ /dev/null @@ -1,56 +0,0 @@ -const Measurement = require('./Measurement'); - -class MeasurementBuilder { - constructor() { - this.type = null; - this.variant = null; - this.position = null; - this.windowSize = 10; // Default window size - } - - // e.g. 'pressure', 'flow', etc. - setType(type) { - this.type = type; - return this; - } - - // e.g. 'predicted' or 'measured', etc.. - setVariant(variant) { - this.variant = variant; - return this; - } - - // Downstream or upstream of parent object - setPosition(position) { - this.position = position; - return this; - } - - // default size of the data that gets tracked - setWindowSize(windowSize) { - this.windowSize = windowSize; - return this; - } - - build() { - // Validate required fields - if (!this.type) { - throw new Error('Measurement type is required'); - } - if (!this.variant) { - throw new Error('Measurement variant is required'); - } - if (!this.position) { - throw new Error('Measurement position is required'); - } - - return new Measurement( - this.type, - this.variant, - this.position, - this.windowSize - ); - } -} - -module.exports = MeasurementBuilder; diff --git a/helper/measurements/MeasurementContainer.js b/helper/measurements/MeasurementContainer.js deleted file mode 100644 index 95cf168..0000000 --- a/helper/measurements/MeasurementContainer.js +++ /dev/null @@ -1,200 +0,0 @@ -const MeasurementBuilder = require('./MeasurementBuilder'); - -class MeasurementContainer { - constructor(options = {}, logger) { - this.logger = logger; - this.measurements = {}; - this.windowSize = options.windowSize || 10; // Default window size - - // For chaining context - this._currentType = null; - this._currentVariant = null; - this._currentPosition = null; - } - - // Chainable methods - type(typeName) { - this._currentType = typeName; - this._currentVariant = null; - this._currentPosition = null; - return this; - } - - variant(variantName) { - if (!this._currentType) { - throw new Error('Type must be specified before variant'); - } - this._currentVariant = variantName; - this._currentPosition = null; - return this; - } - - position(positionName) { - if (!this._currentVariant) { - throw new Error('Variant must be specified before position'); - } - this._currentPosition = positionName; - return this; - } - - // Core methods that complete the chain - value(val, timestamp = Date.now()) { - if (!this._ensureChainIsValid()) return this; - - const measurement = this._getOrCreateMeasurement(); - measurement.setValue(val, timestamp); - return this; - } - - unit(unitName) { - if (!this._ensureChainIsValid()) return this; - - const measurement = this._getOrCreateMeasurement(); - measurement.setUnit(unitName); - return this; - } - - // Terminal operations - get data out - get() { - if (!this._ensureChainIsValid()) return null; - return this._getOrCreateMeasurement(); - } - - getCurrentValue() { - const measurement = this.get(); - return measurement ? measurement.getCurrentValue() : null; - } - - getAverage() { - const measurement = this.get(); - return measurement ? measurement.getAverage() : null; - } - - getMin() { - const measurement = this.get(); - return measurement ? measurement.getMin() : null; - } - - getMax() { - const measurement = this.get(); - return measurement ? measurement.getMax() : null; - } - - getAllValues() { - const measurement = this.get(); - return measurement ? measurement.getAllValues() : null; - } - - // Difference calculations between positions - difference() { - if (!this._currentType || !this._currentVariant) { - throw new Error('Type and variant must be specified for difference calculation'); - } - - // Save position to restore chain state after operation - const savedPosition = this._currentPosition; - - // Get upstream measurement - this._currentPosition = 'upstream'; - const upstream = this.get(); - - // Get downstream measurement - this._currentPosition = 'downstream'; - const downstream = this.get(); - - // Restore chain state - this._currentPosition = savedPosition; - - if (!upstream || !downstream || upstream.values.length === 0 || downstream.values.length === 0) { - return null; - } - - // Ensure units match - let downstreamForCalc = downstream; - if (upstream.unit && downstream.unit && upstream.unit !== downstream.unit) { - try { - downstreamForCalc = downstream.convertTo(upstream.unit); - } catch (error) { - if (this.logger) { - this.logger.error(`Unit conversion failed: ${error.message}`); - } - return null; - } - } - - return { - value: downstreamForCalc.getCurrentValue() - upstream.getCurrentValue() , - avgDiff: downstreamForCalc.getAverage() - upstream.getAverage() , - unit: upstream.unit - }; - } - - // Helper methods - _ensureChainIsValid() { - if (!this._currentType || !this._currentVariant || !this._currentPosition) { - if (this.logger) { - this.logger.error('Incomplete measurement chain, required: type, variant, and position'); - } - return false; - } - return true; - } - - _getOrCreateMeasurement() { - // Initialize nested structure if needed - if (!this.measurements[this._currentType]) { - this.measurements[this._currentType] = {}; - } - - if (!this.measurements[this._currentType][this._currentVariant]) { - this.measurements[this._currentType][this._currentVariant] = {}; - } - - if (!this.measurements[this._currentType][this._currentVariant][this._currentPosition]) { - this.measurements[this._currentType][this._currentVariant][this._currentPosition] = - new MeasurementBuilder() - .setType(this._currentType) - .setVariant(this._currentVariant) - .setPosition(this._currentPosition) - .setWindowSize(this.windowSize) - .build(); - } - - return this.measurements[this._currentType][this._currentVariant][this._currentPosition]; - } - - // Additional utility methods - getTypes() { - return Object.keys(this.measurements); - } - - getVariants() { - if (!this._currentType) { - throw new Error('Type must be specified before listing variants'); - } - return this.measurements[this._currentType] ? - Object.keys(this.measurements[this._currentType]) : []; - } - - getPositions() { - if (!this._currentType || !this._currentVariant) { - throw new Error('Type and variant must be specified before listing positions'); - } - - if (!this.measurements[this._currentType] || - !this.measurements[this._currentType][this._currentVariant]) { - return []; - } - - return Object.keys(this.measurements[this._currentType][this._currentVariant]); - } - - clear() { - this.measurements = {}; - this._currentType = null; - this._currentVariant = null; - this._currentPosition = null; - } -} - -module.exports = MeasurementContainer; diff --git a/helper/measurements/README.md b/helper/measurements/README.md deleted file mode 100644 index b5f16ae..0000000 --- a/helper/measurements/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# Measurement System Documentation - -This system provides a flexible way to store, retrieve, and analyze measurement data using a chainable API. - -## Basic Usage - -```javascript -const { MeasurementContainer } = require('./index'); -const container = new MeasurementContainer({ windowSize: 20 }); - -// Set values -container.type('pressure').variant('measured').position('upstream').value(100).unit('psi'); - -// Get values -const upstreamPressure = container.type('pressure').variant('measured').position('upstream').getCurrentValue(); -console.log(`Upstream pressure: ${upstreamPressure}`); -``` - -## Chainable API Methods - -### Setting Context -- `type(typeName)` - Set the measurement type (pressure, flow, etc.) -- `variant(variantName)` - Set the variant (measured, predicted, etc.) -- `position(positionName)` - Set the position (upstream, downstream, etc.) - -### Setting Data -- `value(val, [timestamp])` - Add a value with optional timestamp -- `unit(unitName)` - Set the measurement unit - -### Getting Data -- `get()` - Get the measurement object -- `getCurrentValue()` - Get the most recent value -- `getAverage()` - Calculate average of all values -- `getMin()` - Get minimum value -- `getMax()` - Get maximum value - -### Calculations -- `difference()` - Calculate difference between upstream and downstream positions - -### Listing Available Data -- `getTypes()` - Get all measurement types -- `listVariants()` - List variants for current type -- `listPositions()` - List positions for current type and variant - -## Example Workflows - -### Setting and retrieving values -```javascript -// Set a measurement -container.type('flow') - .variant('measured') - .position('upstream') - .value(120) - .unit('gpm'); - -// Retrieve the same measurement -const flow = container.type('flow') - .variant('measured') - .position('upstream') - .getCurrentValue(); -``` - -### Calculating differences -```javascript -// Set upstream and downstream measurements -container.type('pressure').variant('measured').position('upstream').value(100).unit('psi'); -container.type('pressure').variant('measured').position('downstream').value(95).unit('psi'); - -// Calculate the difference -const diff = container.type('pressure').variant('measured').difference(); -console.log(`Pressure drop: ${diff.currentDiff} ${diff.unit}`); -``` - -### Working with historical data -```javascript -// Add multiple values -container.type('temperature') - .variant('measured') - .position('outlet') - .value(72) - .value(74) - .value(73) - .unit('F'); - -// Get statistics -const avg = container.type('temperature').variant('measured').position('outlet').getAverage(); -const min = container.type('temperature').variant('measured').position('outlet').getMin(); -const max = container.type('temperature').variant('measured').position('outlet').getMax(); -``` diff --git a/helper/measurements/examples.js b/helper/measurements/examples.js deleted file mode 100644 index 2c69c63..0000000 --- a/helper/measurements/examples.js +++ /dev/null @@ -1,58 +0,0 @@ -const { MeasurementContainer } = require('./index'); - -// Create a container -const container = new MeasurementContainer({ windowSize: 20 }); - -// Example 1: Setting values with chaining -console.log('--- Example 1: Setting values ---'); -container.type('pressure').variant('measured').position('upstream').value(100).unit('psi'); -container.type('pressure').variant('measured').position('downstream').value(95).unit('psi'); -container.type('pressure').variant('measured').position('downstream').value(80); - -// Example 2: Getting values with chaining -console.log('--- Example 2: Getting values ---'); -const upstreamValue = container.type('pressure').variant('measured').position('upstream').getCurrentValue(); -const upstreamUnit = container.type('pressure').variant('measured').position('upstream').get().unit; -console.log(`Upstream pressure: ${upstreamValue} ${upstreamUnit}`); -const downstreamValue = container.type('pressure').variant('measured').position('downstream').getCurrentValue(); -const downstreamUnit = container.type('pressure').variant('measured').position('downstream').get().unit; -console.log(`Downstream pressure: ${downstreamValue} ${downstreamUnit}`); - -// Example 3: Calculations using chained methods -console.log('--- Example 3: Calculations ---'); -container.type('flow').variant('predicted').position('upstream').value(200).unit('gpm'); -container.type('flow').variant('predicted').position('downstream').value(195).unit('gpm'); - -const flowAvg = container.type('flow').variant('predicted').position('upstream').getAverage(); -console.log(`Average upstream flow: ${flowAvg} gpm`); - -// Example 4: Getting pressure difference -console.log('--- Example 4: Difference calculations ---'); -const pressureDiff = container.type('pressure').variant('measured').difference(); -console.log(`Pressure difference: ${pressureDiff.value} ${pressureDiff.unit}`); - -// Example 5: Adding multiple values to track history -console.log('--- Example 5: Multiple values ---'); -// Add several values to upstream flow -container.type('flow').variant('measured').position('upstream') - .value(210).value(215).value(205).unit('gpm'); - -// Then get statistics -console.log('Flow statistics:'); -console.log(`- Current: ${container.type('flow').variant('measured').position('upstream').getCurrentValue()} gpm`); -console.log(`- Average: ${container.type('flow').variant('measured').position('upstream').getAverage()} gpm`); -console.log(`- Min: ${container.type('flow').variant('measured').position('upstream').getMin()} gpm`); -console.log(`- Max: ${container.type('flow').variant('measured').position('upstream').getMax()} gpm`); -console.log(`Show all values : ${JSON.stringify(container.type('flow').variant('measured').position('upstream').getAllValues())}`); - -// Example 6: Listing available data -console.log('--- Example 6: Listing available data ---'); -console.log('Types:', container.getTypes()); -console.log('Pressure variants:', container.type('pressure').getVariants()); -console.log('Measured pressure positions:', container.type('pressure').variant('measured').getPositions()); - -module.exports = { - runExamples: () => { - console.log('Examples of the measurement chainable API'); - } -}; diff --git a/helper/measurements/index.js b/helper/measurements/index.js deleted file mode 100644 index 68fbcb6..0000000 --- a/helper/measurements/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const MeasurementContainer = require('./MeasurementContainer'); -const Measurement = require('./Measurement'); -const MeasurementBuilder = require('./MeasurementBuilder'); - -module.exports = { - MeasurementContainer, - Measurement, - MeasurementBuilder -}; diff --git a/helper/menuUtils.js b/helper/menuUtils.js deleted file mode 100644 index 17d2a24..0000000 --- a/helper/menuUtils.js +++ /dev/null @@ -1,489 +0,0 @@ -class MenuUtils { - -initBasicToggles(elements) { - // Toggle visibility for log level - elements.logCheckbox.addEventListener("change", function () { - elements.rowLogLevel.style.display = this.checked ? "block" : "none"; - }); - elements.rowLogLevel.style.display = elements.logCheckbox.checked - ? "block" - : "none"; -} - -// Define the initialize toggles function within scope -initMeasurementToggles(elements) { - // Toggle visibility for scaling inputs - elements.scalingCheckbox.addEventListener("change", function () { - elements.rowInputMin.style.display = this.checked ? "block" : "none"; - elements.rowInputMax.style.display = this.checked ? "block" : "none"; - }); - - // Set initial states - elements.rowInputMin.style.display = elements.scalingCheckbox.checked - ? "block" - : "none"; - elements.rowInputMax.style.display = elements.scalingCheckbox.checked - ? "block" - : "none"; -} - -initTensionToggles(elements, node) { - const currentMethod = node.interpolationMethod; - elements.rowTension.style.display = - currentMethod === "monotone_cubic_spline" ? "block" : "none"; - console.log( - "Initial tension row display: ", - elements.rowTension.style.display - ); - - elements.interpolationMethodInput.addEventListener("change", function () { - const selectedMethod = this.value; - console.log(`Interpolation method changed: ${selectedMethod}`); - node.interpolationMethod = selectedMethod; - - // Toggle visibility for tension input - elements.rowTension.style.display = - selectedMethod === "monotone_cubic_spline" ? "block" : "none"; - console.log("Tension row display: ", elements.rowTension.style.display); - }); -} -// Define the smoothing methods population function within scope -populateSmoothingMethods(configUrls, elements, node) { - this.fetchData(configUrls.cloud.config, configUrls.local.config) - .then((configData) => { - const smoothingMethods = - configData.smoothing?.smoothMethod?.rules?.values?.map( - (o) => o.value - ) || []; - this.populateDropdown( - elements.smoothMethod, - smoothingMethods, - node, - "smooth_method" - ); - }) - .catch((err) => { - console.error("Error loading smoothing methods", err); - }); -} - -populateInterpolationMethods(configUrls, elements, node) { - this.fetchData(configUrls.cloud.config, configUrls.local.config) - .then((configData) => { - const interpolationMethods = - configData?.interpolation?.type?.rules?.values.map((m) => m.value) || - []; - this.populateDropdown( - elements.interpolationMethodInput, - interpolationMethods, - node, - "interpolationMethod" - ); - - // Find the selected method and use it to spawn 1 more field to fill in tension - //const selectedMethod = interpolationMethods.find(m => m === node.interpolationMethod); - this.initTensionToggles(elements, node); - }) - .catch((err) => { - console.error("Error loading interpolation methods", err); - }); -} - -populateLogLevelOptions(logLevelSelect, configData, node) { - // debug log level - //console.log("Displaying configData => ", configData) ; - - const logLevels = - configData?.general?.logging?.logLevel?.rules?.values?.map( - (l) => l.value - ) || []; - - //console.log("Displaying logLevels => ", logLevels); - - // Reuse your existing generic populateDropdown helper - this.populateDropdown(logLevelSelect, logLevels, node.logLevel); -} - -//cascade dropdowns for asset type, supplier, subType, model, unit -fetchAndPopulateDropdowns(configUrls, elements, node) { - this.fetchData(configUrls.cloud.config, configUrls.local.config) - .then((configData) => { - const assetType = configData.asset?.type?.default; - const localSuppliersUrl = this.constructUrl(configUrls.local.taggcodeAPI,`${assetType}s`,"suppliers.json"); - const cloudSuppliersUrl = this.constructCloudURL(configUrls.cloud.taggcodeAPI, "/vendor/get_vendors.php"); - - return this.fetchData(cloudSuppliersUrl, localSuppliersUrl) - .then((supplierData) => { - - const suppliers = supplierData.map((supplier) => supplier.name); - - // Populate suppliers dropdown and set up its change handler - return this.populateDropdown( - elements.supplier, - suppliers, - node, - "supplier", - function (selectedSupplier) { - if (selectedSupplier) { - this.populateSubTypes(configUrls, elements, node, selectedSupplier); - } - } - ); - }) - .then(() => { - // If we have a saved supplier, trigger subTypes population - if (node.supplier) { - this.populateSubTypes(configUrls, elements, node, node.supplier); - } - }); - }) - .catch((error) => { - console.error("Error in initial dropdown population:", error); - }); -} - -getSpecificConfigUrl(nodeName,cloudAPI) { - - const cloudConfigURL = cloudAPI + "/config/" + nodeName + ".json"; - const localConfigURL = "http://localhost:1880/"+ nodeName + "/dependencies/"+ nodeName + "/" + nodeName + "Config.json"; - - return { cloudConfigURL, localConfigURL }; - -} - -// Save changes to API -async apiCall(node) { - try{ - // OLFIANT when a browser refreshes the tag code is lost!!! fix this later!!!!! - // FIX UUID ALSO LATER - - if(node.assetTagCode !== "" || node.assetTagCode !== null){ } - // API call to register or check asset in central database - let assetregisterAPI = node.configUrls.cloud.taggcodeAPI + "/asset/create_asset.php"; - - const assetModelId = node.modelMetadata.id; //asset_product_model_id - const uuid = node.uuid; //asset_product_model_uuid - const assetName = node.assetType; //asset_name / type? - const description = node.name; // asset_description - const assetStatus = "actief"; //asset_status -> koppel aan enable / disable node ? or make dropdown ? - const assetProfileId = 1; //asset_profile_id these are the rules to check if the childs are valid under this node (parent / child id?) - const child_assets = ["63247"]; //child_assets tagnummer of id? - const assetProcessId = node.processId; //asset_process_id - const assetLocationId = node.locationId; //asset_location_id - const tagCode = node.assetTagCode; // if already exists in the node information use it to tell the api it exists and it will update else we will get it from the api call - //console.log(`this is my tagCode: ${tagCode}`); - - // Build base URL with required parameters - let apiUrl = `?asset_product_model_id=${assetModelId}&asset_product_model_uuid=${uuid}&asset_name=${assetName}&asset_description=${description}&asset_status=${assetStatus}&asset_profile_id=${assetProfileId}&asset_location_id=${assetLocationId}&asset_process_id=${assetProcessId}&child_assets=${child_assets}`; - - // Only add tagCode to URL if it exists - if (tagCode) { - apiUrl += `&asset_tag_number=${tagCode}`; - console.log('hello there'); - } - - assetregisterAPI += apiUrl; - console.log("API call to register asset in central database", assetregisterAPI); - - const response = await fetch(assetregisterAPI, { - method: "POST" - }); - - // Get the response text first - const responseText = await response.text(); - console.log("Raw API response:", responseText); - - // Try to parse the JSON, handling potential parsing errors - let jsonResponse; - try { - jsonResponse = JSON.parse(responseText); - } catch (parseError) { - console.error("JSON Parsing Error:", parseError); - console.error("Response that could not be parsed:", responseText); - throw new Error("Failed to parse API response"); - } - - console.log(jsonResponse); - - if(jsonResponse.success){ - console.log(`${jsonResponse.message}, tag number: ${jsonResponse.asset_tag_number}, asset id: ${jsonResponse.asset_id}`); - // Save the asset tag number and id to the node - } else { - console.log("Asset not registered in central database"); - } - return jsonResponse; - - } catch (error) { - console.log("Error saving changes to asset register API", error); - } -} - - -async fetchData(url, fallbackUrl) { - try { - const response = await fetch(url); - if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); - const responsData = await response.json(); - //responsData - const data = responsData.data; - /* .map(item => { - const { vendor_name, ...rest } = item; - return { - name: vendor_name, - ...rest - }; - }); */ - console.log(url); - console.log("Response Data: ", data); - return data; - - } catch (err) { - console.warn( - `Primary URL failed: ${url}. Trying fallback URL: ${fallbackUrl}`, - err - ); - try { - const response = await fetch(fallbackUrl); - if (!response.ok) - throw new Error(`HTTP error! status: ${response.status}`); - return await response.json(); - } catch (fallbackErr) { - console.error("Both primary and fallback URLs failed:", fallbackErr); - return []; - } - } -} - -async fetchProjectData(url) { - try { - const response = await fetch(url); - if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); - const responsData = await response.json(); - console.log("Response Data: ", responsData); - return responsData; - - } catch (err) { - } -} - -async populateDropdown( - htmlElement, - options, - node, - property, - callback -) { - this.generateHtml(htmlElement, options, node[property]); - - htmlElement.addEventListener("change", async (e) => { - const newValue = e.target.value; - console.log(`Dropdown changed: ${property} = ${newValue}`); - node[property] = newValue; - - RED.nodes.dirty(true); - if (callback) await callback(newValue); // Ensure async callback completion - }); -} - -// Helper function to construct a URL from a base and path internal -constructUrl(base, ...paths) { - - // Remove trailing slash from base and leading slashes from paths - const sanitizedBase = (base || "").replace(/\/+$/, ""); - const sanitizedPaths = paths.map((path) => path.replace(/^\/+|\/+$/g, "")); - - // Join sanitized base and paths - const url = `${sanitizedBase}/${sanitizedPaths.join("/")}`; - console.log("Base:", sanitizedBase); - console.log("Paths:", sanitizedPaths); - console.log("Constructed URL:", url); - return url; -} - -//Adjust for API Gateway -constructCloudURL(base, ...paths) { - // Remove trailing slash from base and leading slashes from paths - const sanitizedBase = base.replace(/\/+$/, ""); - const sanitizedPaths = paths.map((path) => path.replace(/^\/+|\/+$/g, "")); - // Join sanitized base and paths - const url = `${sanitizedBase}/${sanitizedPaths.join("/")}`; - return url; -} - -populateSubTypes(configUrls, elements, node, selectedSupplier) { - - this.fetchData(configUrls.cloud.config, configUrls.local.config) - .then((configData) => { - const assetType = configData.asset?.type?.default; - const supplierFolder = this.constructUrl( configUrls.local.taggcodeAPI, `${assetType}s`, selectedSupplier ); - - const localSubTypesUrl = this.constructUrl(supplierFolder, "subtypes.json"); - const cloudSubTypesUrl = this.constructCloudURL(configUrls.cloud.taggcodeAPI, "/product/get_subtypesFromVendor.php?vendor_name=" + selectedSupplier); - - return this.fetchData(cloudSubTypesUrl, localSubTypesUrl) - .then((subTypeData) => { - const subTypes = subTypeData.map((subType) => subType.name); - - return this.populateDropdown( - elements.subType, - subTypes, - node, - "subType", - function (selectedSubType) { - if (selectedSubType) { - // When subType changes, update both models and units - this.populateModels( - configUrls, - elements, - node, - selectedSupplier, - selectedSubType - ); - this.populateUnitsForSubType( - configUrls, - elements, - node, - selectedSubType - ); - } - } - ); - }) - .then(() => { - // If we have a saved subType, trigger both models and units population - if (node.subType) { - this.populateModels( - configUrls, - elements, - node, - selectedSupplier, - node.subType - ); - this.populateUnitsForSubType(configUrls, elements, node, node.subType); - } - //console.log("In fetch part of subtypes "); - // Store all data from selected model -/* node["modelMetadata"] = modelData.find( - (model) => model.name === node.model - ); - console.log("Model Metadata: ", node["modelMetadata"]); */ - }); - }) - .catch((error) => { - console.error("Error populating subtypes:", error); - }); -} - -populateUnitsForSubType(configUrls, elements, node, selectedSubType) { - // Fetch the units data - this.fetchData(configUrls.cloud.units, configUrls.local.units) - .then((unitsData) => { - // Find the category that matches the subType name - const categoryData = unitsData.units.find( - (category) => - category.category.toLowerCase() === selectedSubType.toLowerCase() - ); - - if (categoryData) { - // Extract just the unit values and descriptions - const units = categoryData.values.map((unit) => ({ - value: unit.value, - description: unit.description, - })); - - // Create the options array with descriptions as labels - const options = units.map((unit) => ({ - value: unit.value, - label: `${unit.value} - ${unit.description}`, - })); - - // Populate the units dropdown - this.populateDropdown( - elements.unit, - options.map((opt) => opt.value), - node, - "unit" - ); - - // If there's no currently selected unit but we have options, select the first one - if (!node.unit && options.length > 0) { - node.unit = options[0].value; - elements.unit.value = options[0].value; - } - } else { - // If no matching category is found, provide a default % option - const defaultUnits = [{ value: "%", description: "Percentage" }]; - this.populateDropdown( - elements.unit, - defaultUnits.map((unit) => unit.value), - node, - "unit" - ); - console.warn( - `No matching unit category found for subType: ${selectedSubType}` - ); - } - }) - .catch((error) => { - console.error("Error fetching units:", error); - }); -} - -populateModels( - configUrls, - elements, - node, - selectedSupplier, - selectedSubType -) { - - this.fetchData(configUrls.cloud.config, configUrls.local.config) - .then((configData) => { - const assetType = configData.asset?.type?.default; - // save assetType to fetch later - node.assetType = assetType; - - const supplierFolder = this.constructUrl( configUrls.local.taggcodeAPI,`${assetType}s`,selectedSupplier); - const subTypeFolder = this.constructUrl(supplierFolder, selectedSubType); - const localModelsUrl = this.constructUrl(subTypeFolder, "models.json"); - const cloudModelsUrl = this.constructCloudURL(configUrls.cloud.taggcodeAPI, "/product/get_product_models.php?vendor_name=" + selectedSupplier + "&product_subtype_name=" + selectedSubType); - - return this.fetchData(cloudModelsUrl, localModelsUrl).then((modelData) => { - const models = modelData.map((model) => model.name); // use this to populate the dropdown - - // If a model is already selected, store its metadata immediately - if (node.model) { - node["modelMetadata"] = modelData.find((model) => model.name === node.model); - } - - this.populateDropdown(elements.model, models, node, "model", (selectedModel) => { - // Store only the metadata for the selected model - node["modelMetadata"] = modelData.find((model) => model.name === selectedModel); - }); - /* - console.log('hello here I am:'); - console.log(node["modelMetadata"]); -*/ - }); - - }) - .catch((error) => { - console.error("Error populating models:", error); - }); -} - -generateHtml(htmlElement, options, savedValue) { - htmlElement.innerHTML = options.length - ? `${options - .map((opt) => ``) - .join("")}` - : ""; - - if (savedValue && options.includes(savedValue)) { - htmlElement.value = savedValue; - } -} - -} - -module.exports = MenuUtils; \ No newline at end of file diff --git a/helper/nodeTemplates.js b/helper/nodeTemplates.js deleted file mode 100644 index da259e4..0000000 --- a/helper/nodeTemplates.js +++ /dev/null @@ -1,56 +0,0 @@ -const nodeTemplates = { - asset: { - category: "digital asset", - color: "#4f8582", - defaults: { - name: { value: "", required: true }, - enableLog: { value: false }, - logLevel: { value: "error" }, - parent: { value: "downstream" }, // indicates the position vs the parent in the process downstream,upstream or none. - supplier: { value: "" }, - subType: { value: "" }, - model: { value: "" }, - unit: { value: "" }, - }, - inputs: 1, - outputs: 3, - inputLabels: ["Machine Input"], - outputLabels: ["process", "dbase", "parent"], - icon: "font-awesome/fa-cogs", - elements: { - // Basic fields - name: "node-input-name", - // Logging fields - logCheckbox: "node-input-enableLog", - logLevelSelect: "node-input-logLevel", - rowLogLevel: "row-logLevel", - // Asset fields - supplier: "node-input-supplier", - subType: "node-input-subType", - model: "node-input-model", - unit: "node-input-unit", - //position vs parent - parent: "node-input-parent", - }, - projectSettingsURL: - "http://localhost:1880/generalFunctions/settings/projectSettings.json", - }, - - exampleTemplate: { - category: "digital twin", - color: "#004080", - defaults: { - name: { value: "", required: true }, - foo: { value: 42 }, - }, - inputs: 2, - outputs: 2, - inputLabels: ["In A", "In B"], - outputLabels: ["Out A", "Out B"], - icon: "font-awesome/fa-gears", - }, - - // …add more node “templates” here… -}; - -export default nodeTemplates; diff --git a/helper/nrmse/errorMetric.test.js b/helper/nrmse/errorMetric.test.js deleted file mode 100644 index 51a22f2..0000000 --- a/helper/nrmse/errorMetric.test.js +++ /dev/null @@ -1,297 +0,0 @@ -const ErrorMetrics = require('./errorMetrics'); - -// Dummy logger for tests -const logger = { - error: console.error, - debug: console.log, - info: console.log -}; - -const config = { - thresholds: { - NRMSE_LOW: 0.05, - NRMSE_MEDIUM: 0.10, - NRMSE_HIGH: 0.15, - LONG_TERM_LOW: 0.02, - LONG_TERM_MEDIUM: 0.04, - LONG_TERM_HIGH: 0.06 - } -}; - -class ErrorMetricsTester { - constructor() { - this.totalTests = 0; - this.passedTests = 0; - this.failedTests = 0; - this.errorMetrics = new ErrorMetrics(config, logger); - } - - assert(condition, message) { - this.totalTests++; - if (condition) { - console.log(`✓ PASS: ${message}`); - this.passedTests++; - } else { - console.log(`✗ FAIL: ${message}`); - this.failedTests++; - } - } - - testMeanSquaredError() { - console.log("\nTesting Mean Squared Error..."); - const predicted = [1, 2, 3]; - const measured = [1, 3, 5]; - const mse = this.errorMetrics.meanSquaredError(predicted, measured); - this.assert(Math.abs(mse - 1.67) < 0.1, "MSE correctly calculated"); - } - - testRootMeanSquaredError() { - console.log("\nTesting Root Mean Squared Error..."); - const predicted = [1, 2, 3]; - const measured = [1, 3, 5]; - const rmse = this.errorMetrics.rootMeanSquaredError(predicted, measured); - this.assert(Math.abs(rmse - 1.29) < 0.1, "RMSE correctly calculated"); - } - - testNormalizedRMSE() { - console.log("\nTesting Normalized RMSE..."); - const predicted = [100, 102, 104]; - const measured = [98, 103, 107]; - const processMin = 90, processMax = 110; - const nrmse = this.errorMetrics.normalizedRootMeanSquaredError(predicted, measured, processMin, processMax); - this.assert(typeof nrmse === 'number' && nrmse > 0, "Normalized RMSE calculated correctly"); - } - - testNormalizeUsingRealtime() { - console.log("\nTesting Normalize Using Realtime..."); - const predicted = [100, 102, 104]; - const measured = [98, 103, 107]; - - try { - const nrmse = this.errorMetrics.normalizeUsingRealtime(predicted, measured); - this.assert(typeof nrmse === 'number' && nrmse > 0, "Normalize using realtime calculated correctly"); - } catch (error) { - this.assert(false, `Normalize using realtime failed: ${error.message}`); - } - - // Test with identical values to check error handling - const sameValues = [100, 100, 100]; - try { - this.errorMetrics.normalizeUsingRealtime(sameValues, sameValues); - this.assert(false, "Should throw error with identical values"); - } catch (error) { - this.assert(true, "Correctly throws error when min/max are the same"); - } - } - - testLongTermNRMSD() { - console.log("\nTesting Long Term NRMSD Accumulation..."); - // Reset the accumulation values - this.errorMetrics.cumNRMSD = 0; - this.errorMetrics.cumCount = 0; - - let lastValue = 0; - for (let i = 0; i < 100; i++) { - lastValue = this.errorMetrics.longTermNRMSD(0.1 + i * 0.001); - } - - this.assert( - this.errorMetrics.cumCount === 100 && - this.errorMetrics.cumNRMSD !== 0 && - lastValue !== 0, - "Long term NRMSD accumulates over 100 iterations" - ); - - // Test that values are returned only after accumulating 100 samples - this.errorMetrics.cumNRMSD = 0; - this.errorMetrics.cumCount = 0; - - for (let i = 0; i < 99; i++) { - const result = this.errorMetrics.longTermNRMSD(0.1); - this.assert(result === 0, "No longTermNRMSD returned before 100 samples"); - } - - // Use a different value for the 100th sample to ensure a non-zero result - const result = this.errorMetrics.longTermNRMSD(0.2); - this.assert(result !== 0, "longTermNRMSD returned after 100 samples"); - } - - testDetectImmediateDrift() { - console.log("\nTesting Immediate Drift Detection..."); - - // Test high drift - let drift = this.errorMetrics.detectImmediateDrift(config.thresholds.NRMSE_HIGH + 0.01); - this.assert(drift.level === 3, "Detects high immediate drift correctly"); - - // Test medium drift - drift = this.errorMetrics.detectImmediateDrift(config.thresholds.NRMSE_MEDIUM + 0.01); - this.assert(drift.level === 2, "Detects medium immediate drift correctly"); - - // Test low drift - drift = this.errorMetrics.detectImmediateDrift(config.thresholds.NRMSE_LOW + 0.01); - this.assert(drift.level === 1, "Detects low immediate drift correctly"); - - // Test no drift - drift = this.errorMetrics.detectImmediateDrift(config.thresholds.NRMSE_LOW - 0.01); - this.assert(drift.level === 0, "Detects no immediate drift correctly"); - } - - testDetectLongTermDrift() { - console.log("\nTesting Long Term Drift Detection..."); - - // Test high drift - let drift = this.errorMetrics.detectLongTermDrift(config.thresholds.LONG_TERM_HIGH + 0.01); - this.assert(drift.level === 3, "Detects high long-term drift correctly"); - - // Test medium drift - drift = this.errorMetrics.detectLongTermDrift(config.thresholds.LONG_TERM_MEDIUM + 0.01); - this.assert(drift.level === 2, "Detects medium long-term drift correctly"); - - // Test low drift - drift = this.errorMetrics.detectLongTermDrift(config.thresholds.LONG_TERM_LOW + 0.01); - this.assert(drift.level === 1, "Detects low long-term drift correctly"); - - // Test no drift - drift = this.errorMetrics.detectLongTermDrift(config.thresholds.LONG_TERM_LOW - 0.01); - this.assert(drift.level === 0, "Detects no long-term drift correctly"); - - // Test negative drift values - drift = this.errorMetrics.detectLongTermDrift(-config.thresholds.LONG_TERM_HIGH - 0.01); - this.assert(drift.level === 3, "Detects negative high long-term drift correctly"); - } - - testDriftDetection() { - console.log("\nTesting Combined Drift Detection..."); - - let nrmseHigh = config.thresholds.NRMSE_HIGH + 0.01; - let ltNRMSD = 0; - - let result = this.errorMetrics.detectDrift(nrmseHigh, ltNRMSD); - - this.assert( - result !== null && - result.ImmDrift && - result.ImmDrift.level === 3 && - result.LongTermDrift.level === 0, - "Detects high immediate drift with no long-term drift" - ); - - nrmseHigh = config.thresholds.NRMSE_LOW - 0.01; - ltNRMSD = config.thresholds.LONG_TERM_MEDIUM + 0.01; - result = this.errorMetrics.detectDrift(nrmseHigh, ltNRMSD); - this.assert( - result !== null && - result.ImmDrift.level === 0 && - result.LongTermDrift && - result.LongTermDrift.level === 2, - "Detects medium long-term drift with no immediate drift" - ); - - nrmseHigh = config.thresholds.NRMSE_MEDIUM + 0.01; - ltNRMSD = config.thresholds.LONG_TERM_MEDIUM + 0.01; - result = this.errorMetrics.detectDrift(nrmseHigh, ltNRMSD); - this.assert( - result.ImmDrift.level === 2 && - result.LongTermDrift.level === 2, - "Detects both medium immediate and medium long-term drift" - ); - - nrmseHigh = config.thresholds.NRMSE_LOW - 0.01; - ltNRMSD = config.thresholds.LONG_TERM_LOW - 0.01; - result = this.errorMetrics.detectDrift(nrmseHigh, ltNRMSD); - this.assert( - result.ImmDrift.level === 0 && - result.LongTermDrift.level === 0, - "No significant drift detected when under thresholds" - ); - } - - testAssessDrift() { - console.log("\nTesting assessDrift function..."); - - // Reset accumulation for testing - this.errorMetrics.cumNRMSD = 0; - this.errorMetrics.cumCount = 0; - - const predicted = [100, 101, 102, 103]; - const measured = [90, 91, 92, 93]; - const processMin = 90, processMax = 110; - - let result = this.errorMetrics.assessDrift(predicted, measured, processMin, processMax); - - this.assert( - result !== null && - typeof result.nrmse === 'number' && - typeof result.longTermNRMSD === 'number' && - typeof result.immediateLevel === 'number' && - typeof result.immediateFeedback === 'string' && - typeof result.longTermLevel === 'number' && - typeof result.longTermFeedback === 'string', - "assessDrift returns complete result structure" - ); - - this.assert( - result.immediateLevel > 0, - "assessDrift detects immediate drift with significant difference" - ); - - // Test with identical values - result = this.errorMetrics.assessDrift(predicted, predicted, processMin, processMax); - this.assert( - result.nrmse === 0 && - result.immediateLevel === 0, - "assessDrift indicates no immediate drift when predicted equals measured" - ); - - // Test with slight drift - const measuredSlight = [100, 100.5, 101, 101.5]; - result = this.errorMetrics.assessDrift(predicted, measuredSlight, processMin, processMax); - - this.assert( - result !== null && - result.nrmse < 0.05 && - (result.immediateLevel < 2), - "assessDrift returns appropriate levels for slight drift" - ); - - // Test long-term drift accumulation - for (let i = 0; i < 100; i++) { - this.errorMetrics.assessDrift( - predicted, - measured.map(m => m + (Math.random() * 2 - 1)), // Add small random fluctuation - processMin, - processMax - ); - } - - result = this.errorMetrics.assessDrift(predicted, measured, processMin, processMax); - this.assert( - result.longTermNRMSD !== 0, - "Long-term drift accumulates over multiple assessments" - ); - } - - async runAllTests() { - console.log("\nStarting Error Metrics Tests...\n"); - this.testMeanSquaredError(); - this.testRootMeanSquaredError(); - this.testNormalizedRMSE(); - this.testNormalizeUsingRealtime(); - this.testLongTermNRMSD(); - this.testDetectImmediateDrift(); - this.testDetectLongTermDrift(); - this.testDriftDetection(); - this.testAssessDrift(); - - console.log("\nTest Summary:"); - console.log(`Total Tests: ${this.totalTests}`); - console.log(`Passed: ${this.passedTests}`); - console.log(`Failed: ${this.failedTests}`); - - process.exit(this.failedTests > 0 ? 1 : 0); - } -} - -// Run all tests -const tester = new ErrorMetricsTester(); -tester.runAllTests().catch(console.error); diff --git a/helper/nrmse/errorMetrics.js b/helper/nrmse/errorMetrics.js deleted file mode 100644 index c567ec4..0000000 --- a/helper/nrmse/errorMetrics.js +++ /dev/null @@ -1,154 +0,0 @@ -//load local dependencies -const EventEmitter = require('events'); - -//load all config modules -const defaultConfig = require('./nrmseConfig.json'); -const ConfigUtils = require('../configUtils'); - -class ErrorMetrics { - constructor(config = {}, logger) { - - this.emitter = new EventEmitter(); // Own EventEmitter - this.configUtils = new ConfigUtils(defaultConfig); - this.config = this.configUtils.initConfig(config); - - // Init after config is set - this.logger = logger; - - // For long-term NRMSD accumulation - this.cumNRMSD = 0; - this.cumCount = 0; - } - - //INCLUDE timestamps in the next update OLIFANT - meanSquaredError(predicted, measured) { - if (predicted.length !== measured.length) { - this.logger.error("Comparing MSE Arrays must have the same length."); - return 0; - } - - - let sumSqError = 0; - for (let i = 0; i < predicted.length; i++) { - const err = predicted[i] - measured[i]; - sumSqError += err * err; - } - return sumSqError / predicted.length; - } - - rootMeanSquaredError(predicted, measured) { - return Math.sqrt(this.meanSquaredError(predicted, measured)); - } - - normalizedRootMeanSquaredError(predicted, measured, processMin, processMax) { - const range = processMax - processMin; - if (range <= 0) { - this.logger.error("Invalid process range: processMax must be greater than processMin."); - } - const rmse = this.rootMeanSquaredError(predicted, measured); - return rmse / range; - } - - longTermNRMSD(input) { - - const storedNRMSD = this.cumNRMSD; - const storedCount = this.cumCount; - const newCount = storedCount + 1; - - // Update cumulative values - this.cumCount = newCount; - - // Calculate new running average - if (storedCount === 0) { - this.cumNRMSD = input; // First value - } else { - // Running average formula: newAvg = oldAvg + (newValue - oldAvg) / newCount - this.cumNRMSD = storedNRMSD + (input - storedNRMSD) / newCount; - } - - if(newCount >= 100) { - // Return the current NRMSD value, not just the contribution from this sample - return this.cumNRMSD; - } - return 0; - } - - normalizeUsingRealtime(predicted, measured) { - const realtimeMin = Math.min(Math.min(...predicted), Math.min(...measured)); - const realtimeMax = Math.max(Math.max(...predicted), Math.max(...measured)); - const range = realtimeMax - realtimeMin; - if (range <= 0) { - throw new Error("Invalid process range: processMax must be greater than processMin."); - } - const rmse = this.rootMeanSquaredError(predicted, measured); - return rmse / range; - } - - detectImmediateDrift(nrmse) { - let ImmDrift = {}; - this.logger.debug(`checking immediate drift with thresholds : ${this.config.thresholds.NRMSE_HIGH} ${this.config.thresholds.NRMSE_MEDIUM} ${this.config.thresholds.NRMSE_LOW}`); - switch (true) { - case( nrmse > this.config.thresholds.NRMSE_HIGH ) : - ImmDrift = {level : 3 , feedback : "High immediate drift detected"}; - break; - case( nrmse > this.config.thresholds.NRMSE_MEDIUM ) : - ImmDrift = {level : 2 , feedback : "Medium immediate drift detected"}; - break; - case(nrmse > this.config.thresholds.NRMSE_LOW ): - ImmDrift = {level : 1 , feedback : "Low immediate drift detected"}; - break; - default: - ImmDrift = {level : 0 , feedback : "No drift detected"}; - } - return ImmDrift; - } - - detectLongTermDrift(longTermNRMSD) { - let LongTermDrift = {}; - this.logger.debug(`checking longterm drift with thresholds : ${this.config.thresholds.LONG_TERM_HIGH} ${this.config.thresholds.LONG_TERM_MEDIUM} ${this.config.thresholds.LONG_TERM_LOW}`); - switch (true) { - case(Math.abs(longTermNRMSD) > this.config.thresholds.LONG_TERM_HIGH) : - LongTermDrift = {level : 3 , feedback : "High long-term drift detected"}; - break; - case (Math.abs(longTermNRMSD) > this.config.thresholds.LONG_TERM_MEDIUM) : - LongTermDrift = {level : 2 , feedback : "Medium long-term drift detected"}; - break; - case ( Math.abs(longTermNRMSD) > this.config.thresholds.LONG_TERM_LOW ) : - LongTermDrift = {level : 1 , feedback : "Low long-term drift detected"}; - break; - default: - LongTermDrift = {level : 0 , feedback : "No drift detected"}; - } - return LongTermDrift; - } - - detectDrift(nrmse, longTermNRMSD) { - const ImmDrift = this.detectImmediateDrift(nrmse); - const LongTermDrift = this.detectLongTermDrift(longTermNRMSD); - return { ImmDrift, LongTermDrift }; - } - - // asses the drift - assessDrift(predicted, measured, processMin, processMax) { - // Compute NRMSE and check for immediate drift - const nrmse = this.normalizedRootMeanSquaredError(predicted, measured, processMin, processMax); - this.logger.debug(`NRMSE: ${nrmse}`); - // cmopute long-term NRMSD and add result to cumalitve NRMSD - const longTermNRMSD = this.longTermNRMSD(nrmse); - // return the drift - // Return the drift assessment object - const driftAssessment = this.detectDrift(nrmse, longTermNRMSD); - return { - nrmse, - longTermNRMSD, - immediateLevel: driftAssessment.ImmDrift.level, - immediateFeedback: driftAssessment.ImmDrift.feedback, - longTermLevel: driftAssessment.LongTermDrift.level, - longTermFeedback: driftAssessment.LongTermDrift.feedback - }; - } - - -} - -module.exports = ErrorMetrics; diff --git a/helper/nrmse/nrmseConfig.json b/helper/nrmse/nrmseConfig.json deleted file mode 100644 index b8eeb9a..0000000 --- a/helper/nrmse/nrmseConfig.json +++ /dev/null @@ -1,138 +0,0 @@ -{ - "general": { - "name": { - "default": "ErrorMetrics", - "rules": { - "type": "string", - "description": "A human-readable name for the configuration." - } - }, - "id": { - "default": null, - "rules": { - "type": "string", - "nullable": true, - "description": "A unique identifier for this configuration, assigned dynamically when needed." - } - }, - "unit": { - "default": "unitless", - "rules": { - "type": "string", - "description": "The unit used for the state values (e.g., 'meters', 'seconds', 'unitless')." - } - }, - "logging": { - "logLevel": { - "default": "info", - "rules": { - "type": "enum", - "values": [ - { - "value": "debug", - "description": "Log messages are printed for debugging purposes." - }, - { - "value": "info", - "description": "Informational messages are printed." - }, - { - "value": "warn", - "description": "Warning messages are printed." - }, - { - "value": "error", - "description": "Error messages are printed." - } - ] - } - }, - "enabled": { - "default": true, - "rules": { - "type": "boolean", - "description": "Indicates whether logging is active. If true, log messages will be generated." - } - } - } - }, - "functionality": { - "softwareType": { - "default": "errorMetrics", - "rules": { - "type": "string", - "description": "Logical name identifying the software type." - } - }, - "role": { - "default": "error calculation", - "rules": { - "type": "string", - "description": "Functional role within the system." - } - } - }, - "mode": { - "current": { - "default": "active", - "rules": { - "type": "enum", - "values": [ - { - "value": "active", - "description": "The error metrics calculation is active." - }, - { - "value": "inactive", - "description": "The error metrics calculation is inactive." - } - ], - "description": "The operational mode of the error metrics calculation." - } - } - }, - "thresholds": { - "NRMSE_LOW": { - "default": 0.05, - "rules": { - "type": "number", - "description": "Low threshold for normalized root mean squared error." - } - }, - "NRMSE_MEDIUM": { - "default": 0.10, - "rules": { - "type": "number", - "description": "Medium threshold for normalized root mean squared error." - } - }, - "NRMSE_HIGH": { - "default": 0.15, - "rules": { - "type": "number", - "description": "High threshold for normalized root mean squared error." - } - }, - "LONG_TERM_LOW": { - "default": 0.02, - "rules": { - "type": "number", - "description": "Low threshold for long-term normalized root mean squared deviation." - } - }, - "LONG_TERM_MEDIUM": { - "default": 0.04, - "rules": { - "type": "number", - "description": "Medium threshold for long-term normalized root mean squared deviation." - } - }, - "LONG_TERM_HIGH": { - "default": 0.06, - "rules": { - "type": "number", - "description": "High threshold for long-term normalized root mean squared deviation." - } - } - } -} diff --git a/helper/outliers/outlierDetection.js b/helper/outliers/outlierDetection.js deleted file mode 100644 index 2cdca81..0000000 --- a/helper/outliers/outlierDetection.js +++ /dev/null @@ -1,89 +0,0 @@ -class DynamicClusterDeviation { - constructor() { - this.clusters = []; // Stores clusters as { center, spread, count } - } - - update(value) { - console.log(`\nProcessing value: ${value}`); - - // If no clusters exist, create the first one - if (this.clusters.length === 0) { - this.clusters.push({ center: value, spread: 0, count: 1 }); - console.log(` → First cluster created at ${value}`); - return { value, isOutlier: false }; - } - - // Step 1: Find the closest cluster - let bestMatch = null; - let minDistance = Infinity; - - for (const cluster of this.clusters) { - const distance = Math.abs(value - cluster.center); - console.log(` Checking against cluster at ${cluster.center} (spread: ${cluster.spread}, count: ${cluster.count}) → distance: ${distance}`); - - if (distance < minDistance) { - bestMatch = cluster; - minDistance = distance; - } - } - - console.log(` Closest cluster found at ${bestMatch.center} with distance: ${minDistance}`); - - // Step 2: Compute dynamic threshold - const dynamicThreshold = 1 + 5 / Math.sqrt(bestMatch.count + 1); - const allowedDeviation = dynamicThreshold * (bestMatch.spread || 1); - - console.log(` Dynamic threshold: ${dynamicThreshold.toFixed(2)}, Allowed deviation: ${allowedDeviation.toFixed(2)}`); - - // Step 3: Check if value fits within the dynamically adjusted cluster spread - if (minDistance <= allowedDeviation) { - // Update cluster dynamically - const newCenter = (bestMatch.center * bestMatch.count + value) / (bestMatch.count + 1); - const newSpread = Math.max(bestMatch.spread, minDistance); - bestMatch.center = newCenter; - bestMatch.spread = newSpread; - bestMatch.count += 1; - - console.log(` ✅ Value fits in cluster! Updating cluster:`); - console.log(` → New center: ${newCenter.toFixed(2)}`); - console.log(` → New spread: ${newSpread.toFixed(2)}`); - console.log(` → New count: ${bestMatch.count}`); - - return { value, isOutlier: false }; - } else { - // If too far, create a new cluster - this.clusters.push({ center: value, spread: 0, count: 1 }); - - console.log(` ❌ Outlier detected! New cluster created at ${value}`); - - return { value, isOutlier: true }; - } - } -} - -// Rolling window simulation with outlier detection -/* -const detector = new DynamicClusterDeviation(); -const dataStream = [10, 10.2, 10.5, 9.8, 11, 50, 10.3, 200, 201, 200.1, 205, 202, 250, 260, 270, 280, 290, 300]; - -// Define the number of elements per rolling window chunk. -const windowSize = 5; -let rollingWindow = []; - -dataStream.forEach((value, index) => { - console.log(`\n=== Processing value ${index + 1} ===`); - rollingWindow.push(value); - const result = detector.update(value); - console.log(`Current rolling window: [${rollingWindow.join(', ')}]`); - console.log(`Result: value=${result.value} (${result.isOutlier ? 'Outlier' : 'Inlier'})`); - - // Once the window size is reached, show current cluster states and reset the window for the next chunk. - if (rollingWindow.length === windowSize) { - console.log("\n--- Rolling window chunk finished ---"); - console.log("Detector cluster states:", JSON.stringify(detector.clusters, null, 2)); - rollingWindow = []; - } -}); - -console.log("\nFinal detector cluster states:", JSON.stringify(detector.clusters, null, 2)); -*/ \ No newline at end of file diff --git a/helper/outputUtils.js b/helper/outputUtils.js deleted file mode 100644 index bd6fb8d..0000000 --- a/helper/outputUtils.js +++ /dev/null @@ -1,132 +0,0 @@ -//this class will handle the output events for the node red node -class OutputUtils { - constructor() { - this.output ={}; - this.output['influxdb'] = {}; - this.output['process'] = {}; - } - - checkForChanges(output, format) { - const changedFields = {}; - for (const key in output) { - if (output.hasOwnProperty(key) && output[key] !== this.output[format][key]) { - let value = output[key]; - // For fields: if the value is an object (and not a Date), stringify it. - if (value !== null && typeof value === 'object' && !(value instanceof Date)) { - changedFields[key] = JSON.stringify(value); - } else { - changedFields[key] = value; - } - } - } - - // Update the saved output state. - this.output[format] = { ...this.output[format], ...changedFields }; - - return changedFields; - } - - formatMsg(output, config, format) { - - //define emtpy message - let msg = {}; - - // Compare output with last output and only include changed values - const changedFields = this.checkForChanges(output,format); - - if (Object.keys(changedFields).length > 0) { - - switch (format) { - case 'influxdb': - // Extract the relevant config properties. - const relevantConfig = this.extractRelevantConfig(config); - // Flatten the tags so that no nested objects are passed on. - const flatTags = this.flattenTags(relevantConfig); - msg = this.influxDBFormat(changedFields, config, flatTags); - - break; - - case 'process': - - // Compare output with last output and only include changed values - msg = this.processFormat(changedFields,config); - //console.log(msg); - break; - - default: - console.log('Unknown format in output utils'); - break; - } - return msg; - } - } - - - influxDBFormat(changedFields, config , flatTags) { - // Create the measurement and topic using softwareType and name config.functionality.softwareType + . - const measurement = config.general.name; - const payload = { - measurement: measurement, - fields: changedFields, - tags: flatTags, - timestamp: new Date(), - }; - - const topic = measurement; - const msg = { topic: topic, payload: payload }; - return msg; - } - - flattenTags(obj) { - const result = {}; - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - const value = obj[key]; - if (value !== null && typeof value === 'object' && !(value instanceof Date)) { - // Recursively flatten the nested object. - const flatChild = this.flattenTags(value); - for (const childKey in flatChild) { - if (flatChild.hasOwnProperty(childKey)) { - result[`${key}_${childKey}`] = String(flatChild[childKey]); - } - } - } else { - // InfluxDB tags must be strings. - result[key] = String(value); - } - } - } - return result; - } - - extractRelevantConfig(config) { - - return { - // general properties - id: config.general?.id, - name: config.general?.name, - unit: config.general?.unit, - // functionality properties - softwareType: config.functionality?.softwareType, - role: config.functionality?.role, - // asset properties (exclude machineCurve) - uuid: config.asset?.uuid, - geoLocation: config.asset?.geoLocation, - supplier: config.asset?.supplier, - type: config.asset?.type, - subType: config.asset?.subType, - model: config.asset?.model, - }; - } - - processFormat(changedFields,config) { - // Create the measurement and topic using softwareType and name config.functionality.softwareType + . - const measurement = config.general.name; - const payload = changedFields; - const topic = measurement; - const msg = { topic: topic, payload: payload }; - return msg; - } -} - -module.exports = OutputUtils; diff --git a/helper/state/movementManager.js b/helper/state/movementManager.js deleted file mode 100644 index 8688cd4..0000000 --- a/helper/state/movementManager.js +++ /dev/null @@ -1,277 +0,0 @@ -//const EventEmitter = require('events'); - -class movementManager { - constructor(config, logger, emitter) { - this.emitter = emitter; //new EventEmitter(); //state class emitter - - const { min, max, initial } = config.position; - const { speed, maxSpeed, interval } = config.movement; - - this.minPosition = min; - this.maxPosition = max; - this.currentPosition = initial; - - this.speed = speed; - this.maxSpeed = maxSpeed; - this.interval = interval; - this.timeleft = 0; // timeleft of current movement - - this.logger = logger; - this.movementMode = config.movement.mode; - } - - getCurrentPosition() { - return this.currentPosition; - } - - async moveTo(targetPosition, signal) { - // Constrain target position if necessary - if ( - targetPosition < this.minPosition || - targetPosition > this.maxPosition - ) { - targetPosition = this.constrain(targetPosition); - this.logger.warn( - `New target position=${targetPosition} is constrained to fit between min=${this.minPosition} and max=${this.maxPosition}` - ); - } - - this.logger.info( - `Starting movement to position ${targetPosition} in ${this.movementMode} with avg speed=${this.speed}%/s.` - ); - - if (signal && signal.aborted) { - this.logger.debug("Movement aborted."); - return; - } - - try { - // Execute the movement logic based on the mode - switch (this.movementMode) { - case "staticspeed": - const movelinFeedback = await this.moveLinear(targetPosition,signal); - this.logger.info(`Linear move: ${movelinFeedback} `); - break; - - case "dynspeed": - const moveDynFeedback = await this.moveEaseInOut(targetPosition,signal); - this.logger.info(`Dynamic move : ${moveDynFeedback}`); - break; - - default: - throw new Error(`Unsupported movement mode: ${this.movementMode}`); - } - } catch (error) { - this.logger.error(error); - } - } - - moveLinear(targetPosition, signal) { - return new Promise((resolve, reject) => { - // Immediate abort if already signalled - if (signal?.aborted) { - return reject(new Error("Movement aborted")); - } - - // Clamp the final target into [minPosition, maxPosition] - targetPosition = this.constrain(targetPosition); - - // Compute direction and remaining distance - const direction = targetPosition > this.currentPosition ? 1 : -1; - const distance = Math.abs(targetPosition - this.currentPosition); - - // Speed is a fraction [0,1] of full-range per second - this.speed = Math.min(Math.max(this.speed, 0), 1); - const fullRange = this.maxPosition - this.minPosition; - const velocity = this.speed * fullRange; // units per second - if (velocity === 0) { - return reject(new Error("Movement aborted: zero speed")); - } - - // Duration and bookkeeping - const duration = distance / velocity; // seconds to go the remaining distance - this.timeleft = duration; - this.logger.debug( - `Linear move: dir=${direction}, dist=${distance}, vel=${velocity.toFixed(2)} u/s, dur=${duration.toFixed(2)}s` - ); - - // Compute how much to move each tick - const intervalMs = this.interval; - const intervalSec = intervalMs / 1000; - const stepSize = direction * velocity * intervalSec; - - const startTime = Date.now(); - - // Kick off the loop - const intervalId = setInterval(() => { - // 7a) Abort check - if (signal?.aborted) { - clearInterval(intervalId); - return reject(new Error("Movement aborted")); - } - - // Advance position and clamp - this.currentPosition += stepSize; - this.currentPosition = this.constrain(this.currentPosition); - this.emitPos(this.currentPosition); - - // Update timeleft - const elapsed = (Date.now() - startTime) / 1000; - this.timeleft = Math.max(0, duration - elapsed); - - this.logger.debug( - `pos=${this.currentPosition.toFixed(2)}, timeleft=${this.timeleft.toFixed(2)}` - ); - - // Completed the move? - if ( - (direction > 0 && this.currentPosition >= targetPosition) || - (direction < 0 && this.currentPosition <= targetPosition) - ) { - clearInterval(intervalId); - this.currentPosition = targetPosition; - this.emitPos(this.currentPosition); - return resolve("Reached target move."); - } - }, intervalMs); - - // 8) Also catch aborts that happen before the first tick - signal?.addEventListener("abort", () => { - clearInterval(intervalId); - reject(new Error("Movement aborted")); - }); - }); -} - - moveLinearinTime(targetPosition,signal) { - return new Promise((resolve, reject) => { - // Abort immediately if already signalled - if (signal?.aborted) { - return reject(new Error("Movement aborted")); - } - - const direction = targetPosition > this.currentPosition ? 1 : -1; - const distance = Math.abs(targetPosition - this.currentPosition); - - // Ensure speed is a percentage [0, 1] - this.speed = Math.min(Math.max(this.speed, 0), 1); - - // Calculate duration based on percentage of distance per second - const duration = 1 / this.speed; // 1 second for 100% of the distance - - this.timeleft = duration; //set this so other classes can use it - this.logger.debug( - `Linear movement: Direction=${direction}, Distance=${distance}, Duration=${duration}s` - ); - - let elapsedTime = 0; - const interval = this.interval; // Update every x ms - const totalSteps = Math.ceil((duration * 1000) / interval); - const stepSize = direction * (distance / totalSteps); - - // 2) Set up the abort listener once - const intervalId = setInterval(() => { - // 3) Check for abort on each tick - if (signal?.aborted) { - clearInterval(intervalId); - return reject(new Error("Movement aborted")); - } - // Update elapsed time - elapsedTime += interval / 1000; - - this.timeleft = duration - elapsedTime; //set this so other classes can use it - - // Update the position incrementally - this.currentPosition += stepSize; - this.emitPos(this.currentPosition); - this.logger.debug( - `Using ${this.movementMode} => Current position ${this.currentPosition}` - ); - - // Check if the target position has been reached - if ( - (direction > 0 && this.currentPosition >= targetPosition) || - (direction < 0 && this.currentPosition <= targetPosition) - ) { - clearInterval(intervalId); - this.currentPosition = targetPosition; - resolve(`Reached target move.`); - } - }, interval); - // Also attach abort outside the interval in case it fires before the first tick: - signal?.addEventListener("abort", () => { - clearInterval(intervalId); - reject(new Error("Movement aborted")); - }); - }); - } - - moveEaseInOut(targetPosition, signal) { - return new Promise((resolve, reject) => { - // 1) Bail immediately if already aborted - if (signal?.aborted) { - return reject(new Error("Movement aborted")); - } - - const direction = targetPosition > this.currentPosition ? 1 : -1; - const totalDistance = Math.abs(targetPosition - this.currentPosition); - const startPosition = this.currentPosition; - this.speed = Math.min(Math.max(this.speed, 0), 1); - - const easeFunction = (t) => - t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; - - let elapsedTime = 0; - const duration = totalDistance / this.speed; - this.timeleft = duration; - const interval = this.interval; - - // 2) Start the moving loop - const intervalId = setInterval(() => { - // 3) Check for abort on each tick - if (signal?.aborted) { - clearInterval(intervalId); - return reject(new Error("Movement aborted")); - } - - elapsedTime += interval / 1000; - const progress = Math.min(elapsedTime / duration, 1); - this.timeleft = duration - elapsedTime; - const easedProgress = easeFunction(progress); - const newPosition = - startPosition + (targetPosition - startPosition) * easedProgress; - - this.emitPos(newPosition); - this.logger.debug( - `Using ${this.movementMode} => Progress=${progress.toFixed( - 2 - )}, Eased=${easedProgress.toFixed(2)}` - ); - - if (progress >= 1) { - clearInterval(intervalId); - this.currentPosition = targetPosition; - resolve(`Reached target move.`); - } else { - this.currentPosition = newPosition; - } - }, interval); - - // 4) Also listen once for abort before first tick - signal?.addEventListener("abort", () => { - clearInterval(intervalId); - reject(new Error("Movement aborted")); - }); - }); - } - - emitPos(newPosition) { - this.emitter.emit("positionChange", newPosition); - } - - constrain(value) { - return Math.min(Math.max(value, this.minPosition), this.maxPosition); - } -} - -module.exports = movementManager; diff --git a/helper/state/state.js b/helper/state/state.js deleted file mode 100644 index a2ee626..0000000 --- a/helper/state/state.js +++ /dev/null @@ -1,131 +0,0 @@ -//load local dependencies -const EventEmitter = require('events'); -const StateManager = require('./stateManager'); -const MovementManager = require('./movementManager'); - -//load all config modules -const defaultConfig = require('./stateConfig.json'); -const ConfigUtils = require('../../../generalFunctions/helper/configUtils'); - -class state{ - constructor(config = {}, logger) { - - this.emitter = new EventEmitter(); // Own EventEmitter - this.configUtils = new ConfigUtils(defaultConfig); - this.config = this.configUtils.initConfig(config); - this.abortController = null; // new abort controller for aborting async tasks - // Init after config is set - this.logger = logger; - - // Initialize StateManager for state handling - this.stateManager = new StateManager(this.config,this.logger); - this.movementManager = new MovementManager(this.config, this.logger, this.emitter); - - this.delayedMove = null; - this.mode = this.config.mode.current; - - // Log initialization - this.logger.info("State class initialized."); - - } - - // -------- Delegate State Management -------- // - - getMoveTimeLeft() { - return this.movementManager.timeleft; - } - - getCurrentState() { - return this.stateManager.currentState; - } - - getStateDescription() { - return this.stateManager.getStateDescription(); - } - - // -------- Movement Methods -------- // - getCurrentPosition() { - return this.movementManager.getCurrentPosition(); - } - - getRunTimeHours() { - return this.stateManager.getRunTimeHours(); - } - - async moveTo(targetPosition) { - - // Check for invalid conditions and throw errors - if (targetPosition === this.getCurrentPosition()) { - this.logger.warn(`Target position=${targetPosition} is the same as the current position ${this.getCurrentPosition()}. Not executing move.`); - return; - } - - if (this.stateManager.getCurrentState() !== "operational") { - if (this.config.mode.current === "auto") { - this.delayedMove = targetPosition; - this.logger.warn(`Saving setpoint=${targetPosition} to execute once back in 'operational' state.`); - } - else{ - this.logger.warn(`Not able to accept setpoint=${targetPosition} while not in ${this.stateManager.getCurrentState()} state`); - } - //return early - return; - } - this.abortController = new AbortController(); - const { signal } = this.abortController; - try { - const newState = targetPosition < this.getCurrentPosition() ? "decelerating" : "accelerating"; - await this.transitionToState(newState,signal); // awaits transition - await this.movementManager.moveTo(targetPosition,signal); // awaits moving - this.emitter.emit("movementComplete", { position: targetPosition }); - await this.transitionToState("operational"); - } catch (error) { - this.logger.error(error); - } - } - - // -------- State Transition Methods -------- // - - async transitionToState(targetState, signal) { - - const fromState = this.getCurrentState(); - const position = this.getCurrentPosition(); - - try { - - this.logger.debug(`Starting transition from ${fromState} to ${targetState}.`); - const feedback = await this.stateManager.transitionTo(targetState,signal); - this.logger.info(`Statemanager: ${feedback}`); - - /* -- Auto pick setpoints in auto mode when operational--*/ - if ( - targetState === "operational" && - this.config.mode.current === "auto" && - this.delayedMove !== position && - this.delayedMove - ) { - this.logger.info(`Automatically picking up on last requested setpoint ${this.delayedMove}`); - //trigger move - await this.moveTo(this.delayedMove,signal); - this.delayedMove = null; - - this.logger.info(`moveTo : ${feedback} `); - } - - this.logger.info(`State change to ${targetState} completed.`); - this.emitter.emit('stateChange', targetState); // <-- Implement Here - } catch (error) { - if ( - error.message === "Transition aborted" || - error.message === "Movement aborted" - ) { - throw error; - } - this.logger.error(error); - } - } - -} - -module.exports = state; - diff --git a/helper/state/stateConfig.json b/helper/state/stateConfig.json deleted file mode 100644 index 8846c61..0000000 --- a/helper/state/stateConfig.json +++ /dev/null @@ -1,331 +0,0 @@ -{ - "general": { - "name": { - "default": "State Configuration", - "rules": { - "type": "string", - "description": "A human-readable name for the state configuration." - } - }, - "id": { - "default": null, - "rules": { - "type": "string", - "nullable": true, - "description": "A unique identifier for this configuration, assigned dynamically when needed." - } - }, - "unit": { - "default": "unitless", - "rules": { - "type": "string", - "description": "The unit used for the state values (e.g., 'meters', 'seconds', 'unitless')." - } - }, - "logging": { - "logLevel": { - "default": "info", - "rules": { - "type": "enum", - "values": [ - { - "value": "debug", - "description": "Log messages are printed for debugging purposes." - }, - { - "value": "info", - "description": "Informational messages are printed." - }, - { - "value": "warn", - "description": "Warning messages are printed." - }, - { - "value": "error", - "description": "Error messages are printed." - } - ] - } - }, - "enabled": { - "default": true, - "rules": { - "type": "boolean", - "description": "Indicates whether logging is active. If true, log messages will be generated." - } - } - } - }, - "functionality": { - "softwareType": { - "default": "state class", - "rules": { - "type": "string", - "description": "Logical name identifying the software type." - } - }, - "role": { - "default": "StateController", - "rules": { - "type": "string", - "description": "Functional role within the system." - } - } - }, - "time": { - "starting": { - "default": 10, - "rules": { - "type": "number", - "description": "Time in seconds for the starting phase." - } - }, - "warmingup": { - "default": 5, - "rules": { - "type": "number", - "description": "Time in seconds for the warming-up phase." - } - }, - "stopping": { - "default": 5, - "rules": { - "type": "number", - "description": "Time in seconds for the stopping phase." - } - }, - "coolingdown": { - "default": 10, - "rules": { - "type": "number", - "description": "Time in seconds for the cooling-down phase." - } - } - }, - "movement": { - "mode": { - "default": "dynspeed", - "rules": { - "type": "enum", - "values": [ - { - "value": "staticspeed", - "description": "Linear movement to setpoint." - }, - { - "value": "dynspeed", - "description": "Ease-in and ease-out to setpoint." - } - ] - } - }, - "speed": { - "default": 1, - "rules": { - "type": "number", - "description": "Current speed setting." - } - }, - "maxSpeed": { - "default": 10, - "rules": { - "type": "number", - "description": "Maximum speed setting." - } - }, - "interval": { - "default": 1000, - "rules": { - "type": "number", - "description": "Feedback interval in milliseconds." - } - } - }, - "position": { - "min": { - "default": 0, - "rules": { - "type": "number", - "description": "Minimum position value." - } - }, - "max": { - "default": 100, - "rules": { - "type": "number", - "description": "Maximum position value." - } - }, - "initial": { - "default": 0, - "rules": { - "type": "number", - "description": "Initial position value." - } - } - }, - "state": { - "current": { - "default": "idle", - "rules": { - "type": "enum", - "values": [ - { - "value": "idle", - "description": "Machine is idle." - }, - { - "value": "starting", - "description": "Machine is starting up." - }, - { - "value": "warmingup", - "description": "Machine is warming up." - }, - { - "value": "operational", - "description": "Machine is running." - }, - { - "value": "accelerating", - "description": "Machine is accelerating." - }, - { - "value": "decelerating", - "description": "Machine is decelerating." - }, - { - "value": "stopping", - "description": "Machine is stopping." - }, - { - "value": "coolingdown", - "description": "Machine is cooling down." - }, - { - "value": "off", - "description": "Machine is off." - } - ], - "description": "Current state of the machine." - } - }, - "allowedTransitions":{ - "default": {}, - "rules": { - "type": "object", - "schema": { - "idle": { - "default": ["starting", "off","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from idle state." - } - }, - "starting": { - "default": ["starting","warmingup","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from starting state." - } - }, - "warmingup": { - "default": ["operational","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from warmingup state." - } - }, - "operational": { - "default": ["accelerating", "decelerating", "stopping","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from operational state." - } - }, - "accelerating": { - "default": ["operational","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from accelerating state." - } - }, - "decelerating": { - "default": ["operational","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from decelerating state." - } - }, - "stopping": { - "default": ["idle","coolingdown","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from stopping state." - } - }, - "coolingdown": { - "default": ["idle","off","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from coolingDown state." - } - }, - "off": { - "default": ["idle","emergencystop"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from off state." - } - }, - "emergencystop": { - "default": ["idle","off"], - "rules":{ - "type": "set", - "itemType": "string", - "description": "Allowed transitions from emergency stop state." - } - } - }, - "description": "Allowed transitions between states." - } - }, - "activeStates":{ - "default": ["operational", "starting", "warmingup", "accelerating", "decelerating"], - "rules": { - "type": "set", - "itemType": "string", - "description": "Active states." - } - } - }, - "mode": { - "current": { - "default": "auto", - "rules": { - "type": "enum", - "values": [ - { - "value": "auto", - "description": "Automatically tracks and handles delayed commands for setpoints > 0." - }, - { - "value": "manual", - "description": "Requires explicit commands to start." - } - ], - "description": "Current mode of the machine." - } - } - } - } - \ No newline at end of file diff --git a/helper/state/stateManager.js b/helper/state/stateManager.js deleted file mode 100644 index 4549308..0000000 --- a/helper/state/stateManager.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @file stateManager.js - * - * Permission is hereby granted to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to use it for personal - * or non-commercial purposes, with the following restrictions: - * - * 1. **No Copying or Redistribution**: The Software or any of its parts may not - * be copied, merged, distributed, sublicensed, or sold without explicit - * prior written permission from the author. - * - * 2. **Commercial Use**: Any use of the Software for commercial purposes requires - * a valid license, obtainable only with the explicit consent of the author. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, - * OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Ownership of this code remains solely with the original author. Unauthorized - * use of this Software is strictly prohibited. - * - * @summary Class for managing state transitions and state descriptions. - * @description Class for managing state transitions and state descriptions. - * @module stateManager - * @exports stateManager - * @version 0.1.0 - * @since 0.1.0 - * - * Author: - * - Rene De Ren - * Email: - * - rene@thegoldenbasket.nl - */ - -class stateManager { - constructor(config, logger) { - this.currentState = config.state.current; - this.availableStates = config.state.available; - this.descriptions = config.state.descriptions; - this.logger = logger; - this.transitionTimeleft = 0; - this.transitionTimes = config.time; - - // Define valid transitions (can be extended dynamically if needed) - this.validTransitions = config.state.allowedTransitions; - - // NEW: Initialize runtime tracking - this.runTimeHours = 0; // cumulative runtime in hours - this.runTimeStart = null; // timestamp when active state began - - // Define active states (runtime counts only in these states) - this.activeStates = config.state.activeStates; - } - - getCurrentState() { - return this.currentState; - } - - transitionTo(newState,signal) { - return new Promise((resolve, reject) => { - if (signal && signal.aborted) { - this.logger.debug("Transition aborted."); - return reject("Transition aborted."); - } - - if (!this.isValidTransition(newState)) { - return reject( - `Invalid transition from ${this.currentState} to ${newState}. Transition not executed.` - ); //go back early and reject promise - } - - // NEW: Handle runtime tracking based on active states - this.handleRuntimeTracking(newState); - - const transitionDuration = this.transitionTimes[this.currentState] || 0; // Default to 0 if no transition time - this.logger.debug( - `Transition from ${this.currentState} to ${newState} will take ${transitionDuration}s.` - ); - - if (transitionDuration > 0) { - const timeoutId = setTimeout(() => { - this.currentState = newState; - resolve(`Transition from ${this.currentState} to ${newState} completed in ${transitionDuration}s.`); - }, transitionDuration * 1000); - if (signal) { - signal.addEventListener('abort', () => { - clearTimeout(timeoutId); - reject(new Error('Transition aborted')); - }); - } - } else { - this.currentState = newState; - resolve(`Immediate transition to ${this.currentState} completed.`); - } - }); - } - - handleRuntimeTracking(newState) { - // NEW: Handle runtime tracking based on active states - const wasActive = this.activeStates.has(this.currentState); - const willBeActive = this.activeStates.has(newState); - if (wasActive && !willBeActive && this.runTimeStart) { - // stop runtime timer and accumulate elapsed time - const elapsed = (Date.now() - this.runTimeStart) / 3600000; // hours - this.runTimeHours += elapsed; - this.runTimeStart = null; - this.logger.debug( - `Runtime timer stopped; elapsed=${elapsed.toFixed( - 3 - )}h, total=${this.runTimeHours.toFixed(3)}h.` - ); - } else if (!wasActive && willBeActive && !this.runTimeStart) { - // starting new runtime - this.runTimeStart = Date.now(); - this.logger.debug("Runtime timer started."); - } - } - - isValidTransition(newState) { - this.logger.debug( - `Check 1 Transition valid ? From ${ - this.currentState - } To ${newState} => ${this.validTransitions[this.currentState]?.has( - newState - )} ` - ); - this.logger.debug( - `Check 2 Transition valid ? ${ - this.currentState - } is not equal to ${newState} => ${this.currentState !== newState}` - ); - // check if transition is valid and not the same as before - const valid = - this.validTransitions[this.currentState]?.has(newState) && - this.currentState !== newState; - - //if not valid - if (!valid) { - return false; - } else { - return true; - } - } - - getStateDescription(state = this.currentState) { - return this.descriptions[state] || "No description available."; - } - - // NEW: Getter to retrieve current cumulative runtime (active time) in hours. - getRunTimeHours() { - // If currently active add the ongoing duration. - let currentElapsed = 0; - if (this.runTimeStart) { - currentElapsed = (Date.now() - this.runTimeStart) / 3600000; - } - return this.runTimeHours + currentElapsed; - } -} - -module.exports = stateManager; diff --git a/helper/validationUtils.js b/helper/validationUtils.js deleted file mode 100644 index 08f31e6..0000000 --- a/helper/validationUtils.js +++ /dev/null @@ -1,528 +0,0 @@ -/** - * @file validation.js - * - * Permission is hereby granted to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to use it for personal - * or non-commercial purposes, with the following restrictions: - * - * 1. **No Copying or Redistribution**: The Software or any of its parts may not - * be copied, merged, distributed, sublicensed, or sold without explicit - * prior written permission from the author. - * - * 2. **Commercial Use**: Any use of the Software for commercial purposes requires - * a valid license, obtainable only with the explicit consent of the author. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, - * OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Ownership of this code remains solely with the original author. Unauthorized - * use of this Software is strictly prohibited. - - * @summary Validation utility for validating and constraining configuration values. - * @description Validation utility for validating and constraining configuration values. - * @module ValidationUtils - * @requires Logger - * @exports ValidationUtils - * @version 0.1.0 - * @since 0.1.0 -*/ - -const Logger = require("./logger"); - -class ValidationUtils { - constructor(IloggerEnabled, IloggerLevel) { - const loggerEnabled = IloggerEnabled || true; - const loggerLevel = IloggerLevel || "warn"; - this.logger = new Logger(loggerEnabled, loggerLevel, 'ValidationUtils'); - } - - constrain(value, min, max) { - if (typeof value !== "number") { - this.logger?.warn(`Value '${value}' is not a number. Defaulting to ${min}.`); - return min; - } - return Math.min(Math.max(value, min), max); - } - - validateSchema(config, schema, name) { - - const validatedConfig = {}; - let configValue; - - // 1. Remove any unknown keys (keys not defined in the schema). - // Log a warning and omit them from the final config. - for (const key of Object.keys(config)) { - if (!(key in schema)) { - this.logger.warn( - `[${name}] Unknown key '${key}' found in config. Removing it.` - ); - delete config[key]; - } - } - - // Validate each key in the schema and loop over wildcards if they are not in schema - for ( const key in schema ) { - - if (key === "rules" || key === "description" || key === "schema") { - continue; - } - - const fieldSchema = schema[key]; - const { rules = {} } = fieldSchema; - - // Default to the schema's default value if the key is missing - if (config[key] === undefined) { - if (fieldSchema.default === undefined) { - // If there's a nested schema, go deeper with an empty object rather than logging "no rule" - if (rules.schema) { - this.logger.warn(`${name}.${key} has no default, but has a nested schema.`); - validatedConfig[key] = this.validateSchema({}, rules.schema, `${name}.${key}`); - } - else { - this.logger.info( - `There is no rule for ${name}.${key} and no default value. ` + - `Using full schema value but validating deeper levels first...` - ); - - const SubObject = this.validateSchema({}, fieldSchema, `${name}.${key}`); - - validatedConfig[key] = SubObject; - - continue; - } - } else { - this.logger.info(`There is no value provided for ${name}.${key}. Using default value.`); - configValue = fieldSchema.default; - } - //continue; - } else { - // Use the provided value if it exists, otherwise use the default value - configValue = config[key] !== undefined ? config[key] : fieldSchema.default; - } - - // Attempt to parse the value to the expected type if possible - switch (rules.type) { - - case "number": - configValue = this.validateNumber(configValue, rules, fieldSchema, name, key); - break; - case "boolean": - configValue = this.validateBoolean(configValue, name, key); - break; - - case "string": - configValue = this.validateString(configValue,rules,fieldSchema, name, key); - break; - - case "array": - configValue = this.validateArray(configValue, rules, fieldSchema, name, key); - break; - - case "set": - configValue = this.validateSet(configValue, rules, fieldSchema, name, key); - break; - - case "object": - configValue = this.validateObject(configValue, rules, fieldSchema, name, key); - break; - - case "enum": - configValue = this.validateEnum(configValue, rules, fieldSchema, name, key); - break; - - case "curve": - validatedConfig[key] = this.validateCurve(configValue,fieldSchema.default); - continue; - - case "machineCurve": - validatedConfig[key] = this.validateMachineCurve(configValue,fieldSchema.default); - continue; - - case "integer": - validatedConfig[key] = this.validateInteger(configValue, rules, fieldSchema, name, key); - continue; - - case undefined: - // If we see 'rules.schema' but no 'rules.type', treat it like an object: - if (rules.schema && !rules.type) { - // Log a warning and skip the extra pass for nested schema - this.logger.warn( - `${name}.${key} has a nested schema but no type. ` + - `Treating it as type="object" to skip extra pass.` - ); - } else { - // Otherwise, fallback to your existing "validateUndefined" logic - validatedConfig[key] = this.validateUndefined(configValue, fieldSchema, name, key); - } - continue; - - default: - this.logger.warn(`${name}.${key} has an unknown validation type: ${rules.type}. Skipping validation.`); - validatedConfig[key] = fieldSchema.default; - continue; - } - - // Assign the validated or converted value - validatedConfig[key] = configValue; - } - - // Ignore unknown keys by not processing them at all - this.logger.info(`Validation completed for ${name}.`); - - return validatedConfig; - } - - removeUnwantedKeys(obj) { - - if (Array.isArray(obj)) { - return obj.map((item) => this.removeUnwantedKeys(item)); - } - if (obj && typeof obj === "object") { - const newObj = {}; - for (const [k, v] of Object.entries(obj)) { - - // Skip or remove keys like 'default', 'rules', 'description', etc. - if (["rules", "description"].includes(k)) { - continue; - } - - if("default" in v){ - //put the default value in the object - newObj[k] = v.default; - continue; - } - - newObj[k] = this.removeUnwantedKeys(v); - } - return newObj; - } - return obj; - } - - validateMachineCurve(curve, defaultCurve) { - if (!curve || typeof curve !== "object" || Object.keys(curve).length === 0) { - this.logger.warn("Curve is missing or invalid. Defaulting to basic curve."); - return defaultCurve; - } - - // Validate that nq and np exist and are objects - const { nq, np } = curve; - if (!nq || typeof nq !== "object" || !np || typeof np !== "object") { - this.logger.warn("Curve must contain valid 'nq' and 'np' objects. Defaulting to basic curve."); - return defaultCurve; - } - - // Validate that each dimension key points to a valid object with x and y arrays - const validatedNq = this.validateDimensionStructure(nq, "nq"); - const validatedNp = this.validateDimensionStructure(np, "np"); - - if (!validatedNq || !validatedNp) { - return defaultCurve; - } - - return { nq: validatedNq, np: validatedNp }; // Return the validated curve - } - - validateCurve(curve, defaultCurve) { - if (!curve || typeof curve !== "object" || Object.keys(curve).length === 0) { - this.logger.warn("Curve is missing or invalid. Defaulting to basic curve."); - return defaultCurve; - } - - // Validate that each dimension key points to a valid object with x and y arrays - const validatedCurve = this.validateDimensionStructure(curve, "curve"); - if (!validatedCurve) { - return defaultCurve; - } - - return validatedCurve; // Return the validated curve - } - - validateDimensionStructure(dimension, name) { - const validatedDimension = {}; - - for (const [key, value] of Object.entries(dimension)) { - // Validate that each key points to an object with x and y arrays - if (typeof value !== "object") { - this.logger.warn(`Dimension '${name}' key '${key}' is not valid. Returning to default.`); - return false; - } - // Validate that x and y are arrays - else if (!Array.isArray(value.x) || !Array.isArray(value.y)) { - this.logger.warn(`Dimension '${name}' key '${key}' is missing x or y arrays. Converting to arrays.`); - // Try to convert to arrays first - value.x = Object.values(value.x); - value.y = Object.values(value.y); - - // If still not arrays return false - if (!Array.isArray(value.x) || !Array.isArray(value.y)) { - this.logger.warn(`Dimension '${name}' key '${key}' is not valid. Returning to default.`); - return false; - } - } - // Validate that x and y arrays are the same length - else if (value.x.length !== value.y.length) { - this.logger.warn(`Dimension '${name}' key '${key}' has mismatched x and y lengths. Ignoring this key.`); - return false; - } - // Validate that x values are in ascending order - else if (!this.isSorted(value.x)) { - this.logger.warn(`Dimension '${name}' key '${key}' has unsorted x values. Sorting...`); - return false; - } - // Validate that x values are unique - else if (!this.isUnique(value.x)) { - this.logger.warn(`Dimension '${name}' key '${key}' has duplicate x values. Removing duplicates...`); - return false; - } - // Validate that y values are numbers - else if (!this.areNumbers(value.y)) { - this.logger.warn(`Dimension '${name}' key '${key}' has non-numeric y values. Ignoring this key.`); - return false; - } - - validatedDimension[key] = value; - } - return validatedDimension; - } - - isSorted(arr) { - return arr.every((_, i) => i === 0 || arr[i] >= arr[i - 1]); - } - - isUnique(arr) { - return new Set(arr).size === arr.length; - } - - areNumbers(arr) { - return arr.every((x) => typeof x === "number"); - } - - validateNumber(configValue, rules, fieldSchema, name, key) { - - if (typeof configValue !== "number") { - const parsedValue = parseFloat(configValue); - if (!isNaN(parsedValue)) { - this.logger.warn(`${name}.${key} was parsed to a number: ${configValue} -> ${parsedValue}`); - configValue = parsedValue; - } - } - - if (rules.min !== undefined && configValue < rules.min) { - this.logger.warn( - `${name}.${key} is below the minimum (${rules.min}). Using default value.` - ); - return fieldSchema.default; - } - if (rules.max !== undefined && configValue > rules.max) { - this.logger.warn( - `${name}.${key} exceeds the maximum (${rules.max}). Using default value.` - ); - return fieldSchema.default; - } - - this.logger.debug(`${name}.${key} is a valid number: ${configValue}`); - - return configValue; - } - - - validateInteger(configValue, rules, fieldSchema, name, key) { - if (typeof configValue !== "number" || !Number.isInteger(configValue)) { - const parsedValue = parseInt(configValue, 10); - if (!isNaN(parsedValue) && Number.isInteger(parsedValue)) { - this.logger.warn(`${name}.${key} was parsed to an integer: ${configValue} -> ${parsedValue}`); - configValue = parsedValue; - } else { - this.logger.warn(`${name}.${key} is not a valid integer. Using default value.`); - return fieldSchema.default; - } - } - - if (rules.min !== undefined && configValue < rules.min) { - this.logger.warn(`${name}.${key} is below the minimum integer value (${rules.min}). Using default value.`); - return fieldSchema.default; - } - - if (rules.max !== undefined && configValue > rules.max) { - this.logger.warn(`${name}.${key} exceeds the maximum integer value (${rules.max}). Using default value.`); - return fieldSchema.default; - } - - this.logger.debug(`${name}.${key} is a valid integer: ${configValue}`); - return configValue; - } - - validateBoolean(configValue, name, key) { - if (typeof configValue !== "boolean") { - if (configValue === "true" || configValue === "false") { - const parsedValue = configValue === "true"; - this.logger.debug(`${name}.${key} was parsed to a boolean: ${configValue} -> ${parsedValue}`); - configValue = parsedValue; - } - } - return configValue; - } - - validateString(configValue, rules, fieldSchema, name, key) { - let newConfigValue = configValue; - - if (typeof configValue !== "string") { - //check if the value is nullable - if(rules.nullable){ - if(configValue === null){ - return null; - } - } - - this.logger.warn(`${name}.${key} is not a string. Trying to convert to string.`); - newConfigValue = String(configValue); // Coerce to string if not already - } - - //check if the string is a valid string after conversion - if (typeof newConfigValue !== "string") { - this.logger.warn(`${name}.${key} is not a valid string. Using default value.`); - return fieldSchema.default; - } - - return newConfigValue; - } - - validateSet(configValue, rules, fieldSchema, name, key) { - // 1. Ensure we have a Set. If not, use default. - if (!(configValue instanceof Set)) { - this.logger.info(`${name}.${key} is not a Set. Converting to one using default value.`); - return new Set(fieldSchema.default); - } - - // 2. Convert the Set to an array for easier filtering. - const validatedArray = [...configValue] - .filter((item) => { - // 3. Filter based on `rules.itemType`. - switch (rules.itemType) { - case "number": - return typeof item === "number"; - case "string": - return typeof item === "string"; - case "null": - // "null" might mean no type restriction (your usage may vary). - return true; - default: - // Fallback if itemType is something else - return typeof item === rules.itemType; - } - }) - .slice(0, rules.maxLength || Infinity); - - // 4. Check if the filtered array meets the minimum length. - if (validatedArray.length < (rules.minLength || 1)) { - this.logger.warn( - `${name}.${key} contains fewer items than allowed (${rules.minLength}). Using default value.` - ); - return new Set(fieldSchema.default); - } - - // 5. Return a new Set containing only the valid items. - return new Set(validatedArray); - } - - validateArray(configValue, rules, fieldSchema, name, key) { - if (!Array.isArray(configValue)) { - this.logger.info(`${name}.${key} is not an array. Using default value.`); - return fieldSchema.default; - } - - // Validate individual items in the array - const validatedArray = configValue - .filter((item) => { - switch (rules.itemType) { - case "number": - return typeof item === "number"; - case "string": - return typeof item === "string"; - case "null": - // anything goes - return true; - default: - return typeof item === rules.itemType; - } - }) - .slice(0, rules.maxLength || Infinity); - - if (validatedArray.length < (rules.minLength || 1)) { - this.logger.warn( - `${name}.${key} contains fewer items than allowed (${rules.minLength}). Using default value.` - ); - return fieldSchema.default; - } - - return validatedArray; - } - - validateObject(configValue, rules, fieldSchema, name, key) { - if (typeof configValue !== "object" || Array.isArray(configValue)) { - this.logger.warn(`${name}.${key} is not a valid object. Using default value.`); - return fieldSchema.default; - } - - if (rules.schema) { - // Recursively validate nested objects if a schema is defined - return this.validateSchema(configValue || {}, rules.schema, `${name}.${key}`); - } else { - // If no schema is defined, log a warning and use the default - this.logger.warn(`${name}.${key} is an object with no schema. Using default value.`); - return fieldSchema.default; - } - } - - validateEnum(configValue, rules, fieldSchema, name, key) { - - if (Array.isArray(rules.values)) { - - //if value is null take default - if(configValue === null){ - this.logger.warn(`${name}.${key} is null. Using default value.`); - return fieldSchema.default; - } - - const validValues = rules.values.map(e => e.value.toLowerCase()); - - //remove caps - configValue = configValue.toLowerCase(); - - if (!validValues.includes(configValue)) { - this.logger.warn( - `${name}.${key} has an invalid value : ${configValue}. Allowed values: [${validValues.join(", ")}]. Using default value.` - ); - return fieldSchema.default; - } - } else { - this.logger.warn( - `${name}.${key} is an enum with no 'values' array. Using default value.` - ); - return fieldSchema.default; - } - return configValue; - } - - validateUndefined(configValue, fieldSchema, name, key) { - if (typeof configValue === "object" && !Array.isArray(configValue)) { - - this.logger.debug(`${name}.${key} has no defined rules but is an object going 1 level deeper.`); - - // Recursively validate the nested object - return this.validateSchema( configValue || {}, fieldSchema, `${name}.${key}`); - } - else { - this.logger.warn(`${name}.${key} has no defined rules. Using default value.`); - return fieldSchema.default; - } - } -} - -module.exports = ValidationUtils; diff --git a/index.js b/index.js index ac75563..97425f8 100644 --- a/index.js +++ b/index.js @@ -7,13 +7,15 @@ // Core helper modules const menuUtils = require('./src/helper/menuUtils.js'); +const outputUtils = require('./src/helper/outputUtils.js'); const logger = require('./src/helper/logger.js'); const validation = require('./src/helper/validationUtils.js'); +const configUtils = require('./src/helper/configUtils.js'); // Domain-specific modules const measurements = require('./src/measurements/index.js'); -const nrmse = require('./src/nrmse/index.js'); -const state = require('./src/state/index.js'); +const nrmse = require('./src/nrmse/ErrorMetrics.js'); +const state = require('./src/state/state.js'); // Configuration loader with error handling function loadConfig(path) { @@ -59,6 +61,8 @@ function loadAssetDatasets() { // Export everything module.exports = { menuUtils, + outputUtils, + configUtils, logger, validation, measurements, diff --git a/src/convert/definitions/angle.js b/src/convert/definitions/angle.js new file mode 100644 index 0000000..a2f091f --- /dev/null +++ b/src/convert/definitions/angle.js @@ -0,0 +1,49 @@ +var angle; + +angle = { + rad: { + name: { + singular: 'radian' + , plural: 'radians' + } + , to_anchor: 180/Math.PI + } +, deg: { + name: { + singular: 'degree' + , plural: 'degrees' + } + , to_anchor: 1 + } +, grad: { + name: { + singular: 'gradian' + , plural: 'gradians' + } + , to_anchor: 9/10 + } +, arcmin: { + name: { + singular: 'arcminute' + , plural: 'arcminutes' + } + , to_anchor: 1/60 + } +, arcsec: { + name: { + singular: 'arcsecond' + , plural: 'arcseconds' + } + , to_anchor: 1/3600 + } +}; + +module.exports = { + metric: angle +, _anchors: { + metric: { + unit: 'deg' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/apparentPower.js b/src/convert/definitions/apparentPower.js new file mode 100644 index 0000000..58d35c6 --- /dev/null +++ b/src/convert/definitions/apparentPower.js @@ -0,0 +1,49 @@ +var apparentPower; + +apparentPower = { + VA: { + name: { + singular: 'Volt-Ampere' + , plural: 'Volt-Amperes' + } + , to_anchor: 1 + } +, mVA: { + name: { + singular: 'Millivolt-Ampere' + , plural: 'Millivolt-Amperes' + } + , to_anchor: .001 + } +, kVA: { + name: { + singular: 'Kilovolt-Ampere' + , plural: 'Kilovolt-Amperes' + } + , to_anchor: 1000 + } +, MVA: { + name: { + singular: 'Megavolt-Ampere' + , plural: 'Megavolt-Amperes' + } + , to_anchor: 1000000 + } +, GVA: { + name: { + singular: 'Gigavolt-Ampere' + , plural: 'Gigavolt-Amperes' + } + , to_anchor: 1000000000 + } +}; + +module.exports = { + metric: apparentPower +, _anchors: { + metric: { + unit: 'VA' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/area.js b/src/convert/definitions/area.js new file mode 100644 index 0000000..20b374d --- /dev/null +++ b/src/convert/definitions/area.js @@ -0,0 +1,93 @@ +var metric + , imperial; + +metric = { + mm2: { + name: { + singular: 'Square Millimeter' + , plural: 'Square Millimeters' + } + , to_anchor: 1/1000000 + } +, cm2: { + name: { + singular: 'Centimeter' + , plural: 'Centimeters' + } + , to_anchor: 1/10000 + } +, m2: { + name: { + singular: 'Square Meter' + , plural: 'Square Meters' + } + , to_anchor: 1 + } +, ha: { + name: { + singular: 'Hectare' + , plural: 'Hectares' + } + , to_anchor: 10000 + } +, km2: { + name: { + singular: 'Square Kilometer' + , plural: 'Square Kilometers' + } + , to_anchor: 1000000 + } +}; + +imperial = { + 'in2': { + name: { + singular: 'Square Inch' + , plural: 'Square Inches' + } + , to_anchor: 1/144 + } +, yd2: { + name: { + singular: 'Square Yard' + , plural: 'Square Yards' + } + , to_anchor: 9 + } +, ft2: { + name: { + singular: 'Square Foot' + , plural: 'Square Feet' + } + , to_anchor: 1 + } +, ac: { + name: { + singular: 'Acre' + , plural: 'Acres' + } + , to_anchor: 43560 + } +, mi2: { + name: { + singular: 'Square Mile' + , plural: 'Square Miles' + } + , to_anchor: 27878400 + } +}; + +module.exports = { + metric: metric +, imperial: imperial +, _anchors: { + metric: { + unit: 'm2' + , ratio: 10.7639 + } + , imperial: { + unit: 'ft2' + , ratio: 1/10.7639 + } + } +}; diff --git a/src/convert/definitions/current.js b/src/convert/definitions/current.js new file mode 100644 index 0000000..05775df --- /dev/null +++ b/src/convert/definitions/current.js @@ -0,0 +1,35 @@ +var current; + +current = { + A: { + name: { + singular: 'Ampere' + , plural: 'Amperes' + } + , to_anchor: 1 + } +, mA: { + name: { + singular: 'Milliampere' + , plural: 'Milliamperes' + } + , to_anchor: .001 + } +, kA: { + name: { + singular: 'Kiloampere' + , plural: 'Kiloamperes' + } + , to_anchor: 1000 + } +}; + +module.exports = { + metric: current +, _anchors: { + metric: { + unit: 'A' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/digital.js b/src/convert/definitions/digital.js new file mode 100644 index 0000000..e63a4a6 --- /dev/null +++ b/src/convert/definitions/digital.js @@ -0,0 +1,93 @@ +var bits + , bytes; + +bits = { + b: { + name: { + singular: 'Bit' + , plural: 'Bits' + } + , to_anchor: 1 + } +, Kb: { + name: { + singular: 'Kilobit' + , plural: 'Kilobits' + } + , to_anchor: 1024 + } +, Mb: { + name: { + singular: 'Megabit' + , plural: 'Megabits' + } + , to_anchor: 1048576 + } +, Gb: { + name: { + singular: 'Gigabit' + , plural: 'Gigabits' + } + , to_anchor: 1073741824 + } +, Tb: { + name: { + singular: 'Terabit' + , plural: 'Terabits' + } + , to_anchor: 1099511627776 + } +}; + +bytes = { + B: { + name: { + singular: 'Byte' + , plural: 'Bytes' + } + , to_anchor: 1 + } +, KB: { + name: { + singular: 'Kilobyte' + , plural: 'Kilobytes' + } + , to_anchor: 1024 + } +, MB: { + name: { + singular: 'Megabyte' + , plural: 'Megabytes' + } + , to_anchor: 1048576 + } +, GB: { + name: { + singular: 'Gigabyte' + , plural: 'Gigabytes' + } + , to_anchor: 1073741824 + } +, TB: { + name: { + singular: 'Terabyte' + , plural: 'Terabytes' + } + , to_anchor: 1099511627776 + } +}; + +module.exports = { + bits: bits +, bytes: bytes +, _anchors: { + bits: { + unit: 'b' + , ratio: 1/8 + } + , bytes: { + unit: 'B' + , ratio: 8 + } + } +}; diff --git a/src/convert/definitions/each.js b/src/convert/definitions/each.js new file mode 100644 index 0000000..0f4f331 --- /dev/null +++ b/src/convert/definitions/each.js @@ -0,0 +1,30 @@ +var metric + , imperial; + +metric = { + ea: { + name: { + singular: 'Each' + , plural: 'Each' + } + , to_anchor: 1 + }, + dz: { + name: { + singular: 'Dozen' + , plural: 'Dozens' + } + , to_anchor: 12 + } +}; + +module.exports = { + metric: metric +, imperial: {} +, _anchors: { + metric: { + unit: 'ea' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/energy.js b/src/convert/definitions/energy.js new file mode 100644 index 0000000..f885df7 --- /dev/null +++ b/src/convert/definitions/energy.js @@ -0,0 +1,63 @@ +var energy; + +energy = { + Wh: { + name: { + singular: 'Watt-hour' + , plural: 'Watt-hours' + } + , to_anchor: 3600 + } +, mWh: { + name: { + singular: 'Milliwatt-hour' + , plural: 'Milliwatt-hours' + } + , to_anchor: 3.6 + } +, kWh: { + name: { + singular: 'Kilowatt-hour' + , plural: 'Kilowatt-hours' + } + , to_anchor: 3600000 + } +, MWh: { + name: { + singular: 'Megawatt-hour' + , plural: 'Megawatt-hours' + } + , to_anchor: 3600000000 + } +, GWh: { + name: { + singular: 'Gigawatt-hour' + , plural: 'Gigawatt-hours' + } + , to_anchor: 3600000000000 + } +, J: { + name: { + singular: 'Joule' + , plural: 'Joules' + } + , to_anchor: 1 + } +, kJ: { + name: { + singular: 'Kilojoule' + , plural: 'Kilojoules' + } + , to_anchor: 1000 + } +}; + +module.exports = { + metric: energy +, _anchors: { + metric: { + unit: 'J' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/frequency.js b/src/convert/definitions/frequency.js new file mode 100644 index 0000000..c292e8b --- /dev/null +++ b/src/convert/definitions/frequency.js @@ -0,0 +1,78 @@ +var frequency; + +frequency = { + mHz: { + name: { + singular: 'millihertz' + , plural: 'millihertz' + } + , to_anchor: 1/1000 + } +, Hz: { + name: { + singular: 'hertz' + , plural: 'hertz' + } + , to_anchor: 1 + } +, kHz: { + name: { + singular: 'kilohertz' + , plural: 'kilohertz' + } + , to_anchor: 1000 + } +, MHz: { + name: { + singular: 'megahertz' + , plural: 'megahertz' + } + , to_anchor: 1000 * 1000 + } +, GHz: { + name: { + singular: 'gigahertz' + , plural: 'gigahertz' + } + , to_anchor: 1000 * 1000 * 1000 + } +, THz: { + name: { + singular: 'terahertz' + , plural: 'terahertz' + } + , to_anchor: 1000 * 1000 * 1000 * 1000 + } +, rpm: { + name: { + singular: 'rotation per minute' + , plural: 'rotations per minute' + } + , to_anchor: 1/60 + } +, "deg/s": { + name: { + singular: 'degree per second' + , plural: 'degrees per second' + } + , to_anchor: 1/360 + } +, "rad/s": { + name: { + singular: 'radian per second' + , plural: 'radians per second' + } + , to_anchor: 1/(Math.PI * 2) + } +}; + + +module.exports = { + metric: frequency +, _anchors: { + frequency: { + unit: 'hz' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/illuminance.js b/src/convert/definitions/illuminance.js new file mode 100644 index 0000000..eefb1f3 --- /dev/null +++ b/src/convert/definitions/illuminance.js @@ -0,0 +1,37 @@ +var metric, +imperial; + +metric = { + 'lx': { + name: { + singular: 'Lux', + plural: 'Lux' + }, + to_anchor: 1 + } +}; + +imperial = { + 'ft-cd': { + name: { + singular: 'Foot-candle', + plural: 'Foot-candles' + }, + to_anchor: 1 + } +}; + +module.exports = { + metric: metric, + imperial: imperial, + _anchors: { + metric: { + unit: 'lx', + ratio: 1/10.76391 + }, + imperial: { + unit: 'ft-cd', + ratio: 10.76391 + } + } +}; diff --git a/src/convert/definitions/length.js b/src/convert/definitions/length.js new file mode 100644 index 0000000..84a7adf --- /dev/null +++ b/src/convert/definitions/length.js @@ -0,0 +1,86 @@ +var metric, +imperial; + +metric = { + mm: { + name: { + singular: 'Millimeter', + plural: 'Millimeters' + }, + to_anchor: 1/1000 + }, + cm: { + name: { + singular: 'Centimeter', + plural: 'Centimeters' + }, + to_anchor: 1/100 + }, + m: { + name: { + singular: 'Meter', + plural: 'Meters' + }, + to_anchor: 1 + }, + km: { + name: { + singular: 'Kilometer', + plural: 'Kilometers' + }, + to_anchor: 1000 + } +}; + +imperial = { + 'in': { + name: { + singular: 'Inch', + plural: 'Inches' + }, + to_anchor: 1/12 + }, + yd: { + name: { + singular: 'Yard', + plural: 'Yards' + }, + to_anchor: 3 + }, + 'ft-us': { + name: { + singular: 'US Survey Foot', + plural: 'US Survey Feet' + }, + to_anchor: 1.000002 + }, + ft: { + name: { + singular: 'Foot', + plural: 'Feet' + }, + to_anchor: 1 + }, + mi: { + name: { + singular: 'Mile', + plural: 'Miles' + }, + to_anchor: 5280 + } +}; + +module.exports = { + metric: metric, + imperial: imperial, + _anchors: { + metric: { + unit: 'm', + ratio: 3.28084 + }, + imperial: { + unit: 'ft', + ratio: 1/3.28084 + } + } +}; diff --git a/src/convert/definitions/mass.js b/src/convert/definitions/mass.js new file mode 100644 index 0000000..7c60cb8 --- /dev/null +++ b/src/convert/definitions/mass.js @@ -0,0 +1,78 @@ +var metric + , imperial; + +metric = { + mcg: { + name: { + singular: 'Microgram' + , plural: 'Micrograms' + } + , to_anchor: 1/1000000 + } +, mg: { + name: { + singular: 'Milligram' + , plural: 'Milligrams' + } + , to_anchor: 1/1000 + } +, g: { + name: { + singular: 'Gram' + , plural: 'Grams' + } + , to_anchor: 1 + } +, kg: { + name: { + singular: 'Kilogram' + , plural: 'Kilograms' + } + , to_anchor: 1000 +} +, mt: { + name: { + singular: 'Metric Tonne' + , plural: 'Metric Tonnes' + } + , to_anchor: 1000000 + } +}; + +imperial = { + oz: { + name: { + singular: 'Ounce' + , plural: 'Ounces' + } + , to_anchor: 1/16 + } +, lb: { + name: { + singular: 'Pound' + , plural: 'Pounds' + } + , to_anchor: 1 +}, t: { + name: { + singular: 'Ton', + plural: 'Tons', + }, + to_anchor: 2000, + }, +}; + +module.exports = { + metric: metric +, imperial: imperial +, _anchors: { + metric: { + unit: 'g' + , ratio: 1/453.592 + } + , imperial: { + unit: 'lb' + , ratio: 453.592 + } + } +}; diff --git a/src/convert/definitions/pace.js b/src/convert/definitions/pace.js new file mode 100644 index 0000000..1b5cdfa --- /dev/null +++ b/src/convert/definitions/pace.js @@ -0,0 +1,51 @@ +var metric + , imperial; + +metric = { + 'min/km': { + name: { + singular: 'Minute per kilometre' + , plural: 'Minutes per kilometre' + } + , to_anchor: 0.06 + } + ,'s/m': { + name: { + singular: 'Second per metre' + , plural: 'Seconds per metre' + } + , to_anchor: 1 + } +} + +imperial = { + 'min/mi': { + name: { + singular: 'Minute per mile' + , plural: 'Minutes per mile' + } + , to_anchor: 0.0113636 + } + , 's/ft': { + name: { + singular: 'Second per foot' + , plural: 'Seconds per foot' + } + , to_anchor: 1 + } +}; + +module.exports = { + metric: metric +, imperial: imperial +, _anchors: { + metric: { + unit: 's/m' + , ratio: 0.3048 + } + , imperial: { + unit: 's/ft' + , ratio: 1/0.3048 + } + } +}; diff --git a/src/convert/definitions/partsPer.js b/src/convert/definitions/partsPer.js new file mode 100644 index 0000000..333a203 --- /dev/null +++ b/src/convert/definitions/partsPer.js @@ -0,0 +1,44 @@ +var metric + , imperial; + +metric = { + ppm: { + name: { + singular: 'Part-per Million' + , plural: 'Parts-per Million' + } + , to_anchor: 1 + } + , ppb: { + name: { + singular: 'Part-per Billion' + , plural: 'Parts-per Billion' + } + , to_anchor: .001 + } + , ppt: { + name: { + singular: 'Part-per Trillion' + , plural: 'Parts-per Trillion' + } + , to_anchor: .000001 + } + , ppq: { + name: { + singular: 'Part-per Quadrillion' + , plural: 'Parts-per Quadrillion' + } + , to_anchor: .000000001 + } +}; + +module.exports = { + metric: metric + , imperial: {} + , _anchors: { + metric: { + unit: 'ppm' + , ratio: .000001 + } + } +}; diff --git a/src/convert/definitions/power.js b/src/convert/definitions/power.js new file mode 100644 index 0000000..36896cc --- /dev/null +++ b/src/convert/definitions/power.js @@ -0,0 +1,49 @@ +var power; + +power = { + W: { + name: { + singular: 'Watt' + , plural: 'Watts' + } + , to_anchor: 1 + } +, mW: { + name: { + singular: 'Milliwatt' + , plural: 'Milliwatts' + } + , to_anchor: .001 + } +, kW: { + name: { + singular: 'Kilowatt' + , plural: 'Kilowatts' + } + , to_anchor: 1000 + } +, MW: { + name: { + singular: 'Megawatt' + , plural: 'Megawatts' + } + , to_anchor: 1000000 + } +, GW: { + name: { + singular: 'Gigawatt' + , plural: 'Gigawatts' + } + , to_anchor: 1000000000 + } +}; + +module.exports = { + metric: power +, _anchors: { + metric: { + unit: 'W' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/pressure.js b/src/convert/definitions/pressure.js new file mode 100644 index 0000000..91519ff --- /dev/null +++ b/src/convert/definitions/pressure.js @@ -0,0 +1,86 @@ +var metric + , imperial; + +metric = { + Pa: { + name: { + singular: 'pascal' + , plural: 'pascals' + } + , to_anchor: 1/1000 + } +, kPa: { + name: { + singular: 'kilopascal' + , plural: 'kilopascals' + } + , to_anchor: 1 + } +, MPa: { + name: { + singular: 'megapascal' + , plural: 'megapascals' + } + , to_anchor: 1000 + } +, hPa: { + name: { + singular: 'hectopascal' + , plural: 'hectopascals' + } + , to_anchor: 1/10 + } +, bar: { + name: { + singular: 'bar' + , plural: 'bar' + } + , to_anchor: 100 + } + , mbar: { + name: { + singular: 'mbar' + , plural: 'mbar' + } + , to_anchor: 1/10 + } +, torr: { + name: { + singular: 'torr' + , plural: 'torr' + } + , to_anchor: 101325/760000 + } +}; + +imperial = { + psi: { + name: { + singular: 'pound per square inch' + , plural: 'pounds per square inch' + } + , to_anchor: 1/1000 + } +, ksi: { + name: { + singular: 'kilopound per square inch' + , plural: 'kilopound per square inch' + } + , to_anchor: 1 + } +}; + +module.exports = { + metric: metric +, imperial: imperial +, _anchors: { + metric: { + unit: 'kPa' + , ratio: 0.00014503768078 + } + , imperial: { + unit: 'psi' + , ratio: 1/0.00014503768078 + } + } +}; diff --git a/src/convert/definitions/reactiveEnergy.js b/src/convert/definitions/reactiveEnergy.js new file mode 100644 index 0000000..3d7e1a8 --- /dev/null +++ b/src/convert/definitions/reactiveEnergy.js @@ -0,0 +1,49 @@ +var reactiveEnergy; + +reactiveEnergy = { + VARh: { + name: { + singular: 'Volt-Ampere Reactive Hour' + , plural: 'Volt-Amperes Reactive Hour' + } + , to_anchor: 1 + } +, mVARh: { + name: { + singular: 'Millivolt-Ampere Reactive Hour' + , plural: 'Millivolt-Amperes Reactive Hour' + } + , to_anchor: .001 + } +, kVARh: { + name: { + singular: 'Kilovolt-Ampere Reactive Hour' + , plural: 'Kilovolt-Amperes Reactive Hour' + } + , to_anchor: 1000 + } +, MVARh: { + name: { + singular: 'Megavolt-Ampere Reactive Hour' + , plural: 'Megavolt-Amperes Reactive Hour' + } + , to_anchor: 1000000 + } +, GVARh: { + name: { + singular: 'Gigavolt-Ampere Reactive Hour' + , plural: 'Gigavolt-Amperes Reactive Hour' + } + , to_anchor: 1000000000 + } +}; + +module.exports = { + metric: reactiveEnergy +, _anchors: { + metric: { + unit: 'VARh' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/reactivePower.js b/src/convert/definitions/reactivePower.js new file mode 100644 index 0000000..348da53 --- /dev/null +++ b/src/convert/definitions/reactivePower.js @@ -0,0 +1,49 @@ +var reactivePower; + +reactivePower = { + VAR: { + name: { + singular: 'Volt-Ampere Reactive' + , plural: 'Volt-Amperes Reactive' + } + , to_anchor: 1 + } +, mVAR: { + name: { + singular: 'Millivolt-Ampere Reactive' + , plural: 'Millivolt-Amperes Reactive' + } + , to_anchor: .001 + } +, kVAR: { + name: { + singular: 'Kilovolt-Ampere Reactive' + , plural: 'Kilovolt-Amperes Reactive' + } + , to_anchor: 1000 + } +, MVAR: { + name: { + singular: 'Megavolt-Ampere Reactive' + , plural: 'Megavolt-Amperes Reactive' + } + , to_anchor: 1000000 + } +, GVAR: { + name: { + singular: 'Gigavolt-Ampere Reactive' + , plural: 'Gigavolt-Amperes Reactive' + } + , to_anchor: 1000000000 + } +}; + +module.exports = { + metric: reactivePower +, _anchors: { + metric: { + unit: 'VAR' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/speed.js b/src/convert/definitions/speed.js new file mode 100644 index 0000000..81b3567 --- /dev/null +++ b/src/convert/definitions/speed.js @@ -0,0 +1,58 @@ +var metric + , imperial; + +metric = { + 'm/s': { + name: { + singular: 'Metre per second' + , plural: 'Metres per second' + } + , to_anchor: 3.6 + } +, 'km/h': { + name: { + singular: 'Kilometre per hour' + , plural: 'Kilometres per hour' + } + , to_anchor: 1 + } +} + + imperial = { + 'm/h': { + name: { + singular: 'Mile per hour' + , plural: 'Miles per hour' + } + , to_anchor: 1 + } + , knot: { + name: { + singular: 'Knot' + , plural: 'Knots' + } + , to_anchor: 1.150779 + } + , 'ft/s': { + name: { + singular: 'Foot per second' + , plural: 'Feet per second' + } + , to_anchor: 0.681818 + } +}; + +module.exports = { + metric: metric +, imperial: imperial +, _anchors: { + metric: { + unit: 'km/h' + , ratio: 1/1.609344 + } + , imperial: { + unit: 'm/h' + , ratio: 1.609344 + } + } +}; diff --git a/src/convert/definitions/temperature.js b/src/convert/definitions/temperature.js new file mode 100644 index 0000000..a118dbf --- /dev/null +++ b/src/convert/definitions/temperature.js @@ -0,0 +1,55 @@ +var metric + , imperial; + +metric = { + C: { + name: { + singular: 'degree Celsius' + , plural: 'degrees Celsius' + } + , to_anchor: 1 + , anchor_shift: 0 + }, + K: { + name: { + singular: 'degree Kelvin' + , plural: 'degrees Kelvin' + } + , to_anchor: 1 + , anchor_shift: 273.15 + } +}; + +imperial = { + F: { + name: { + singular: 'degree Fahrenheit' + , plural: 'degrees Fahrenheit' + } + , to_anchor: 1 + }, + R: { + name: { + singular: 'degree Rankine' + , plural: 'degrees Rankine' + } + , to_anchor: 1 + , anchor_shift: 459.67 + } +}; + +module.exports = { + metric: metric +, imperial: imperial +, _anchors: { + metric: { + unit: 'C' + , transform: function (C) { return C / (5/9) + 32 } + } + , imperial: { + unit: 'F' + , transform: function (F) { return (F - 32) * (5/9) } + } + } +}; + diff --git a/src/convert/definitions/time.js b/src/convert/definitions/time.js new file mode 100644 index 0000000..fc1ad32 --- /dev/null +++ b/src/convert/definitions/time.js @@ -0,0 +1,86 @@ +var time; +var daysInYear = 365.25; + +time = { + ns: { + name: { + singular: 'Nanosecond' + , plural: 'Nanoseconds' + } + , to_anchor: 1/1000000000 + } +, mu: { + name: { + singular: 'Microsecond' + , plural: 'Microseconds' + } + , to_anchor: 1/1000000 + } +, ms: { + name: { + singular: 'Millisecond' + , plural: 'Milliseconds' + } + , to_anchor: 1/1000 + } +, s: { + name: { + singular: 'Second' + , plural: 'Seconds' + } + , to_anchor: 1 + } +, min: { + name: { + singular: 'Minute' + , plural: 'Minutes' + } + , to_anchor: 60 + } +, h: { + name: { + singular: 'Hour' + , plural: 'Hours' + } + , to_anchor: 60 * 60 + } +, d: { + name: { + singular: 'Day' + , plural: 'Days' + } + , to_anchor: 60 * 60 * 24 + } +, week: { + name: { + singular: 'Week' + , plural: 'Weeks' + } + , to_anchor: 60 * 60 * 24 * 7 + } +, month: { + name: { + singular: 'Month' + , plural: 'Months' + } + , to_anchor: 60 * 60 * 24 * daysInYear / 12 + } +, year: { + name: { + singular: 'Year' + , plural: 'Years' + } + , to_anchor: 60 * 60 * 24 * daysInYear + } +}; + + +module.exports = { + metric: time +, _anchors: { + metric: { + unit: 's' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/voltage.js b/src/convert/definitions/voltage.js new file mode 100644 index 0000000..9234f42 --- /dev/null +++ b/src/convert/definitions/voltage.js @@ -0,0 +1,35 @@ +var voltage; + +voltage = { + V: { + name: { + singular: 'Volt' + , plural: 'Volts' + } + , to_anchor: 1 + } +, mV: { + name: { + singular: 'Millivolt' + , plural: 'Millivolts' + } + , to_anchor: .001 + } +, kV: { + name: { + singular: 'Kilovolt' + , plural: 'Kilovolts' + } + , to_anchor: 1000 + } +}; + +module.exports = { + metric: voltage +, _anchors: { + metric: { + unit: 'V' + , ratio: 1 + } + } +}; diff --git a/src/convert/definitions/volume.js b/src/convert/definitions/volume.js new file mode 100644 index 0000000..ee35057 --- /dev/null +++ b/src/convert/definitions/volume.js @@ -0,0 +1,200 @@ +var metric + , imperial; + +metric = { + mm3: { + name: { + singular: 'Cubic Millimeter' + , plural: 'Cubic Millimeters' + } + , to_anchor: 1/1000000 + } +, cm3: { + name: { + singular: 'Cubic Centimeter' + , plural: 'Cubic Centimeters' + } + , to_anchor: 1/1000 + } +, ml: { + name: { + singular: 'Millilitre' + , plural: 'Millilitres' + } + , to_anchor: 1/1000 + } +, cl: { + name: { + singular: 'Centilitre' + , plural: 'Centilitres' + } + , to_anchor: 1/100 + } +, dl: { + name: { + singular: 'Decilitre' + , plural: 'Decilitres' + } + , to_anchor: 1/10 + } +, l: { + name: { + singular: 'Litre' + , plural: 'Litres' + } + , to_anchor: 1 + } +, kl: { + name: { + singular: 'Kilolitre' + , plural: 'Kilolitres' + } + , to_anchor: 1000 + } +, m3: { + name: { + singular: 'Cubic meter' + , plural: 'Cubic meters' + } + , to_anchor: 1000 + } +, km3: { + name: { + singular: 'Cubic kilometer' + , plural: 'Cubic kilometers' + } + , to_anchor: 1000000000000 + } + +// Swedish units +, krm: { + name: { + singular: 'Matsked' + , plural: 'Matskedar' + } + , to_anchor: 1/1000 +} +, tsk: { + name: { + singular: 'Tesked' + , plural: 'Teskedar' + } + , to_anchor: 5/1000 + } +, msk: { + name: { + singular: 'Matsked' + , plural: 'Matskedar' + } + , to_anchor: 15/1000 + } +, kkp: { + name: { + singular: 'Kaffekopp' + , plural: 'Kaffekoppar' + } + , to_anchor: 150/1000 + } +, glas: { + name: { + singular: 'Glas' + , plural: 'Glas' + } + , to_anchor: 200/1000 + } +, kanna: { + name: { + singular: 'Kanna' + , plural: 'Kannor' + } + , to_anchor: 2.617 + } +}; + +imperial = { + tsp: { + name: { + singular: 'Teaspoon' + , plural: 'Teaspoons' + } + , to_anchor: 1/6 + } +, Tbs: { + name: { + singular: 'Tablespoon' + , plural: 'Tablespoons' + } + , to_anchor: 1/2 + } +, in3: { + name: { + singular: 'Cubic inch' + , plural: 'Cubic inches' + } + , to_anchor: 0.55411 + } +, 'fl-oz': { + name: { + singular: 'Fluid Ounce' + , plural: 'Fluid Ounces' + } + , to_anchor: 1 + } +, cup: { + name: { + singular: 'Cup' + , plural: 'Cups' + } + , to_anchor: 8 + } +, pnt: { + name: { + singular: 'Pint' + , plural: 'Pints' + } + , to_anchor: 16 + } +, qt: { + name: { + singular: 'Quart' + , plural: 'Quarts' + } + , to_anchor: 32 + } +, gal: { + name: { + singular: 'Gallon' + , plural: 'Gallons' + } + , to_anchor: 128 + } +, ft3: { + name: { + singular: 'Cubic foot' + , plural: 'Cubic feet' + } + , to_anchor: 957.506 + } +, yd3: { + name: { + singular: 'Cubic yard' + , plural: 'Cubic yards' + } + , to_anchor: 25852.7 + } +}; + +module.exports = { + metric: metric +, imperial: imperial +, _anchors: { + metric: { + unit: 'l' + , ratio: 33.8140226 + } + , imperial: { + unit: 'fl-oz' + , ratio: 1/33.8140226 + } + } +}; diff --git a/src/convert/definitions/volumeFlowRate.js b/src/convert/definitions/volumeFlowRate.js new file mode 100644 index 0000000..b6cd84f --- /dev/null +++ b/src/convert/definitions/volumeFlowRate.js @@ -0,0 +1,282 @@ +var metric + , imperial; + +metric = { + 'mm3/s': { + name: { + singular: 'Cubic Millimeter per second' + , plural: 'Cubic Millimeters per second' + } + , to_anchor: 1/1000000 + } +, 'cm3/s': { + name: { + singular: 'Cubic Centimeter per second' + , plural: 'Cubic Centimeters per second' + } + , to_anchor: 1/1000 + } +, 'ml/s': { + name: { + singular: 'Millilitre per second' + , plural: 'Millilitres per second' + } + , to_anchor: 1/1000 + } +, 'cl/s': { + name: { + singular: 'Centilitre per second' + , plural: 'Centilitres per second' + } + , to_anchor: 1/100 + } +, 'dl/s': { + name: { + singular: 'Decilitre per second' + , plural: 'Decilitres per second' + } + , to_anchor: 1/10 + } +, 'l/s': { + name: { + singular: 'Litre per second' + , plural: 'Litres per second' + } + , to_anchor: 1 + } +, 'l/min': { + name: { + singular: 'Litre per minute' + , plural: 'Litres per minute' + } + , to_anchor: 1/60 + } +, 'l/h': { + name: { + singular: 'Litre per hour' + , plural: 'Litres per hour' + } + , to_anchor: 1/3600 + } +, 'kl/s': { + name: { + singular: 'Kilolitre per second' + , plural: 'Kilolitres per second' + } + , to_anchor: 1000 + } +, 'kl/min': { + name: { + singular: 'Kilolitre per minute' + , plural: 'Kilolitres per minute' + } + , to_anchor: 50/3 + } +, 'kl/h': { + name: { + singular: 'Kilolitre per hour' + , plural: 'Kilolitres per hour' + } + , to_anchor: 5/18 + } +, 'm3/s': { + name: { + singular: 'Cubic meter per second' + , plural: 'Cubic meters per second' + } + , to_anchor: 1000 + } +, 'm3/min': { + name: { + singular: 'Cubic meter per minute' + , plural: 'Cubic meters per minute' + } + , to_anchor: 50/3 + } +, 'm3/h': { + name: { + singular: 'Cubic meter per hour' + , plural: 'Cubic meters per hour' + } + , to_anchor: 5/18 + } +, 'km3/s': { + name: { + singular: 'Cubic kilometer per second' + , plural: 'Cubic kilometers per second' + } + , to_anchor: 1000000000000 + } +}; + +imperial = { + 'tsp/s': { + name: { + singular: 'Teaspoon per second' + , plural: 'Teaspoons per second' + } + , to_anchor: 1/6 + } +, 'Tbs/s': { + name: { + singular: 'Tablespoon per second' + , plural: 'Tablespoons per second' + } + , to_anchor: 1/2 + } +, 'in3/s': { + name: { + singular: 'Cubic inch per second' + , plural: 'Cubic inches per second' + } + , to_anchor: 0.55411 + } +, 'in3/min': { + name: { + singular: 'Cubic inch per minute' + , plural: 'Cubic inches per minute' + } + , to_anchor: 0.55411/60 + } +, 'in3/h': { + name: { + singular: 'Cubic inch per hour' + , plural: 'Cubic inches per hour' + } + , to_anchor: 0.55411/3600 + } +, 'fl-oz/s': { + name: { + singular: 'Fluid Ounce per second' + , plural: 'Fluid Ounces per second' + } + , to_anchor: 1 + } +, 'fl-oz/min': { + name: { + singular: 'Fluid Ounce per minute' + , plural: 'Fluid Ounces per minute' + } + , to_anchor: 1/60 + } +, 'fl-oz/h': { + name: { + singular: 'Fluid Ounce per hour' + , plural: 'Fluid Ounces per hour' + } + , to_anchor: 1/3600 + } +, 'cup/s': { + name: { + singular: 'Cup per second' + , plural: 'Cups per second' + } + , to_anchor: 8 + } +, 'pnt/s': { + name: { + singular: 'Pint per second' + , plural: 'Pints per second' + } + , to_anchor: 16 + } +, 'pnt/min': { + name: { + singular: 'Pint per minute' + , plural: 'Pints per minute' + } + , to_anchor: 4/15 + } +, 'pnt/h': { + name: { + singular: 'Pint per hour' + , plural: 'Pints per hour' + } + , to_anchor: 1/225 + } +, 'qt/s': { + name: { + singular: 'Quart per second' + , plural: 'Quarts per second' + } + , to_anchor: 32 + } +, 'gal/s': { + name: { + singular: 'Gallon per second' + , plural: 'Gallons per second' + } + , to_anchor: 128 + } +, 'gal/min': { + name: { + singular: 'Gallon per minute' + , plural: 'Gallons per minute' + } + , to_anchor: 32/15 + } +, 'gal/h': { + name: { + singular: 'Gallon per hour' + , plural: 'Gallons per hour' + } + , to_anchor: 8/225 + } +, 'ft3/s': { + name: { + singular: 'Cubic foot per second' + , plural: 'Cubic feet per second' + } + , to_anchor: 957.506 + } +, 'ft3/min': { + name: { + singular: 'Cubic foot per minute' + , plural: 'Cubic feet per minute' + } + , to_anchor: 957.506/60 + } +, 'ft3/h': { + name: { + singular: 'Cubic foot per hour' + , plural: 'Cubic feet per hour' + } + , to_anchor: 957.506/3600 + } +, 'yd3/s': { + name: { + singular: 'Cubic yard per second' + , plural: 'Cubic yards per second' + } + , to_anchor: 25852.7 + } +, 'yd3/min': { + name: { + singular: 'Cubic yard per minute' + , plural: 'Cubic yards per minute' + } + , to_anchor: 25852.7/60 + } +, 'yd3/h': { + name: { + singular: 'Cubic yard per hour' + , plural: 'Cubic yards per hour' + } + , to_anchor: 25852.7/3600 + } +}; + +module.exports = { + metric: metric +, imperial: imperial +, _anchors: { + metric: { + unit: 'l/s' + , ratio: 33.8140227 + } + , imperial: { + unit: 'fl-oz/s' + , ratio: 1/33.8140227 + } + } +}; diff --git a/src/convert/fysics.js b/src/convert/fysics.js new file mode 100644 index 0000000..be9b9bc --- /dev/null +++ b/src/convert/fysics.js @@ -0,0 +1,160 @@ +/* +Copyright: +Year : (c) 2023 +Author : Rene De Ren +Contact details : zn375ix3@gmail.com +Location : The Netherlands + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files +(the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +The author shall be notified of any and all improvements or adaptations this software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +class Fysics{ + + constructor(){ + + //gasses + this.air_density = 0; // weight of air + this.atm_pressure = 1.01325 ; //atm pressure at sea level + this.earth_gravity = 9.80665 ; // acceleration of standard gravity on earth in m/s2 + this.water_molar_mass = 18.01528 // g/mol + this.num_moles_water = 6.022 * 1023; // number of moles in water + this.water_density = 997 ; // this.water_molar_mass * this.num_moles_water // water density in kg/m3; + + //load converter + this.convert = require('./index'); + + // o2 solubility curve based on pressure and temp + this.o2Solubility = { + 1: // abs bar + { + x:[0,5,10,15,20,25,30,35,40,45,50], // temp in degrees celcius + y:[14.6,12.8,11.3,10.1,9.1,8.3,7.6,7,6.5,6,5.6], // mg/l + }, + 2: // abs bar + { + x:[0,5,10,15,20,25,30,35,40,45,50], // temp in degrees celcius + y:[29.2,25.5,22.6,20.2,18.2,16.5,15.2,14,12.9,12,11.3], // mg/l + }, + 4: // abs bar + { + x:[0,5,10,15,20,25,30,35,40,45,50], // temp in degrees celcius + y:[58.4,51.1,45.1,40.3,36.4,33.1,30.3,27.9,25.9,24,22.7], // mg/l + }, + } + + } + + /*------------------- functions -------------------*/ + //use input to calculate air density in kg/m3 is valid up to 100 degrees + //pressure in bar RH in % and temp in degrees celcius + // Antoine Equation is, Log P = A - B / ( T + C ) + // D8 = temp , d7 = RH , pressure in mbar = d6 + //=1.2923*(273.15/(273.15+temp))*(((pressure*100000)-0.3783*((((MACHT(10,(8.07-(1730.63/(233.43+temp)))))*1000/760)*RH)*100))/(1.01325*100000)) + /* + calc_air_dens(pressure,RH,temp){ + + let air_density = + 1.2923 * + ( + 273.15 / ( 273.15 + temp ) + ) + * + ( + ( + ( + pressure * 100000 + ) + - 0.3783 * + ( + ( + ( + ( + Math.pow( 10, ( 8.07 - ( 1730.63 / ( 233.43 + temp) ) ) ) + ) + *1000/760 + ) + *RH + ) + *100 + ) + ) + / (this.atm_pressure * 100000 ) + ); + + return air_density ; + } + */ + + calc_air_dens(pressure, RH, temp) { + const Rd = 287.05; // Specific gas constant for dry air in J/(kg·K) + const Rv = 461.495; // Specific gas constant for water vapor in J/(kg·K) + + // Convert temperature to Kelvin + const T = temp + 273.15; + + // Antoine constants for water vapor + const A = 8.07131; + const B = 1730.63; + const C = 233.426; + + // Calculate saturation vapor pressure (e_s) using the Antoine equation (in hPa) + const e_s = Math.pow(10, (A - (B / (C + temp)))); + + // Actual vapor pressure (e) in hPa + const e = RH * e_s / 100; + + // Convert pressure to Pascals + const pressurePa = this.convert(pressure).from('mbar').to('Pa'); + + // Partial pressure of dry air (Pa) + const p_d = pressurePa - (e * 100); + + // Air density (kg/m³) + const air_density = (p_d / (Rd * T)) + ((e * 100) / (Rv * T)); + + return air_density; + } + + //convert height to pressure ( density => kg/m3 , height => meter) output is in bar + heigth_to_pressure(density,height){ + + //calc pressure + let pressure = density * this.earth_gravity * height; + //convert Pa to bar + pressure = this.convert(pressure).from('Pa').to('mbar'); + + return pressure; + } + + //input is in meters ! + calc_volume(height,width,length){ + let result = 0; + result = height * width * length; + return result ; + } + + +} + +/* +let fysics = new Fysics(); +console.log("converted pressure : " + fysics.heigth_to_pressure(fysics.water_density,10) + " mbar "); +console.log( "air density : " + fysics.calc_air_dens(1.012,0,0) + " kg / m3" ); + +//*/ + +module.exports = Fysics; \ No newline at end of file diff --git a/src/convert/index.js b/src/convert/index.js new file mode 100644 index 0000000..0734221 --- /dev/null +++ b/src/convert/index.js @@ -0,0 +1,304 @@ +var convert + , keys = require('./lodash/lodash.keys') + , each = require('./lodash/lodash.foreach') + , measures = { + length: require('./definitions/length') + , area: require('./definitions/area') + , mass: require('./definitions/mass') + , volume: require('./definitions/volume') + , each: require('./definitions/each') + , temperature: require('./definitions/temperature') + , time: require('./definitions/time') + , digital: require('./definitions/digital') + , partsPer: require('./definitions/partsPer') + , speed: require('./definitions/speed') + , pace: require('./definitions/pace') + , pressure: require('./definitions/pressure') + , current: require('./definitions/current') + , voltage: require('./definitions/voltage') + , power: require('./definitions/power') + , reactivePower: require('./definitions/reactivePower') + , apparentPower: require('./definitions/apparentPower') + , energy: require('./definitions/energy') + , reactiveEnergy: require('./definitions/reactiveEnergy') + , volumeFlowRate: require('./definitions/volumeFlowRate') + , illuminance: require('./definitions/illuminance') + , frequency: require('./definitions/frequency') + , angle : require('./definitions/angle') + } + , Converter; + +Converter = function (numerator, denominator) { + if(denominator) + this.val = numerator / denominator; + else + this.val = numerator; +}; + +/** +* Lets the converter know the source unit abbreviation +*/ +Converter.prototype.from = function (from) { + if(this.destination) + throw new Error('.from must be called before .to'); + + this.origin = this.getUnit(from); + + if(!this.origin) { + this.throwUnsupportedUnitError(from); + } + + return this; +}; + +/** +* Converts the unit and returns the value +*/ +Converter.prototype.to = function (to) { + if(!this.origin) + throw new Error('.to must be called after .from'); + + this.destination = this.getUnit(to); + + var result + , transform; + + if(!this.destination) { + this.throwUnsupportedUnitError(to); + } + + // Don't change the value if origin and destination are the same + if (this.origin.abbr === this.destination.abbr) { + return this.val; + } + + // You can't go from liquid to mass, for example + if(this.destination.measure != this.origin.measure) { + throw new Error('Cannot convert incompatible measures of ' + + this.destination.measure + ' and ' + this.origin.measure); + } + + /** + * Convert from the source value to its anchor inside the system + */ + result = this.val * this.origin.unit.to_anchor; + + /** + * For some changes it's a simple shift (C to K) + * So we'll add it when convering into the unit (later) + * and subtract it when converting from the unit + */ + if (this.origin.unit.anchor_shift) { + result -= this.origin.unit.anchor_shift + } + + /** + * Convert from one system to another through the anchor ratio. Some conversions + * aren't ratio based or require more than a simple shift. We can provide a custom + * transform here to provide the direct result + */ + if(this.origin.system != this.destination.system) { + transform = measures[this.origin.measure]._anchors[this.origin.system].transform; + if (typeof transform === 'function') { + result = transform(result) + } + else { + result *= measures[this.origin.measure]._anchors[this.origin.system].ratio; + } + } + + /** + * This shift has to be done after the system conversion business + */ + if (this.destination.unit.anchor_shift) { + result += this.destination.unit.anchor_shift; + } + + /** + * Convert to another unit inside the destination system + */ + return result / this.destination.unit.to_anchor; +}; + +/** +* Converts the unit to the best available unit. +*/ +Converter.prototype.toBest = function(options) { + if(!this.origin) + throw new Error('.toBest must be called after .from'); + + var options = Object.assign({ + exclude: [], + cutOffNumber: 1, + }, options) + + var best; + /** + Looks through every possibility for the 'best' available unit. + i.e. Where the value has the fewest numbers before the decimal point, + but is still higher than 1. + */ + each(this.possibilities(), function(possibility) { + var unit = this.describe(possibility); + var isIncluded = options.exclude.indexOf(possibility) === -1; + + if (isIncluded && unit.system === this.origin.system) { + var result = this.to(possibility); + if (!best || (result >= options.cutOffNumber && result < best.val)) { + best = { + val: result, + unit: possibility, + singular: unit.singular, + plural: unit.plural + }; + } + } + }.bind(this)); + + return best; +} + +/** +* Finds the unit +*/ +Converter.prototype.getUnit = function (abbr) { + var found; + + each(measures, function (systems, measure) { + each(systems, function (units, system) { + if(system == '_anchors') + return false; + + each(units, function (unit, testAbbr) { + if(testAbbr == abbr) { + found = { + abbr: abbr + , measure: measure + , system: system + , unit: unit + }; + return false; + } + }); + + if(found) + return false; + }); + + if(found) + return false; + }); + + return found; +}; + +var describe = function(resp) { + return { + abbr: resp.abbr + , measure: resp.measure + , system: resp.system + , singular: resp.unit.name.singular + , plural: resp.unit.name.plural + }; +} + +/** +* An alias for getUnit +*/ +Converter.prototype.describe = function (abbr) { + var resp = Converter.prototype.getUnit(abbr); + var desc = null; + + try { + desc = describe(resp); + } catch(err) { + this.throwUnsupportedUnitError(abbr); + } + + return desc; +}; + +/** +* Detailed list of all supported units +*/ +Converter.prototype.list = function (measure) { + var list = []; + + each(measures, function (systems, testMeasure) { + if(measure && measure !== testMeasure) + return; + + each(systems, function (units, system) { + if(system == '_anchors') + return false; + + each(units, function (unit, abbr) { + list = list.concat(describe({ + abbr: abbr, + measure: testMeasure + , system: system + , unit: unit + })); + }); + }); + }); + + return list; +}; + +Converter.prototype.throwUnsupportedUnitError = function (what) { + var validUnits = []; + + each(measures, function (systems, measure) { + each(systems, function (units, system) { + if(system == '_anchors') + return false; + + validUnits = validUnits.concat(keys(units)); + }); + }); + + throw new Error('Unsupported unit ' + what + ', use one of: ' + validUnits.join(', ')); +} + +/** +* Returns the abbreviated measures that the value can be +* converted to. +*/ +Converter.prototype.possibilities = function (measure) { + var possibilities = []; + if(!this.origin && !measure) { + each(keys(measures), function (measure){ + each(measures[measure], function (units, system) { + if(system == '_anchors') + return false; + + possibilities = possibilities.concat(keys(units)); + }); + }); + } else { + measure = measure || this.origin.measure; + each(measures[measure], function (units, system) { + if(system == '_anchors') + return false; + + possibilities = possibilities.concat(keys(units)); + }); + } + + return possibilities; +}; + +/** +* Returns the abbreviated measures that the value can be +* converted to. +*/ +Converter.prototype.measures = function () { + return keys(measures); +}; + +convert = function (value) { + return new Converter(value); +}; + +module.exports = convert; diff --git a/src/convert/lodash/lodash._basebind/LICENSE.txt b/src/convert/lodash/lodash._basebind/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._basebind/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._basebind/README.md b/src/convert/lodash/lodash._basebind/README.md new file mode 100644 index 0000000..55d05fb --- /dev/null +++ b/src/convert/lodash/lodash._basebind/README.md @@ -0,0 +1,15 @@ +# lodash._basebind v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) function `baseBind` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._basebind/index.js b/src/convert/lodash/lodash._basebind/index.js new file mode 100644 index 0000000..6cf782d --- /dev/null +++ b/src/convert/lodash/lodash._basebind/index.js @@ -0,0 +1,58 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseCreate = require('./../lodash._basecreate'), + isObject = require('./../lodash.isobject'), + setBindData = require('./../lodash._setbinddata'); + +/** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ +var arrayRef = []; + +/** Native method shortcuts */ +var push = arrayRef.push; + +/** + * The base implementation of `_.bind` that creates the bound function and + * sets its meta data. + * + * @private + * @param {Array} bindData The bind data array. + * @returns {Function} Returns the new bound function. + */ +function baseBind(bindData) { + var func = bindData[0], + partialArgs = bindData[2], + thisArg = bindData[4]; + + function bound() { + // `Function#bind` spec + // http://es5.github.io/#x15.3.4.5 + if (partialArgs) { + var args = partialArgs.slice(); + push.apply(args, arguments); + } + // mimic the constructor's `return` behavior + // http://es5.github.io/#x13.2.2 + if (this instanceof bound) { + // ensure `new bound` is an instance of `func` + var thisBinding = baseCreate(func.prototype), + result = func.apply(thisBinding, args || arguments); + return isObject(result) ? result : thisBinding; + } + return func.apply(thisArg, args || arguments); + } + setBindData(bound, bindData); + return bound; +} + +module.exports = baseBind; diff --git a/src/convert/lodash/lodash._basebind/package.json b/src/convert/lodash/lodash._basebind/package.json new file mode 100644 index 0000000..e452d30 --- /dev/null +++ b/src/convert/lodash/lodash._basebind/package.json @@ -0,0 +1,21 @@ +{ + "name": "lodash._basebind", + "version": "2.3.0", + "description": "The internal Lo-Dash function `baseBind` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._basecreate": "~2.3.0", + "lodash.isobject": "~2.3.0", + "lodash._setbinddata": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._basecreate/LICENSE.txt b/src/convert/lodash/lodash._basecreate/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._basecreate/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._basecreate/README.md b/src/convert/lodash/lodash._basecreate/README.md new file mode 100644 index 0000000..6c039a8 --- /dev/null +++ b/src/convert/lodash/lodash._basecreate/README.md @@ -0,0 +1,15 @@ +# lodash._basecreate v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) function `baseCreate` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._basecreate/index.js b/src/convert/lodash/lodash._basecreate/index.js new file mode 100644 index 0000000..c6fc38a --- /dev/null +++ b/src/convert/lodash/lodash._basecreate/index.js @@ -0,0 +1,42 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isObject = require('./../lodash.isobject'), + noop = require('./../lodash.noop'), + reNative = require('./../lodash._renative'); + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate; + +/** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ +function baseCreate(prototype, properties) { + return isObject(prototype) ? nativeCreate(prototype) : {}; +} +// fallback for browsers without `Object.create` +if (!nativeCreate) { + baseCreate = (function() { + function Object() {} + return function(prototype) { + if (isObject(prototype)) { + Object.prototype = prototype; + var result = new Object; + Object.prototype = null; + } + return result || global.Object(); + }; + }()); +} + +module.exports = baseCreate; diff --git a/src/convert/lodash/lodash._basecreate/package.json b/src/convert/lodash/lodash._basecreate/package.json new file mode 100644 index 0000000..6a72ca2 --- /dev/null +++ b/src/convert/lodash/lodash._basecreate/package.json @@ -0,0 +1,21 @@ +{ + "name": "lodash._basecreate", + "version": "2.3.0", + "description": "The internal Lo-Dash function `baseCreate` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash.isobject": "~2.3.0", + "lodash.noop": "~2.3.0", + "lodash._renative": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._basecreatecallback/LICENSE.txt b/src/convert/lodash/lodash._basecreatecallback/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._basecreatecallback/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._basecreatecallback/README.md b/src/convert/lodash/lodash._basecreatecallback/README.md new file mode 100644 index 0000000..ff8a676 --- /dev/null +++ b/src/convert/lodash/lodash._basecreatecallback/README.md @@ -0,0 +1,15 @@ +# lodash._basecreatecallback v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) function `baseCreateCallback` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._basecreatecallback/index.js b/src/convert/lodash/lodash._basecreatecallback/index.js new file mode 100644 index 0000000..e60dc44 --- /dev/null +++ b/src/convert/lodash/lodash._basecreatecallback/index.js @@ -0,0 +1,80 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var bind = require('./../lodash.bind'), + identity = require('./../lodash.identity'), + setBindData = require('./../lodash._setbinddata'), + support = require('./../lodash.support'); + +/** Used to detected named functions */ +var reFuncName = /^\s*function[ \n\r\t]+\w/; + +/** Used to detect functions containing a `this` reference */ +var reThis = /\bthis\b/; + +/** Native method shortcuts */ +var fnToString = Function.prototype.toString; + +/** + * The base implementation of `_.createCallback` without support for creating + * "_.pluck" or "_.where" style callbacks. + * + * @private + * @param {*} [func=identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of the created callback. + * @param {number} [argCount] The number of arguments the callback accepts. + * @returns {Function} Returns a callback function. + */ +function baseCreateCallback(func, thisArg, argCount) { + if (typeof func != 'function') { + return identity; + } + // exit early for no `thisArg` or already bound by `Function#bind` + if (typeof thisArg == 'undefined' || !('prototype' in func)) { + return func; + } + var bindData = func.__bindData__; + if (typeof bindData == 'undefined') { + if (support.funcNames) { + bindData = !func.name; + } + bindData = bindData || !support.funcDecomp; + if (!bindData) { + var source = fnToString.call(func); + if (!support.funcNames) { + bindData = !reFuncName.test(source); + } + if (!bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = reThis.test(source); + setBindData(func, bindData); + } + } + } + // exit early if there are no `this` references or `func` is bound + if (bindData === false || (bindData !== true && bindData[1] & 1)) { + return func; + } + switch (argCount) { + case 1: return function(value) { + return func.call(thisArg, value); + }; + case 2: return function(a, b) { + return func.call(thisArg, a, b); + }; + case 3: return function(value, index, collection) { + return func.call(thisArg, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(thisArg, accumulator, value, index, collection); + }; + } + return bind(func, thisArg); +} + +module.exports = baseCreateCallback; diff --git a/src/convert/lodash/lodash._basecreatecallback/package.json b/src/convert/lodash/lodash._basecreatecallback/package.json new file mode 100644 index 0000000..c969bad --- /dev/null +++ b/src/convert/lodash/lodash._basecreatecallback/package.json @@ -0,0 +1,22 @@ +{ + "name": "lodash._basecreatecallback", + "version": "2.3.0", + "description": "The internal Lo-Dash function `baseCreateCallback` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash.bind": "~2.3.0", + "lodash.identity": "~2.3.0", + "lodash._setbinddata": "~2.3.0", + "lodash.support": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._basecreatewrapper/LICENSE.txt b/src/convert/lodash/lodash._basecreatewrapper/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._basecreatewrapper/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._basecreatewrapper/README.md b/src/convert/lodash/lodash._basecreatewrapper/README.md new file mode 100644 index 0000000..8400ff6 --- /dev/null +++ b/src/convert/lodash/lodash._basecreatewrapper/README.md @@ -0,0 +1,15 @@ +# lodash._basecreatewrapper v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) function `baseCreateWrapper` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._basecreatewrapper/index.js b/src/convert/lodash/lodash._basecreatewrapper/index.js new file mode 100644 index 0000000..50309fb --- /dev/null +++ b/src/convert/lodash/lodash._basecreatewrapper/index.js @@ -0,0 +1,78 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseCreate = require('./../lodash._basecreate'), + isObject = require('./../lodash.isobject'), + setBindData = require('./../lodash._setbinddata'), + slice = require('./../lodash._slice'); + +/** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ +var arrayRef = []; + +/** Native method shortcuts */ +var push = arrayRef.push; + +/** + * The base implementation of `createWrapper` that creates the wrapper and + * sets its meta data. + * + * @private + * @param {Array} bindData The bind data array. + * @returns {Function} Returns the new function. + */ +function baseCreateWrapper(bindData) { + var func = bindData[0], + bitmask = bindData[1], + partialArgs = bindData[2], + partialRightArgs = bindData[3], + thisArg = bindData[4], + arity = bindData[5]; + + var isBind = bitmask & 1, + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + key = func; + + function bound() { + var thisBinding = isBind ? thisArg : this; + if (partialArgs) { + var args = partialArgs.slice(); + push.apply(args, arguments); + } + if (partialRightArgs || isCurry) { + args || (args = slice(arguments)); + if (partialRightArgs) { + push.apply(args, partialRightArgs); + } + if (isCurry && args.length < arity) { + bitmask |= 16 & ~32; + return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]); + } + } + args || (args = arguments); + if (isBindKey) { + func = thisBinding[key]; + } + if (this instanceof bound) { + thisBinding = baseCreate(func.prototype); + var result = func.apply(thisBinding, args); + return isObject(result) ? result : thisBinding; + } + return func.apply(thisBinding, args); + } + setBindData(bound, bindData); + return bound; +} + +module.exports = baseCreateWrapper; diff --git a/src/convert/lodash/lodash._basecreatewrapper/package.json b/src/convert/lodash/lodash._basecreatewrapper/package.json new file mode 100644 index 0000000..13ad4a2 --- /dev/null +++ b/src/convert/lodash/lodash._basecreatewrapper/package.json @@ -0,0 +1,22 @@ +{ + "name": "lodash._basecreatewrapper", + "version": "2.3.0", + "description": "The internal Lo-Dash function `baseCreateWrapper` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._basecreate": "~2.3.0", + "lodash.isobject": "~2.3.0", + "lodash._setbinddata": "~2.3.0", + "lodash._slice": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._createwrapper/LICENSE.txt b/src/convert/lodash/lodash._createwrapper/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._createwrapper/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._createwrapper/README.md b/src/convert/lodash/lodash._createwrapper/README.md new file mode 100644 index 0000000..649ef36 --- /dev/null +++ b/src/convert/lodash/lodash._createwrapper/README.md @@ -0,0 +1,15 @@ +# lodash._createwrapper v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) function `createWrapper` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._createwrapper/index.js b/src/convert/lodash/lodash._createwrapper/index.js new file mode 100644 index 0000000..b2b8de3 --- /dev/null +++ b/src/convert/lodash/lodash._createwrapper/index.js @@ -0,0 +1,98 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseBind = require('./../lodash._basebind'), + baseCreateWrapper = require('./../lodash._basecreatewrapper'), + isFunction = require('./../lodash.isfunction'); + +/** + * Used for `Array` method references. + * + * Normally `Array.prototype` would suffice, however, using an array literal + * avoids issues in Narwhal. + */ +var arrayRef = []; + +/** Native method shortcuts */ +var push = arrayRef.push; + +/** + * Creates a function that, when called, either curries or invokes `func` + * with an optional `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to reference. + * @param {number} bitmask The bitmask of method flags to compose. + * The bitmask may be composed of the following flags: + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` + * 8 - `_.curry` (bound) + * 16 - `_.partial` + * 32 - `_.partialRight` + * @param {Array} [partialArgs] An array of arguments to prepend to those + * provided to the new function. + * @param {Array} [partialRightArgs] An array of arguments to append to those + * provided to the new function. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new function. + */ +function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { + var isBind = bitmask & 1, + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + isPartial = bitmask & 16, + isPartialRight = bitmask & 32; + + if (!isBindKey && !isFunction(func)) { + throw new TypeError; + } + if (isPartial && !partialArgs.length) { + bitmask &= ~16; + isPartial = partialArgs = false; + } + if (isPartialRight && !partialRightArgs.length) { + bitmask &= ~32; + isPartialRight = partialRightArgs = false; + } + var bindData = func && func.__bindData__; + if (bindData && bindData !== true) { + bindData = bindData.slice(); + + // set `thisBinding` is not previously bound + if (isBind && !(bindData[1] & 1)) { + bindData[4] = thisArg; + } + // set if previously bound but not currently (subsequent curried functions) + if (!isBind && bindData[1] & 1) { + bitmask |= 8; + } + // set curried arity if not yet set + if (isCurry && !(bindData[1] & 4)) { + bindData[5] = arity; + } + // append partial left arguments + if (isPartial) { + push.apply(bindData[2] || (bindData[2] = []), partialArgs); + } + // append partial right arguments + if (isPartialRight) { + push.apply(bindData[3] || (bindData[3] = []), partialRightArgs); + } + // merge flags + bindData[1] |= bitmask; + return createWrapper.apply(null, bindData); + } + // fast path for `_.bind` + var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper; + return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]); +} + +module.exports = createWrapper; diff --git a/src/convert/lodash/lodash._createwrapper/package.json b/src/convert/lodash/lodash._createwrapper/package.json new file mode 100644 index 0000000..509eccb --- /dev/null +++ b/src/convert/lodash/lodash._createwrapper/package.json @@ -0,0 +1,21 @@ +{ + "name": "lodash._createwrapper", + "version": "2.3.0", + "description": "The internal Lo-Dash function `createWrapper` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._basebind": "~2.3.0", + "lodash._basecreatewrapper": "~2.3.0", + "lodash.isfunction": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._objecttypes/LICENSE.txt b/src/convert/lodash/lodash._objecttypes/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._objecttypes/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._objecttypes/README.md b/src/convert/lodash/lodash._objecttypes/README.md new file mode 100644 index 0000000..58bd76e --- /dev/null +++ b/src/convert/lodash/lodash._objecttypes/README.md @@ -0,0 +1,15 @@ +# lodash._objecttypes v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) variable `objectTypes` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._objecttypes/index.js b/src/convert/lodash/lodash._objecttypes/index.js new file mode 100644 index 0000000..f24fa98 --- /dev/null +++ b/src/convert/lodash/lodash._objecttypes/index.js @@ -0,0 +1,20 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used to determine if values are of the language type Object */ +var objectTypes = { + 'boolean': false, + 'function': true, + 'object': true, + 'number': false, + 'string': false, + 'undefined': false +}; + +module.exports = objectTypes; diff --git a/src/convert/lodash/lodash._objecttypes/package.json b/src/convert/lodash/lodash._objecttypes/package.json new file mode 100644 index 0000000..2dc2610 --- /dev/null +++ b/src/convert/lodash/lodash._objecttypes/package.json @@ -0,0 +1,16 @@ +{ + "name": "lodash._objecttypes", + "version": "2.3.0", + "description": "The internal Lo-Dash variable `objectTypes` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._renative/LICENSE.txt b/src/convert/lodash/lodash._renative/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._renative/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._renative/README.md b/src/convert/lodash/lodash._renative/README.md new file mode 100644 index 0000000..0d9a605 --- /dev/null +++ b/src/convert/lodash/lodash._renative/README.md @@ -0,0 +1,15 @@ +# lodash._renative v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) variable `reNative` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._renative/index.js b/src/convert/lodash/lodash._renative/index.js new file mode 100644 index 0000000..41c1476 --- /dev/null +++ b/src/convert/lodash/lodash._renative/index.js @@ -0,0 +1,23 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Used to resolve the internal [[Class]] of values */ +var toString = objectProto.toString; + +/** Used to detect if a method is native */ +var reNative = RegExp('^' + + String(toString) + .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + .replace(/toString| for [^\]]+/g, '.*?') + '$' +); + +module.exports = reNative; diff --git a/src/convert/lodash/lodash._renative/package.json b/src/convert/lodash/lodash._renative/package.json new file mode 100644 index 0000000..24bdaaf --- /dev/null +++ b/src/convert/lodash/lodash._renative/package.json @@ -0,0 +1,16 @@ +{ + "name": "lodash._renative", + "version": "2.3.0", + "description": "The internal Lo-Dash variable `reNative` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._setbinddata/LICENSE.txt b/src/convert/lodash/lodash._setbinddata/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._setbinddata/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._setbinddata/README.md b/src/convert/lodash/lodash._setbinddata/README.md new file mode 100644 index 0000000..e7ab45d --- /dev/null +++ b/src/convert/lodash/lodash._setbinddata/README.md @@ -0,0 +1,15 @@ +# lodash._setbinddata v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) function `setBindData` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._setbinddata/index.js b/src/convert/lodash/lodash._setbinddata/index.js new file mode 100644 index 0000000..7e86d4c --- /dev/null +++ b/src/convert/lodash/lodash._setbinddata/index.js @@ -0,0 +1,43 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var noop = require('./../lodash.noop'), + reNative = require('./../lodash._renative'); + +/** Used as the property descriptor for `__bindData__` */ +var descriptor = { + 'configurable': false, + 'enumerable': false, + 'value': null, + 'writable': false +}; + +/** Used to set meta data on functions */ +var defineProperty = (function() { + // IE 8 only accepts DOM elements + try { + var o = {}, + func = reNative.test(func = Object.defineProperty) && func, + result = func(o, o, o) && func; + } catch(e) { } + return result; +}()); + +/** + * Sets `this` binding data on a given function. + * + * @private + * @param {Function} func The function to set data on. + * @param {Array} value The data array to set. + */ +var setBindData = !defineProperty ? noop : function(func, value) { + descriptor.value = value; + defineProperty(func, '__bindData__', descriptor); +}; + +module.exports = setBindData; diff --git a/src/convert/lodash/lodash._setbinddata/package.json b/src/convert/lodash/lodash._setbinddata/package.json new file mode 100644 index 0000000..4185301 --- /dev/null +++ b/src/convert/lodash/lodash._setbinddata/package.json @@ -0,0 +1,20 @@ +{ + "name": "lodash._setbinddata", + "version": "2.3.0", + "description": "The internal Lo-Dash function `setBindData` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash.noop": "~2.3.0", + "lodash._renative": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._shimkeys/LICENSE.txt b/src/convert/lodash/lodash._shimkeys/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._shimkeys/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._shimkeys/README.md b/src/convert/lodash/lodash._shimkeys/README.md new file mode 100644 index 0000000..4ce09c9 --- /dev/null +++ b/src/convert/lodash/lodash._shimkeys/README.md @@ -0,0 +1,15 @@ +# lodash._shimkeys v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) function `shimKeys` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._shimkeys/index.js b/src/convert/lodash/lodash._shimkeys/index.js new file mode 100644 index 0000000..4f3e9eb --- /dev/null +++ b/src/convert/lodash/lodash._shimkeys/index.js @@ -0,0 +1,38 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var objectTypes = require('./../lodash._objecttypes'); + +/** Used for native method references */ +var objectProto = Object.prototype; + +/** Native method shortcuts */ +var hasOwnProperty = objectProto.hasOwnProperty; + +/** + * A fallback implementation of `Object.keys` which produces an array of the + * given object's own enumerable property names. + * + * @private + * @type Function + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names. + */ +var shimKeys = function(object) { + var index, iterable = object, result = []; + if (!iterable) return result; + if (!(objectTypes[typeof object])) return result; + for (index in iterable) { + if (hasOwnProperty.call(iterable, index)) { + result.push(index); + } + } + return result +}; + +module.exports = shimKeys; diff --git a/src/convert/lodash/lodash._shimkeys/package.json b/src/convert/lodash/lodash._shimkeys/package.json new file mode 100644 index 0000000..99b6f68 --- /dev/null +++ b/src/convert/lodash/lodash._shimkeys/package.json @@ -0,0 +1,19 @@ +{ + "name": "lodash._shimkeys", + "version": "2.3.0", + "description": "The internal Lo-Dash function `shimKeys` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._objecttypes": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash._slice/LICENSE.txt b/src/convert/lodash/lodash._slice/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash._slice/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash._slice/README.md b/src/convert/lodash/lodash._slice/README.md new file mode 100644 index 0000000..f771fbe --- /dev/null +++ b/src/convert/lodash/lodash._slice/README.md @@ -0,0 +1,15 @@ +# lodash._slice v2.3.0 + +The internal [Lo-Dash](http://lodash.com/) function `slice` as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash._slice/index.js b/src/convert/lodash/lodash._slice/index.js new file mode 100644 index 0000000..bb3f449 --- /dev/null +++ b/src/convert/lodash/lodash._slice/index.js @@ -0,0 +1,38 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * Slices the `collection` from the `start` index up to, but not including, + * the `end` index. + * + * Note: This function is used instead of `Array#slice` to support node lists + * in IE < 9 and to ensure dense arrays are returned. + * + * @private + * @param {Array|Object|string} collection The collection to slice. + * @param {number} start The start index. + * @param {number} end The end index. + * @returns {Array} Returns the new array. + */ +function slice(array, start, end) { + start || (start = 0); + if (typeof end == 'undefined') { + end = array ? array.length : 0; + } + var index = -1, + length = end - start || 0, + result = Array(length < 0 ? 0 : length); + + while (++index < length) { + result[index] = array[start + index]; + } + return result; +} + +module.exports = slice; diff --git a/src/convert/lodash/lodash._slice/package.json b/src/convert/lodash/lodash._slice/package.json new file mode 100644 index 0000000..4ad7827 --- /dev/null +++ b/src/convert/lodash/lodash._slice/package.json @@ -0,0 +1,16 @@ +{ + "name": "lodash._slice", + "version": "2.3.0", + "description": "The internal Lo-Dash function `slice` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.bind/LICENSE.txt b/src/convert/lodash/lodash.bind/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.bind/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.bind/README.md b/src/convert/lodash/lodash.bind/README.md new file mode 100644 index 0000000..d2ef202 --- /dev/null +++ b/src/convert/lodash/lodash.bind/README.md @@ -0,0 +1,15 @@ +# lodash.bind v2.3.0 + +The [Lo-Dash](http://lodash.com/) function [`_.bind`](http://lodash.com/docs#bind) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.bind/index.js b/src/convert/lodash/lodash.bind/index.js new file mode 100644 index 0000000..dc87bee --- /dev/null +++ b/src/convert/lodash/lodash.bind/index.js @@ -0,0 +1,41 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var createWrapper = require('./../lodash._createwrapper'), + reNative = require('./../lodash._renative'), + slice = require('./../lodash._slice'); + +/** + * Creates a function that, when called, invokes `func` with the `this` + * binding of `thisArg` and prepends any additional `bind` arguments to those + * provided to the bound function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to bind. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {...*} [arg] Arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * var func = function(greeting) { + * return greeting + ' ' + this.name; + * }; + * + * func = _.bind(func, { 'name': 'fred' }, 'hi'); + * func(); + * // => 'hi fred' + */ +function bind(func, thisArg) { + return arguments.length > 2 + ? createWrapper(func, 17, slice(arguments, 2), null, thisArg) + : createWrapper(func, 1, null, null, thisArg); +} + +module.exports = bind; diff --git a/src/convert/lodash/lodash.bind/package.json b/src/convert/lodash/lodash.bind/package.json new file mode 100644 index 0000000..734669a --- /dev/null +++ b/src/convert/lodash/lodash.bind/package.json @@ -0,0 +1,22 @@ +{ + "name": "lodash.bind", + "version": "2.3.0", + "description": "The Lo-Dash function `_.bind` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._createwrapper": "~2.3.0", + "lodash._renative": "~2.3.0", + "lodash._slice": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.foreach/LICENSE.txt b/src/convert/lodash/lodash.foreach/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.foreach/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.foreach/README.md b/src/convert/lodash/lodash.foreach/README.md new file mode 100644 index 0000000..2fbd249 --- /dev/null +++ b/src/convert/lodash/lodash.foreach/README.md @@ -0,0 +1,15 @@ +# lodash.foreach v2.3.0 + +The [Lo-Dash](http://lodash.com/) function [`_.forEach`](http://lodash.com/docs#forEach) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.foreach/index.js b/src/convert/lodash/lodash.foreach/index.js new file mode 100644 index 0000000..ac2818f --- /dev/null +++ b/src/convert/lodash/lodash.foreach/index.js @@ -0,0 +1,55 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseCreateCallback = require('./../lodash._basecreatecallback'), + forOwn = require('./../lodash.forown'); + +/** + * Iterates over elements of a collection, executing the callback for each + * element. The callback is bound to `thisArg` and invoked with three arguments; + * (value, index|key, collection). Callbacks may exit iteration early by + * explicitly returning `false`. + * + * Note: As with other "Collections" methods, objects with a `length` property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * + * @static + * @memberOf _ + * @alias each + * @category Collections + * @param {Array|Object|string} collection The collection to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array|Object|string} Returns `collection`. + * @example + * + * _([1, 2, 3]).forEach(function(num) { console.log(num); }).join(','); + * // => logs each number and returns '1,2,3' + * + * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { console.log(num); }); + * // => logs each number and returns the object (property order is not guaranteed across environments) + */ +function forEach(collection, callback, thisArg) { + var index = -1, + length = collection ? collection.length : 0; + + callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); + if (typeof length == 'number') { + while (++index < length) { + if (callback(collection[index], index, collection) === false) { + break; + } + } + } else { + forOwn(collection, callback); + } + return collection; +} + +module.exports = forEach; diff --git a/src/convert/lodash/lodash.foreach/package.json b/src/convert/lodash/lodash.foreach/package.json new file mode 100644 index 0000000..0a2f005 --- /dev/null +++ b/src/convert/lodash/lodash.foreach/package.json @@ -0,0 +1,21 @@ +{ + "name": "lodash.foreach", + "version": "2.3.0", + "description": "The Lo-Dash function `_.forEach` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._basecreatecallback": "~2.3.0", + "lodash.forown": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.forown/LICENSE.txt b/src/convert/lodash/lodash.forown/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.forown/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.forown/README.md b/src/convert/lodash/lodash.forown/README.md new file mode 100644 index 0000000..dd2d34c --- /dev/null +++ b/src/convert/lodash/lodash.forown/README.md @@ -0,0 +1,15 @@ +# lodash.forown v2.3.0 + +The [Lo-Dash](http://lodash.com/) function [`_.forOwn`](http://lodash.com/docs#forOwn) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.forown/index.js b/src/convert/lodash/lodash.forown/index.js new file mode 100644 index 0000000..b76999e --- /dev/null +++ b/src/convert/lodash/lodash.forown/index.js @@ -0,0 +1,50 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var baseCreateCallback = require('./../lodash._basecreatecallback'), + keys = require('./../lodash.keys'), + objectTypes = require('./../lodash._objecttypes'); + +/** + * Iterates over own enumerable properties of an object, executing the callback + * for each property. The callback is bound to `thisArg` and invoked with three + * arguments; (value, key, object). Callbacks may exit iteration early by + * explicitly returning `false`. + * + * @static + * @memberOf _ + * @type Function + * @category Objects + * @param {Object} object The object to iterate over. + * @param {Function} [callback=identity] The function called per iteration. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Object} Returns `object`. + * @example + * + * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { + * console.log(key); + * }); + * // => logs '0', '1', and 'length' (property order is not guaranteed across environments) + */ +var forOwn = function(collection, callback, thisArg) { + var index, iterable = collection, result = iterable; + if (!iterable) return result; + if (!objectTypes[typeof iterable]) return result; + callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3); + var ownIndex = -1, + ownProps = objectTypes[typeof iterable] && keys(iterable), + length = ownProps ? ownProps.length : 0; + + while (++ownIndex < length) { + index = ownProps[ownIndex]; + if (callback(iterable[index], index, collection) === false) return result; + } + return result +}; + +module.exports = forOwn; diff --git a/src/convert/lodash/lodash.forown/package.json b/src/convert/lodash/lodash.forown/package.json new file mode 100644 index 0000000..079de45 --- /dev/null +++ b/src/convert/lodash/lodash.forown/package.json @@ -0,0 +1,22 @@ +{ + "name": "lodash.forown", + "version": "2.3.0", + "description": "The Lo-Dash function `_.forOwn` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._basecreatecallback": "~2.3.0", + "lodash.keys": "~2.3.0", + "lodash._objecttypes": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.identity/LICENSE.txt b/src/convert/lodash/lodash.identity/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.identity/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.identity/README.md b/src/convert/lodash/lodash.identity/README.md new file mode 100644 index 0000000..8c57239 --- /dev/null +++ b/src/convert/lodash/lodash.identity/README.md @@ -0,0 +1,15 @@ +# lodash.identity v2.3.0 + +The [Lo-Dash](http://lodash.com/) function [`_.identity`](http://lodash.com/docs#identity) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.identity/index.js b/src/convert/lodash/lodash.identity/index.js new file mode 100644 index 0000000..595a6e4 --- /dev/null +++ b/src/convert/lodash/lodash.identity/index.js @@ -0,0 +1,28 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * This method returns the first argument provided to it. + * + * @static + * @memberOf _ + * @category Utilities + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'name': 'fred' }; + * _.identity(object) === object; + * // => true + */ +function identity(value) { + return value; +} + +module.exports = identity; diff --git a/src/convert/lodash/lodash.identity/package.json b/src/convert/lodash/lodash.identity/package.json new file mode 100644 index 0000000..1e09a5e --- /dev/null +++ b/src/convert/lodash/lodash.identity/package.json @@ -0,0 +1,17 @@ +{ + "name": "lodash.identity", + "version": "2.3.0", + "description": "The Lo-Dash function `_.identity` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.isfunction/LICENSE.txt b/src/convert/lodash/lodash.isfunction/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.isfunction/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.isfunction/README.md b/src/convert/lodash/lodash.isfunction/README.md new file mode 100644 index 0000000..e16c6a3 --- /dev/null +++ b/src/convert/lodash/lodash.isfunction/README.md @@ -0,0 +1,15 @@ +# lodash.isfunction v2.3.0 + +The [Lo-Dash](http://lodash.com/) function [`_.isFunction`](http://lodash.com/docs#isFunction) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.isfunction/index.js b/src/convert/lodash/lodash.isfunction/index.js new file mode 100644 index 0000000..2b333d3 --- /dev/null +++ b/src/convert/lodash/lodash.isfunction/index.js @@ -0,0 +1,27 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * Checks if `value` is a function. + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + */ +function isFunction(value) { + return typeof value == 'function'; +} + +module.exports = isFunction; diff --git a/src/convert/lodash/lodash.isfunction/package.json b/src/convert/lodash/lodash.isfunction/package.json new file mode 100644 index 0000000..446ae6d --- /dev/null +++ b/src/convert/lodash/lodash.isfunction/package.json @@ -0,0 +1,17 @@ +{ + "name": "lodash.isfunction", + "version": "2.3.0", + "description": "The Lo-Dash function `_.isFunction` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.isobject/LICENSE.txt b/src/convert/lodash/lodash.isobject/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.isobject/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.isobject/README.md b/src/convert/lodash/lodash.isobject/README.md new file mode 100644 index 0000000..897d749 --- /dev/null +++ b/src/convert/lodash/lodash.isobject/README.md @@ -0,0 +1,15 @@ +# lodash.isobject v2.3.0 + +The [Lo-Dash](http://lodash.com/) function [`_.isObject`](http://lodash.com/docs#isObject) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.isobject/index.js b/src/convert/lodash/lodash.isobject/index.js new file mode 100644 index 0000000..fbd5c9c --- /dev/null +++ b/src/convert/lodash/lodash.isobject/index.js @@ -0,0 +1,39 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var objectTypes = require('./../lodash._objecttypes'); + +/** + * Checks if `value` is the language type of Object. + * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @category Objects + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(1); + * // => false + */ +function isObject(value) { + // check if the value is the ECMAScript language type of Object + // http://es5.github.io/#x8 + // and avoid a V8 bug + // http://code.google.com/p/v8/issues/detail?id=2291 + return !!(value && objectTypes[typeof value]); +} + +module.exports = isObject; diff --git a/src/convert/lodash/lodash.isobject/package.json b/src/convert/lodash/lodash.isobject/package.json new file mode 100644 index 0000000..e032a9a --- /dev/null +++ b/src/convert/lodash/lodash.isobject/package.json @@ -0,0 +1,20 @@ +{ + "name": "lodash.isobject", + "version": "2.3.0", + "description": "The Lo-Dash function `_.isObject` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._objecttypes": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.keys/LICENSE.txt b/src/convert/lodash/lodash.keys/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.keys/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.keys/README.md b/src/convert/lodash/lodash.keys/README.md new file mode 100644 index 0000000..5fc0154 --- /dev/null +++ b/src/convert/lodash/lodash.keys/README.md @@ -0,0 +1,15 @@ +# lodash.keys v2.3.0 + +The [Lo-Dash](http://lodash.com/) function [`_.keys`](http://lodash.com/docs#keys) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.keys/index.js b/src/convert/lodash/lodash.keys/index.js new file mode 100644 index 0000000..cc6e7f1 --- /dev/null +++ b/src/convert/lodash/lodash.keys/index.js @@ -0,0 +1,36 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var isObject = require('./../lodash.isobject'), + reNative = require('./../lodash._renative'), + shimKeys = require('./../lodash._shimkeys'); + +/* Native method shortcuts for methods with the same name as other `lodash` methods */ +var nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys; + +/** + * Creates an array composed of the own enumerable property names of an object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns an array of property names. + * @example + * + * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); + * // => ['one', 'two', 'three'] (property order is not guaranteed across environments) + */ +var keys = !nativeKeys ? shimKeys : function(object) { + if (!isObject(object)) { + return []; + } + return nativeKeys(object); +}; + +module.exports = keys; diff --git a/src/convert/lodash/lodash.keys/package.json b/src/convert/lodash/lodash.keys/package.json new file mode 100644 index 0000000..a6ad91b --- /dev/null +++ b/src/convert/lodash/lodash.keys/package.json @@ -0,0 +1,22 @@ +{ + "name": "lodash.keys", + "version": "2.3.0", + "description": "The Lo-Dash function `_.keys` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash.isobject": "~2.3.0", + "lodash._renative": "~2.3.0", + "lodash._shimkeys": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.noop/LICENSE.txt b/src/convert/lodash/lodash.noop/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.noop/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.noop/README.md b/src/convert/lodash/lodash.noop/README.md new file mode 100644 index 0000000..c277049 --- /dev/null +++ b/src/convert/lodash/lodash.noop/README.md @@ -0,0 +1,15 @@ +# lodash.noop v2.3.0 + +The [Lo-Dash](http://lodash.com/) function [`_.noop`](http://lodash.com/docs#noop) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.noop/index.js b/src/convert/lodash/lodash.noop/index.js new file mode 100644 index 0000000..4d43843 --- /dev/null +++ b/src/convert/lodash/lodash.noop/index.js @@ -0,0 +1,26 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ + +/** + * A no-operation function. + * + * @static + * @memberOf _ + * @category Utilities + * @example + * + * var object = { 'name': 'fred' }; + * _.noop(object) === undefined; + * // => true + */ +function noop() { + // no operation performed +} + +module.exports = noop; diff --git a/src/convert/lodash/lodash.noop/package.json b/src/convert/lodash/lodash.noop/package.json new file mode 100644 index 0000000..2849bdd --- /dev/null +++ b/src/convert/lodash/lodash.noop/package.json @@ -0,0 +1,17 @@ +{ + "name": "lodash.noop", + "version": "2.3.0", + "description": "The Lo-Dash function `_.noop` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" } +} \ No newline at end of file diff --git a/src/convert/lodash/lodash.support/LICENSE.txt b/src/convert/lodash/lodash.support/LICENSE.txt new file mode 100644 index 0000000..49869bb --- /dev/null +++ b/src/convert/lodash/lodash.support/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2012-2013 The Dojo Foundation +Based on Underscore.js 1.5.2, copyright 2009-2013 Jeremy Ashkenas, +DocumentCloud and Investigative Reporters & Editors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/src/convert/lodash/lodash.support/README.md b/src/convert/lodash/lodash.support/README.md new file mode 100644 index 0000000..905f3a7 --- /dev/null +++ b/src/convert/lodash/lodash.support/README.md @@ -0,0 +1,15 @@ +# lodash.support v2.3.0 + +The [Lo-Dash](http://lodash.com/) object [`_.support`](http://lodash.com/docs#support) as a [Node.js](http://nodejs.org/) module generated by [lodash-cli](https://npmjs.org/package/lodash-cli). + +## Author + +| [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") | +|---| +| [John-David Dalton](http://allyoucanleet.com/) | + +## Contributors + +| [![twitter/blainebublitz](http://gravatar.com/avatar/ac1c67fd906c9fecd823ce302283b4c1?s=70)](https://twitter.com/blainebublitz "Follow @BlaineBublitz on Twitter") | [![twitter/kitcambridge](http://gravatar.com/avatar/6662a1d02f351b5ef2f8b4d815804661?s=70)](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") | [![twitter/mathias](http://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") | +|---|---|---| +| [Blaine Bublitz](http://www.iceddev.com/) | [Kit Cambridge](http://kitcambridge.be/) | [Mathias Bynens](http://mathiasbynens.be/) | diff --git a/src/convert/lodash/lodash.support/index.js b/src/convert/lodash/lodash.support/index.js new file mode 100644 index 0000000..d4830bf --- /dev/null +++ b/src/convert/lodash/lodash.support/index.js @@ -0,0 +1,40 @@ +/** + * Lo-Dash 2.3.0 (Custom Build) + * Build: `lodash modularize modern exports="npm" -o ./npm/` + * Copyright 2012-2013 The Dojo Foundation + * Based on Underscore.js 1.5.2 + * Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + * Available under MIT license + */ +var reNative = require('./../lodash._renative'); + +/** Used to detect functions containing a `this` reference */ +var reThis = /\bthis\b/; + +/** + * An object used to flag environments features. + * + * @static + * @memberOf _ + * @type Object + */ +var support = {}; + +/** + * Detect if functions can be decompiled by `Function#toString` + * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). + * + * @memberOf _.support + * @type boolean + */ +support.funcDecomp = !reNative.test(global.WinRTError) && reThis.test(function() { return this; }); + +/** + * Detect if `Function#name` is supported (all but IE). + * + * @memberOf _.support + * @type boolean + */ +support.funcNames = typeof Function.name == 'string'; + +module.exports = support; diff --git a/src/convert/lodash/lodash.support/package.json b/src/convert/lodash/lodash.support/package.json new file mode 100644 index 0000000..86bacf4 --- /dev/null +++ b/src/convert/lodash/lodash.support/package.json @@ -0,0 +1,20 @@ +{ + "name": "lodash.support", + "version": "2.3.0", + "description": "The Lo-Dash object `_.support` as a Node.js module generated by lodash-cli.", + "homepage": "http://lodash.com/custom-builds", + "license": "MIT", + "keywords": ["functional", "lodash", "lodash-modularized", "server", "util"], + "author": "John-David Dalton (http://allyoucanleet.com/)", + "contributors": [ + "John-David Dalton (http://allyoucanleet.com/)", + "Blaine Bublitz (http://www.iceddev.com/)", + "Kit Cambridge (http://kitcambridge.be/)", + "Mathias Bynens (http://mathiasbynens.be/)" + ], + "bugs": "https://github.com/lodash/lodash-cli/issues", + "repository": { "type": "git", "url": "https://github.com/lodash/lodash-cli.git" }, + "dependencies": { + "lodash._renative": "~2.3.0" + } +} \ No newline at end of file diff --git a/src/convert/percentError.js b/src/convert/percentError.js new file mode 100644 index 0000000..8ee2a3a --- /dev/null +++ b/src/convert/percentError.js @@ -0,0 +1,3 @@ +module.exports = function (expected, actual) { + return Math.abs((expected - actual) / actual); +} diff --git a/src/helper/menuUtils.js b/src/helper/menuUtils.js index 3e9d474..9d0352a 100644 --- a/src/helper/menuUtils.js +++ b/src/helper/menuUtils.js @@ -1,4 +1,6 @@ -export function initBasicToggles(elements) { +class MenuUtils { + +initBasicToggles(elements) { // Toggle visibility for log level elements.logCheckbox.addEventListener("change", function () { elements.rowLogLevel.style.display = this.checked ? "block" : "none"; @@ -9,7 +11,7 @@ export function initBasicToggles(elements) { } // Define the initialize toggles function within scope -export function initMeasurementToggles(elements) { +initMeasurementToggles(elements) { // Toggle visibility for scaling inputs elements.scalingCheckbox.addEventListener("change", function () { elements.rowInputMin.style.display = this.checked ? "block" : "none"; @@ -25,7 +27,7 @@ export function initMeasurementToggles(elements) { : "none"; } -export function initTensionToggles(elements, node) { +initTensionToggles(elements, node) { const currentMethod = node.interpolationMethod; elements.rowTension.style.display = currentMethod === "monotone_cubic_spline" ? "block" : "none"; @@ -46,14 +48,14 @@ export function initTensionToggles(elements, node) { }); } // Define the smoothing methods population function within scope -export function populateSmoothingMethods(configUrls, elements, node) { - fetchData(configUrls.cloud.config, configUrls.local.config) +populateSmoothingMethods(configUrls, elements, node) { + this.fetchData(configUrls.cloud.config, configUrls.local.config) .then((configData) => { const smoothingMethods = configData.smoothing?.smoothMethod?.rules?.values?.map( (o) => o.value ) || []; - populateDropdown( + this.populateDropdown( elements.smoothMethod, smoothingMethods, node, @@ -65,13 +67,13 @@ export function populateSmoothingMethods(configUrls, elements, node) { }); } -export function populateInterpolationMethods(configUrls, elements, node) { - fetchData(configUrls.cloud.config, configUrls.local.config) +populateInterpolationMethods(configUrls, elements, node) { + this.fetchData(configUrls.cloud.config, configUrls.local.config) .then((configData) => { const interpolationMethods = configData?.interpolation?.type?.rules?.values.map((m) => m.value) || []; - populateDropdown( + this.populateDropdown( elements.interpolationMethodInput, interpolationMethods, node, @@ -80,14 +82,14 @@ export function populateInterpolationMethods(configUrls, elements, node) { // Find the selected method and use it to spawn 1 more field to fill in tension //const selectedMethod = interpolationMethods.find(m => m === node.interpolationMethod); - initTensionToggles(elements, node); + this.initTensionToggles(elements, node); }) .catch((err) => { console.error("Error loading interpolation methods", err); }); } -export function populateLogLevelOptions(logLevelSelect, configData, node) { +populateLogLevelOptions(logLevelSelect, configData, node) { // debug log level //console.log("Displaying configData => ", configData) ; @@ -99,32 +101,31 @@ export function populateLogLevelOptions(logLevelSelect, configData, node) { //console.log("Displaying logLevels => ", logLevels); // Reuse your existing generic populateDropdown helper - populateDropdown(logLevelSelect, logLevels, node.logLevel); + this.populateDropdown(logLevelSelect, logLevels, node.logLevel); } //cascade dropdowns for asset type, supplier, subType, model, unit -export function fetchAndPopulateDropdowns(configUrls, elements, node) { - - fetchData(configUrls.cloud.config, configUrls.local.config) +fetchAndPopulateDropdowns(configUrls, elements, node) { + this.fetchData(configUrls.cloud.config, configUrls.local.config) .then((configData) => { const assetType = configData.asset?.type?.default; - const localSuppliersUrl = constructUrl(configUrls.local.taggcodeAPI,`${assetType}s`,"suppliers.json"); - const cloudSuppliersUrl = constructCloudURL(configUrls.cloud.taggcodeAPI, "/vendor/get_vendors.php"); + const localSuppliersUrl = this.constructUrl(configUrls.local.taggcodeAPI,`${assetType}s`,"suppliers.json"); + const cloudSuppliersUrl = this.constructCloudURL(configUrls.cloud.taggcodeAPI, "/vendor/get_vendors.php"); - return fetchData(cloudSuppliersUrl, localSuppliersUrl) + return this.fetchData(cloudSuppliersUrl, localSuppliersUrl) .then((supplierData) => { const suppliers = supplierData.map((supplier) => supplier.name); // Populate suppliers dropdown and set up its change handler - return populateDropdown( + return this.populateDropdown( elements.supplier, suppliers, node, "supplier", function (selectedSupplier) { if (selectedSupplier) { - populateSubTypes(configUrls, elements, node, selectedSupplier); + this.populateSubTypes(configUrls, elements, node, selectedSupplier); } } ); @@ -132,7 +133,7 @@ export function fetchAndPopulateDropdowns(configUrls, elements, node) { .then(() => { // If we have a saved supplier, trigger subTypes population if (node.supplier) { - populateSubTypes(configUrls, elements, node, node.supplier); + this.populateSubTypes(configUrls, elements, node, node.supplier); } }); }) @@ -141,17 +142,17 @@ export function fetchAndPopulateDropdowns(configUrls, elements, node) { }); } - export function getSpecificConfigUrl(nodeName,cloudAPI) { +getSpecificConfigUrl(nodeName,cloudAPI) { const cloudConfigURL = cloudAPI + "/config/" + nodeName + ".json"; const localConfigURL = "http://localhost:1880/"+ nodeName + "/dependencies/"+ nodeName + "/" + nodeName + "Config.json"; return { cloudConfigURL, localConfigURL }; - } +} // Save changes to API -export async function apiCall(node) { +async apiCall(node) { try{ // OLFIANT when a browser refreshes the tag code is lost!!! fix this later!!!!! // FIX UUID ALSO LATER @@ -218,7 +219,7 @@ export async function apiCall(node) { } -export async function fetchData(url, fallbackUrl) { +async fetchData(url, fallbackUrl) { try { const response = await fetch(url); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); @@ -253,7 +254,7 @@ export async function fetchData(url, fallbackUrl) { } } -export async function fetchProjectData(url) { +async fetchProjectData(url) { try { const response = await fetch(url); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); @@ -265,14 +266,14 @@ export async function fetchProjectData(url) { } } -async function populateDropdown( +async populateDropdown( htmlElement, options, node, property, callback ) { - generateHtml(htmlElement, options, node[property]); + this.generateHtml(htmlElement, options, node[property]); htmlElement.addEventListener("change", async (e) => { const newValue = e.target.value; @@ -285,7 +286,7 @@ async function populateDropdown( } // Helper function to construct a URL from a base and path internal -function constructUrl(base, ...paths) { +constructUrl(base, ...paths) { // Remove trailing slash from base and leading slashes from paths const sanitizedBase = (base || "").replace(/\/+$/, ""); @@ -300,7 +301,7 @@ function constructUrl(base, ...paths) { } //Adjust for API Gateway -function constructCloudURL(base, ...paths) { +constructCloudURL(base, ...paths) { // Remove trailing slash from base and leading slashes from paths const sanitizedBase = base.replace(/\/+$/, ""); const sanitizedPaths = paths.map((path) => path.replace(/^\/+|\/+$/g, "")); @@ -309,21 +310,21 @@ function constructCloudURL(base, ...paths) { return url; } -function populateSubTypes(configUrls, elements, node, selectedSupplier) { +populateSubTypes(configUrls, elements, node, selectedSupplier) { - fetchData(configUrls.cloud.config, configUrls.local.config) + this.fetchData(configUrls.cloud.config, configUrls.local.config) .then((configData) => { const assetType = configData.asset?.type?.default; - const supplierFolder = constructUrl( configUrls.local.taggcodeAPI, `${assetType}s`, selectedSupplier ); + const supplierFolder = this.constructUrl( configUrls.local.taggcodeAPI, `${assetType}s`, selectedSupplier ); - const localSubTypesUrl = constructUrl(supplierFolder, "subtypes.json"); - const cloudSubTypesUrl = constructCloudURL(configUrls.cloud.taggcodeAPI, "/product/get_subtypesFromVendor.php?vendor_name=" + selectedSupplier); + const localSubTypesUrl = this.constructUrl(supplierFolder, "subtypes.json"); + const cloudSubTypesUrl = this.constructCloudURL(configUrls.cloud.taggcodeAPI, "/product/get_subtypesFromVendor.php?vendor_name=" + selectedSupplier); - return fetchData(cloudSubTypesUrl, localSubTypesUrl) + return this.fetchData(cloudSubTypesUrl, localSubTypesUrl) .then((subTypeData) => { const subTypes = subTypeData.map((subType) => subType.name); - return populateDropdown( + return this.populateDropdown( elements.subType, subTypes, node, @@ -331,14 +332,14 @@ function populateSubTypes(configUrls, elements, node, selectedSupplier) { function (selectedSubType) { if (selectedSubType) { // When subType changes, update both models and units - populateModels( + this.populateModels( configUrls, elements, node, selectedSupplier, selectedSubType ); - populateUnitsForSubType( + this.populateUnitsForSubType( configUrls, elements, node, @@ -351,14 +352,14 @@ function populateSubTypes(configUrls, elements, node, selectedSupplier) { .then(() => { // If we have a saved subType, trigger both models and units population if (node.subType) { - populateModels( + this.populateModels( configUrls, elements, node, selectedSupplier, node.subType ); - populateUnitsForSubType(configUrls, elements, node, node.subType); + this.populateUnitsForSubType(configUrls, elements, node, node.subType); } //console.log("In fetch part of subtypes "); // Store all data from selected model @@ -373,9 +374,9 @@ function populateSubTypes(configUrls, elements, node, selectedSupplier) { }); } -function populateUnitsForSubType(configUrls, elements, node, selectedSubType) { +populateUnitsForSubType(configUrls, elements, node, selectedSubType) { // Fetch the units data - fetchData(configUrls.cloud.units, configUrls.local.units) + this.fetchData(configUrls.cloud.units, configUrls.local.units) .then((unitsData) => { // Find the category that matches the subType name const categoryData = unitsData.units.find( @@ -397,7 +398,7 @@ function populateUnitsForSubType(configUrls, elements, node, selectedSubType) { })); // Populate the units dropdown - populateDropdown( + this.populateDropdown( elements.unit, options.map((opt) => opt.value), node, @@ -412,7 +413,7 @@ function populateUnitsForSubType(configUrls, elements, node, selectedSubType) { } else { // If no matching category is found, provide a default % option const defaultUnits = [{ value: "%", description: "Percentage" }]; - populateDropdown( + this.populateDropdown( elements.unit, defaultUnits.map((unit) => unit.value), node, @@ -428,7 +429,7 @@ function populateUnitsForSubType(configUrls, elements, node, selectedSubType) { }); } -function populateModels( +populateModels( configUrls, elements, node, @@ -436,18 +437,18 @@ function populateModels( selectedSubType ) { - fetchData(configUrls.cloud.config, configUrls.local.config) + this.fetchData(configUrls.cloud.config, configUrls.local.config) .then((configData) => { const assetType = configData.asset?.type?.default; // save assetType to fetch later node.assetType = assetType; - const supplierFolder = constructUrl( configUrls.local.taggcodeAPI,`${assetType}s`,selectedSupplier); - const subTypeFolder = constructUrl(supplierFolder, selectedSubType); - const localModelsUrl = constructUrl(subTypeFolder, "models.json"); - const cloudModelsUrl = constructCloudURL(configUrls.cloud.taggcodeAPI, "/product/get_product_models.php?vendor_name=" + selectedSupplier + "&product_subtype_name=" + selectedSubType); + const supplierFolder = this.constructUrl( configUrls.local.taggcodeAPI,`${assetType}s`,selectedSupplier); + const subTypeFolder = this.constructUrl(supplierFolder, selectedSubType); + const localModelsUrl = this.constructUrl(subTypeFolder, "models.json"); + const cloudModelsUrl = this.constructCloudURL(configUrls.cloud.taggcodeAPI, "/product/get_product_models.php?vendor_name=" + selectedSupplier + "&product_subtype_name=" + selectedSubType); - return fetchData(cloudModelsUrl, localModelsUrl).then((modelData) => { + return this.fetchData(cloudModelsUrl, localModelsUrl).then((modelData) => { const models = modelData.map((model) => model.name); // use this to populate the dropdown // If a model is already selected, store its metadata immediately @@ -455,7 +456,7 @@ function populateModels( node["modelMetadata"] = modelData.find((model) => model.name === node.model); } - populateDropdown(elements.model, models, node, "model", (selectedModel) => { + this.populateDropdown(elements.model, models, node, "model", (selectedModel) => { // Store only the metadata for the selected model node["modelMetadata"] = modelData.find((model) => model.name === selectedModel); }); @@ -471,7 +472,7 @@ function populateModels( }); } -function generateHtml(htmlElement, options, savedValue) { +generateHtml(htmlElement, options, savedValue) { htmlElement.innerHTML = options.length ? `${options .map((opt) => ``) @@ -482,3 +483,60 @@ function generateHtml(htmlElement, options, savedValue) { htmlElement.value = savedValue; } } + +createMenuUtilsEndpoint(RED, nodeName, customHelpers = {}) { + RED.httpAdmin.get(`/${nodeName}/resources/menuUtils.js`, function(req, res) { + console.log(`Serving menuUtils.js for ${nodeName} node`); + res.set('Content-Type', 'application/javascript'); + + const browserCode = this.generateMenuUtilsCode(nodeName, customHelpers); + res.send(browserCode); + }.bind(this)); + } + +generateMenuUtilsCode(nodeName, customHelpers = {}) { + const defaultHelpers = { + validateRequired: `function(value) { + return value && value.toString().trim() !== ''; + }`, + formatDisplayValue: `function(value, unit) { + return \`\${value} \${unit || ''}\`.trim(); + }` + }; + + const allHelpers = { ...defaultHelpers, ...customHelpers }; + + const helpersCode = Object.entries(allHelpers) + .map(([name, func]) => ` ${name}: ${func}`) + .join(',\n'); + + const classCode = MenuUtils.toString(); // <-- this gives full class MenuUtils {...} + + return ` + // Create EVOLV namespace structure + window.EVOLV = window.EVOLV || {}; + window.EVOLV.nodes = window.EVOLV.nodes || {}; + window.EVOLV.nodes.${nodeName} = window.EVOLV.nodes.${nodeName} || {}; + + // Inject MenuUtils class + ${classCode} + + // Expose MenuUtils instance to namespace + window.EVOLV.nodes.${nodeName}.utils = { + menuUtils: new MenuUtils(), + + helpers: { +${helpersCode} + } + }; + + // Optionally expose globally + window.MenuUtils = MenuUtils; + + console.log('${nodeName} utilities loaded in namespace'); + `; +} + +} + +module.exports = MenuUtils; \ No newline at end of file diff --git a/src/measurements/Measurement.js b/src/measurements/Measurement.js index f9882b5..121e3ac 100644 --- a/src/measurements/Measurement.js +++ b/src/measurements/Measurement.js @@ -1,5 +1,5 @@ // Add unit conversion support -const convertModule = require('../../../convert/dependencies/index'); +const convertModule = require('../convert/index'); class Measurement { constructor(type, variant, position, windowSize) { diff --git a/src/nrmse/errorMetrics.js b/src/nrmse/errorMetrics.js index c567ec4..07b7765 100644 --- a/src/nrmse/errorMetrics.js +++ b/src/nrmse/errorMetrics.js @@ -3,7 +3,7 @@ const EventEmitter = require('events'); //load all config modules const defaultConfig = require('./nrmseConfig.json'); -const ConfigUtils = require('../configUtils'); +const ConfigUtils = require('../helper/configUtils'); class ErrorMetrics { constructor(config = {}, logger) { diff --git a/src/state/state.js b/src/state/state.js index a2ee626..af33641 100644 --- a/src/state/state.js +++ b/src/state/state.js @@ -5,7 +5,7 @@ const MovementManager = require('./movementManager'); //load all config modules const defaultConfig = require('./stateConfig.json'); -const ConfigUtils = require('../../../generalFunctions/helper/configUtils'); +const ConfigUtils = require('../helper/configUtils'); class state{ constructor(config = {}, logger) {