node-red-contrib-prib-functions 0.17.0 → 0.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,214 @@
1
+ <script type="text/javascript">
2
+ /*globals RED */
3
+ RED.nodes.registerType('matrix', {
4
+ category: 'function',
5
+ color: '#fdeea2',
6
+ defaults: {
7
+ name: {value:null},
8
+ action: {value: "create",required:true},
9
+ args: {value:[]},
10
+ arg: {value:null},"arg-type": {value:"msg"},
11
+ call:{value:null},
12
+ column: {value:null},"column-type": {value:"num"},
13
+ columns: {value:null},"columns-type": {value:"num"},
14
+ end: {value:null},"end-type": {value:"num"},
15
+ factor: {value:null},"factor-type": {value:"num"},
16
+ matrix: {value:"payload"},"matrix-type": {value:"msg"},
17
+ precision: {value:3},"precision-type": {value:"num"},
18
+ row: {value:3},"row-type": {value:"num"},
19
+ rows: {value:3},"rows-type": {value:"num"},
20
+ rowTarget: {value:null},"rowTarget-type": {value:"num"},
21
+ source: {value:"_matrix"},"source-type": {value:"msg"},
22
+ start: {value:null},"start-type": {value:"num"},
23
+ target: {value:"_matrix"},"target-type": {value:"msg"},
24
+ value: {value:"payload"},"value-type": {value:"msg"},
25
+ vector: {value:"payload"},"vector-type": {value:"msg"}
26
+ },
27
+ inputs: 1,
28
+ outputs: 2,
29
+ icon: "icons8-matrix-desktop-80.png",
30
+ align: 'left',
31
+ paletteLabel: "Matrix",
32
+ inputLabels: "Message In",
33
+ outputLabels: ["Message Out","Error"],
34
+ label: function () {
35
+ return this.name || ("Matrix "+this.action||"*** new ***");
36
+ },
37
+ oneditprepare: function() {
38
+ const node=this;
39
+ node.properties=[];
40
+ node.editors=[];
41
+ const actions={
42
+ define:{label:"Define",show:["target"],args:["rows","columns"]},
43
+ defineEmpty:{label:"Define Empty",show:["target"],args:["rows","columns"]},
44
+ create:{label:"Create",show:["target"],args:[]},
45
+ createLike:{label:"Create Like",show:["source","target"],args:[]},
46
+ clone:{label:"Clone",show:["source","target"],args:[]},
47
+ add:{label:"Add",show:["source"],args:["matrix"]},
48
+ addRow:{label:"Add Row",show:["source"],args:["row","vector"]},
49
+ addRow2Row:{label:"Add Row to Row",show:["source"],args:["row","target","factor","start","end"]},
50
+ addCell:{label:"Add to Cell",show:["source"],args:["row","column","value"]},
51
+ subtractCell:{label:"Subtract Cell",show:["source","target"],args:["row","column","value"]},
52
+ multiple:{label:"Multiple",show:["source","target"],args:[]},
53
+ multipleCell:{label:"Multiple Cell",show:["source","target"],args:["rows","columns","value"]},
54
+ divideCell:{label:"Divide Cell",show:["source"],args:["rows","columns","value"]},
55
+ divideRow:{label:"Divide Row",show:["source"],args:["row","factor","start","end"]},
56
+ transpose:{label:"Transpose",show:["source","target"],args:[]},
57
+ getAdjoint:{label:"Adjoint",show:["source","target"],args:[]},
58
+ getCofactor:{label:"Cofactor",show:["source","target"],args:[]},
59
+ getComplementMinor:{label:"Complement Minor",show:["source","target"],args:[]},
60
+ getIdentity:{label:"Identity",show:["source","target"],args:[]},
61
+ getInverse:{label:"Inverse",show:["source","target"],args:[]},
62
+ getInverseAdjointMethod:{label:"Inverse (Adjoint Method)",show:["source","target"],args:[]},
63
+ getInverseGaussJordan:{label:"Inverse (Gauss Jordan Method)",show:["source","target"],args:[]},
64
+ norm:{label:"Norm",show:["source","target"],args:[]},
65
+ getDeterminant:{label:"Determinant",show:["source","target"],args:[]},
66
+ getDeterminantUsingCofactor:{label:"Determinant (Cofactor)",show:["source","target"],args:[]},
67
+ getDeterminantUsingCofactor:{label:"Determinant (Row Echelon Form)",show:["source","target"],args:[]},
68
+ backwardSubstitution:{label:"Backward Substitution",show:["source"],args:[]},
69
+ forwardElimination:{label:"Forward Elimination",show:["source"],args:[]},
70
+ gaussianElimination:{label:"Gaussian Elimination",show:["source"],args:[]},
71
+ reducedRowEchelonForm:{label:"Reduced Row EchelonForm",show:["source"],args:[]},
72
+ rowEchelonForm:{label:"Row Echelon Form",show:["source"],args:[]},
73
+ equalsNearly:{label:"Nearly Equals",show:["source"],args:[]},
74
+ testIsSquare:{label:"Is Square",show:["source"],args:[]},
75
+ get:{label:"Get Cell",show:["source","target"],args:[]},
76
+ sumRow:{label:"Sum Row",show:["source","target"],args:[]},
77
+ swapRows:{label:"Swap Rows",show:["source"],args:[]},
78
+ toArray:{label:"To Array Object",show:["source","target"],args:[]},
79
+ runningSum:{label:"Running Sum",show:["source","target"],args:[]},
80
+ getVandermonde:{label:"Vandermonde",show:["target"],args:["vector","columns"]},
81
+ create:{label:"Create",show:[,"target"],args:["rows","columns"]},
82
+ createForEachCellPairSet:{label:"Create Pair Set Cells",show:["source","target"],args:["matrix","call"],default:{call:"(baseCellValue,matrixCellValue)=>{}"}},
83
+ findRowColumn:{label:"Find in Row",show:["source"],args:["row","call","start","end"],default:{call:"(value,row,column,offset,vector)=>true"}},
84
+ forRowCells:{label:"Row Cells",show:["source"],args:["row","call","start","end"],default:{call:"()=>{}"}},
85
+ fillArray:{label:"fill",show:["source"],args:["matrix"]},
86
+ findColumnRow:{label:"Find in Column",show:["source"],args:["column","call","start","end"],default:{call:"()=>{}"}},
87
+ forColumnCells:{label:"Column Cells",show:["source"],args:["column","call","start","end"],default:{call:"()=>{}"}},
88
+ forEachCell:{label:"For Each Cell",show:["source"],args:["call"],default:{call:"()=>{}"}},
89
+ forEachRow:{label:"For Each Row",show:["source"],args:["call"],default:{call:"()=>{}"}},
90
+ forEachCellPairSet:{label:"For Each Cell Pair Set",show:["source"],args:["matrix","call"],default:{call:"()=>{}"}},
91
+ getIndex:{label:"Get Vector Offset",show:["source","target"],args:["row","column"]},
92
+ getZeroed:{label:"Get Zeroed",show:["source","target"],args:["row","column"]},
93
+ getMatrix:{label:"get Sub Matrix",show:["source","target"],args:["row","column","rows","columns"]},
94
+ getRow:{label:"Get Row",show:["source","target"],args:["row"]},
95
+ maxAbsColumn:{label:"Column Maximum Absolute",show:["source","target"],args:["column","start"]},
96
+ maxColumn:{label:"Column Max",show:["source","target"],args:["column","start"]},
97
+ multiplyRow:{label:"Multiply Row",show:["source"],args:["row","factor"]},
98
+ reduceRow:{label:"Reduce Row",show:["source","target"],args:["row","call","value"],default:{call:"(agregatevalue,cellValue,row,column)=>agregatevalue+cellValue"}},
99
+ set:{label:"Set Cell",show:["source"],args:["row","column","value"]},
100
+ setRow:{label:"Set Row",show:["source"],args:["vector","row"]},
101
+ reduce:{label:"Reduce Cells",show:["source","target"],args:["call","value"],default:{call:"()=>{}"}}
102
+ };
103
+ const baseDiv=$("#node-inputDynamicBase");
104
+ function defineProperty(property,...types) {
105
+ const element=$('<div/>',{ "class": "form-row form-row-http-in-"+property.name+" hide" }).append(
106
+ $('<label for="node-input-'+property.name+'" style="white-space: nowrap"><i class="fa fa-'+(property.icon||'bookmark')+'"></i> '+property.label+'</label>'),
107
+ );
108
+ element.appendTo(baseDiv);
109
+ node.properties.push(property.name);
110
+ if(types[0]=="edit") {
111
+ element.append($('<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-'+property.name+'-editor"></div>'));
112
+ node.editors[property.name] = RED.editor.createEditor({
113
+ id: 'node-input-'+property.name+'-editor',
114
+ mode: 'ace/mode/'+property.mode||"text",
115
+ value: node[property.name]||property.default
116
+ });
117
+ } else {
118
+ const inputNode=$('<input type="text" id="node-input-'+property.name+'"/>').val(node[property.name]);
119
+ const typeNode=$('<input type="hidden" id="node-input-'+property.name+'-type"/>');
120
+ element.append([inputNode,typeNode]);
121
+ const typeValue=node[property.name+"-type"];
122
+ if(typeValue) typeNode.val(typeValue);
123
+ $("#node-input-"+property.name).typedInput({
124
+ type:typeValue||types[0],
125
+ types:types,
126
+ typeField: "#node-input-"+property.name+"-type"
127
+ });
128
+ }
129
+ }
130
+ defineProperty({name:"source" ,label:"Source" ,icon:"crosshairs"},"msg","flow","global");
131
+ defineProperty({name:"arg" ,label:"Argument" ,icon:"tag"},"num","json","msg","flow","global","env");
132
+ defineProperty({name:"matrix" ,label:"Matrix" ,icon:"th"},"msg","flow","global");
133
+ defineProperty({name:"target" ,label:"Target" ,icon:"save"},"msg","flow","global");
134
+ defineProperty({name:"column" ,label:"Column" ,icon:"bars fa-rotate-90"},"num","msg","flow","global");
135
+ defineProperty({name:"columns" ,label:"Columns" ,icon:"bars fa-rotate-90"},"num","msg","flow","global");
136
+ defineProperty({name:"row" ,label:"Row" ,icon:"bars"},"num","msg","flow","global");
137
+ defineProperty({name:"rows" ,label:"Rows" ,icon:"bars"},"num","msg","flow","global");
138
+ defineProperty({name:"value" ,label:"Value" ,icon:"tachometer"},"num","msg","flow","global");
139
+ defineProperty({name:"rowTarget",label:"Target Row" ,icon:"bars"},"num","msg","flow","global");
140
+ defineProperty({name:"factor" ,label:"Factor" ,icon:"adjust"},"num","msg","flow","global");
141
+ defineProperty({name:"precision",label:"Precision" ,icon:"tachometer"},"num","msg","flow","global");
142
+ defineProperty({name:"start" ,label:"Start" ,icon:"tachometer"},"num","msg","flow","global");
143
+ defineProperty({name:"end" ,label:"End" ,icon:"tachometer"},"num","msg","flow","global");
144
+ defineProperty({name:"size" ,label:"Size" ,icon:"tachometer"},"num","msg","flow","global");
145
+ defineProperty({name:"vector" ,label:"Vector" ,icon:"ellipsis-h"},"json","msg","flow","global");
146
+ defineProperty({name:"call" ,label:"Call" ,icon:"js",mode:"javascript"},"edit");
147
+
148
+ const options=Object.keys(actions).reduce((previousValue,property)=>previousValue.concat({value:property,label:actions[property].label}),
149
+ []);
150
+ const actionNode=$("#node-input-action");
151
+ actionNode.typedInput({
152
+ types: [{
153
+ value: "actionType",
154
+ options: options
155
+ }]
156
+ });
157
+ actionNode.change(function() {
158
+ action=$(this).val();
159
+ node.args=[];
160
+ node.properties.forEach(property=>$(".form-row-http-in-"+property).hide());
161
+ const actionDef=actions[action];
162
+ node.args=actionDef.args;
163
+ node.args.forEach(property=>$(".form-row-http-in-"+property).show());
164
+ actionDef.show.forEach(property=>$(".form-row-http-in-"+property).show());
165
+
166
+ });
167
+ },
168
+ oneditsave: function() {
169
+ const node=this;
170
+ Object.keys(node.editors).forEach(property=>{
171
+ const editor=node.editors[property];
172
+ node[property]=editor.getValue();
173
+ editor.destroy();
174
+ delete editor;
175
+ })
176
+ },
177
+ oneditcancel: function() {
178
+ const node=this;
179
+ Object.keys(node.editors).forEach(property=>{
180
+ const editor=node.editors[property];
181
+ editor.destroy();
182
+ delete editor;
183
+ });
184
+ },
185
+ resizeRule: function(file,newWidth) {
186
+ }
187
+ });
188
+ </script>
189
+
190
+ <script type="text/x-red" data-template-name="matrix">
191
+
192
+ <div class="form-row">
193
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name </label>
194
+ <input type="text" id="node-input-name" placeholder="Name">
195
+ </div>
196
+ <div class="form-row">
197
+ <label for="node-input-action" style="white-space: nowrap"><i class="fa fa-cog"></i> Action</label>
198
+ <input type="text" id="node-input-action">
199
+ </div>
200
+ <div id="node-inputDynamicBase"/>
201
+ </script>
202
+
203
+ <script type="text/x-red" data-help-name="matrix">
204
+ <p>
205
+ Matrix manipulation
206
+ </p>
207
+ <h3>Inputs</h3>
208
+ <dl class="message-properties">
209
+ <dt>msg <span class="property-type">topic</span></dt>
210
+ <dd>incoming message with topic</dd>
211
+ <dt>msg <span class="property-type">payload</span></dt>
212
+ <dd></dd>
213
+ </dl>
214
+ </script>
@@ -0,0 +1,162 @@
1
+ const logger = new (require("node-red-contrib-logger"))("matrix");
2
+ logger.sendInfo("Copyright 2022 Jaroslav Peter Prib");
3
+ const Matrix = require("./matrix");
4
+ function error(node,message,shortMessage){
5
+ if(logger.active) logger.send({label:"error",node:node.id,error:error,shortMessage});
6
+ node.error(message);
7
+ node.status({fill:"red",shape:"ring",text:shortMessage});
8
+ }
9
+ function evalFunction(id,mapping){
10
+ logger.sendInfo({label:"evalFunction",id:id,mapping:mapping})
11
+ try{
12
+ return eval(mapping);
13
+ } catch(ex) {
14
+ logger.sendError({label:"evalFunction error",id:id,mapping:mapping,error:ex.message})
15
+ throw Error(id+" "+ex.message);
16
+ }
17
+ }
18
+ function evalInFunction(node,propertyName){
19
+ try{
20
+ const nodeContext = node.context();
21
+ const flow = nodeContext.flow;
22
+ const global = nodeContext.global;
23
+ const property=node[propertyName];
24
+ if(property==null) throw Error("no value for "+propertyName);
25
+ const propertyType=propertyName+"-type";
26
+ switch (node[propertyType]){
27
+ case "num":
28
+ case "json":
29
+ return evalFunction(propertyName,"()=>"+property);
30
+ case "node":
31
+ return evalFunction(propertyName,"()=>nodeContext.get("+property+")");
32
+ case "flow":
33
+ if(flow) throw Error("context store may be memoryonly so flow doesn't work")
34
+ return evalFunction(propertyName,"()=>flow.get("+property+")");
35
+ case "global":
36
+ return evalFunction(propertyName,"()=>global.get("+property+")");
37
+ case "env":
38
+ return evalFunction(propertyName,"()=>env.get("+property+")");
39
+ case "msg":
40
+ return evalFunction(propertyName,"(msg)=>msg."+property);
41
+ default:
42
+ logger.sendInfo({label:"setData unknown type",action:node.action,propertyType:propertyType,type:node[propertyType]});
43
+ throw Error("unknown type "+node[propertyType])
44
+ }
45
+ } catch(ex) {
46
+ logger.sendError({label:"setup",error:ex.message,stack:ex.stack});
47
+ throw Error(property+" "+ex.message);
48
+ }
49
+ }
50
+ function argsArray(node,msg) {
51
+ const args=[];
52
+ node.argFunction.forEach(callFunction=> {
53
+ const result=callFunction(msg);
54
+ args.push(result);
55
+ });
56
+ return args;
57
+ }
58
+ module.exports = function (RED) {
59
+ function matrixNode(n) {
60
+ RED.nodes.createNode(this,n);
61
+ // logger.sendInfo({label:"create",node:n});
62
+ const node=Object.assign(this,n);
63
+ try{
64
+ if(node.source)node.getSource=evalInFunction(node,"source");
65
+ if(node.target) {
66
+ const nodeContext = node.context();
67
+ const flow = nodeContext.flow;
68
+ const global = nodeContext.global;
69
+ switch(node["target-type"]){
70
+ case "node":
71
+ node.setData=evalFunction("target","data=>nodeContext.set("+node.target+",data)");
72
+ break;
73
+ case "flow":
74
+ if(flow) throw Error("context store may be memoryonly so flow doesn't work")
75
+ node.setData=evalFunction("target","data=>flow.set("+node.target+",data)");
76
+ break;
77
+ case "global":
78
+ node.setData=evalFunction("target","data=>global.set("+node.target+",data)");
79
+ break;
80
+ case "msg":
81
+ node.setData=evalFunction("target","(data,msg)=>{msg."+node.target+"=data;}");
82
+ break;
83
+ default:
84
+ logger.sendInfo({label:"setData unknown type",action:node.action,targetType:node["target-type"]});
85
+ }
86
+ }
87
+ node.argFunction=[];
88
+ node.args.forEach(property=>{
89
+ node.argFunction.push(evalInFunction(node,property).bind(this));
90
+ })
91
+ function baseProcess(msg){
92
+ const sourceIn=node.getSource(msg);
93
+ if(sourceIn==null) throw Error("source data not found");
94
+ const sourceMatrix=(sourceIn instanceof Matrix?sourceIn:new Matrix(sourceIn));
95
+ return sourceMatrix[node.action].apply(sourceMatrix,argsArray(node,msg));
96
+ }
97
+ function baseProcessAndSet(msg){
98
+ const result=baseProcess(msg);
99
+ node.setData.apply(node,[result,msg]);
100
+ }
101
+ function createProcess(msg){
102
+ const sourceIn=node.getSource(msg);
103
+ if(sourceIn==null) throw Error("source data not found");
104
+ const sourceMatrix=(sourceIn instanceof Matrix?sourceIn.clone():new Matrix(sourceIn));
105
+ node.setData.apply(node,[sourceMatrix,msg]);
106
+ }
107
+ function defineProcess(msg){
108
+ if(logger.active) logger.sendInfo({label:"define",arg:{rows:node.row,columns:node.column}});
109
+ const sourceMatrix=new Matrix({rows:node.rows,columns:node.columns});
110
+ node.setData.apply(node,[sourceMatrix,msg]);
111
+ }
112
+ function defineEmptyProcess(msg){
113
+ if(logger.active) logger.sendInfo({label:"define",arg:{rowsMax:node.row,columns:node.column}});
114
+ const sourceMatrix=new Matrix({rowsMax:node.rows,columns:node.columns});
115
+ node.setData.apply(node,[sourceMatrix,msg]);
116
+ }
117
+ function createSize(msg){
118
+ const sourceMatrix=new Matrix({rows:node.size,columns:node.size});
119
+ node.setData.apply(node,[sourceMatrix[node.action](),msg]);
120
+ }
121
+ function createDummy(msg){
122
+ const sourceMatrix=new Matrix(1,1);
123
+ node.setData.apply(node,[sourceMatrix[node.action].apply(sourceMatrix,argsArray(node,msg)),msg]);
124
+ }
125
+ node.msgProcess=baseProcess;
126
+ if(["define"].includes(node.action)){
127
+ node.msgProcess=defineProcess;
128
+ }else if(["defineEmpty"].includes(node.action)){
129
+ node.msgProcess=defineEmptyProcess;
130
+ }else if(["create"].includes(node.action)){
131
+ node.msgProcess=createProcess;
132
+ }else if(["runningSum"].includes(node.action)){
133
+ node.msgProcess=createSize;
134
+ }else if(["getVandermonde"].includes(node.action)){
135
+ node.msgProcess=createDummy;
136
+ }else{
137
+ if(node.action.startsWith("get")
138
+ || ["create","createLike","clone","transpose","sumRow","createForEachCellPairSet",
139
+ ,"findRowColumn","findColumnRow","maxAbsColumn","maxColumn","toArray"
140
+ ].includes(node.action)) {
141
+ node.msgProcess=baseProcessAndSet;
142
+ }
143
+ }
144
+ } catch(ex) {
145
+ logger.sendError({label:"setup",error:ex.message,stack:ex.stack})
146
+ error(node,ex,"Invalid setup "+ex.message);
147
+ return;
148
+ }
149
+ node.status({fill:"green",shape:"ring"});
150
+ node.on("input",function (msg) {
151
+ try{
152
+ node.msgProcess(msg);
153
+ node.send(msg);
154
+ } catch(ex) {
155
+ msg.error=ex.message;
156
+ node.send([null,msg]);
157
+ if(logger.active) logger.send({label:"error",node:node.id,action:node.action,exception:ex.message,stack:ex.stack});
158
+ }
159
+ });
160
+ }
161
+ RED.nodes.registerType(logger.label, matrixNode);
162
+ };
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "node-red-contrib-prib-functions",
3
- "version": "0.17.0",
3
+ "version": "0.19.2",
4
4
  "description": "Node-RED added node functions.",
5
5
  "dependencies": {
6
6
  "avsc": "^5.6.1",
7
+ "compressiontool": "*",
7
8
  "fast-xml-parser": "^3.19.0",
8
- "node-red-contrib-logger": "^0.0.6",
9
+ "node-red-contrib-logger": "latest",
10
+ "node-red-contrib-noderedbase": ">=0.0.16",
9
11
  "xlsx": "^0.17.0"
10
12
  },
11
13
  "devDependencies": {
@@ -14,11 +16,12 @@
14
16
  "bcrypt": "^5.0.1",
15
17
  "bl": "^5.0.0",
16
18
  "mocha": "^9.2.2",
17
- "node-red": "^2.2.2",
18
- "node-red-node-test-helper": "^0.2.7"
19
+ "node-red": "^3.0.2",
20
+ "node-red-node-test-helper": "^0.3.0"
19
21
  },
20
22
  "scripts": {
21
- "test": "mocha \"test/**/e*.js\""
23
+ "test": "mocha \"test/matrix/**/*.js\"",
24
+ "startNodeRed": "pwd; node-red --title '***test nodered***' --setting ./test/data/settings.js ./test/data/flow.json"
22
25
  },
23
26
  "repository": {
24
27
  "type": "git",
@@ -26,32 +29,49 @@
26
29
  },
27
30
  "keywords": [
28
31
  "node-red",
32
+ "adjoint",
29
33
  "append",
30
34
  "analysis",
31
35
  "average",
32
36
  "avg",
33
37
  "AVRO",
34
38
  "arvo",
39
+ "backward substitution",
35
40
  "compare",
41
+ "Complement Minor",
42
+ "compression",
36
43
  "CMA",
37
44
  "cumulative",
38
45
  "Cumulative Moving Average",
39
46
  "data",
40
47
  "data analysis",
48
+ "decompression",
49
+ "deflate",
41
50
  "delta",
51
+ "determinant",
42
52
  "distance",
43
53
  "euclidian distance",
44
54
  "EMA",
45
55
  "EWMA",
46
56
  "Exponential Moving Average",
57
+ "forward elimination",
47
58
  "functions",
48
- "injector",
59
+ "gauss jordan",
60
+ "Gauss Jordan Inverse",
61
+ "gaussian elimination",
62
+ "gzip",
49
63
  "host available",
50
64
  "host status",
65
+ "identity",
66
+ "inflate",
67
+ "injector",
68
+ "inverse",
69
+ "inverse matrix",
51
70
  "Linear Correlation Coefficient",
52
71
  "levenshtein distance",
53
72
  "load",
54
73
  "load injector",
74
+ "matrix",
55
75
  "maximum",
56
76
  "mean",
57
77
  "median",
@@ -66,6 +86,8 @@
66
86
  "Process",
67
87
  "range",
68
88
  "realtime",
89
+ "Reduced Row Echelon Form",
90
+ "Row Echelon Form",
69
91
  "sample variance",
70
92
  "sample stddev",
71
93
  "Simple Moving Average",
@@ -82,6 +104,8 @@
82
104
  "test",
83
105
  "translate",
84
106
  "transform",
107
+ "transpose",
108
+ "unzip",
85
109
  "variance",
86
110
  "weighted",
87
111
  "Weighted Moving Average",
@@ -91,15 +115,18 @@
91
115
  "xcel",
92
116
  "xml",
93
117
  "XML",
118
+ "zip",
94
119
  "Z-score"
95
120
  ],
96
121
  "node-red": {
122
+ "version": ">=2.0.0",
97
123
  "nodes": {
98
124
  "append": "append/append.js",
99
125
  "dataAnalysis": "dataAnalysis/dataAnalysis.js",
100
126
  "hostAvailable": "testing/hostAvailable.js",
101
127
  "levenshteinDistance": "levenshteinDistance/levenshteinDistanceNode.js",
102
128
  "load-injector": "testing/load-injector.js",
129
+ "matrix": "matrix/matrixNode.js",
103
130
  "monitorflow": "monitor/monitorflow.js",
104
131
  "os": "nodejs/os.js",
105
132
  "spawnProcess": "spawnProcess/spawnProcess.js",
@@ -0,0 +1,88 @@
1
+ const assert=require('assert');
2
+ const should=require("should");
3
+ const helper=require("node-red-node-test-helper");
4
+ const storageDefinition=require("../nodes/storageDefinition.js");
5
+ const storageRead = require('../nodes/storageRead.js');
6
+
7
+ helper.init(require.resolve('node-red'));
8
+
9
+ function getAndTestNodeProperties(o) {
10
+ const n = helper.getNode(o.id);
11
+ for(let p in o) n.should.have.property(p, o[p]);
12
+ return n;
13
+ }
14
+
15
+ const blockStorage={
16
+ id : "blockStorage",
17
+ type : "Storage Definition",
18
+ name : "Block Storage",
19
+ action: "blockStorage",
20
+ sourceProperty:"blockStorageFile",
21
+ blockSize:4096
22
+ };
23
+
24
+ const StorageReadBlock={
25
+ id : "StorageReadBlockid",
26
+ type : "Storage Read",
27
+ name : "Block Storage",
28
+ target:"payload",
29
+ "target-type":"msg",
30
+ key:"topic"
31
+ };
32
+
33
+ function testFlow(done,node,data,result) {
34
+ const flow = [
35
+ Object.assign(node,{wires : [ [ "outHelper" ],["errorHelper"] ]}),
36
+ {id :"outHelper", type : "helper"},
37
+ {id :"errorHelper", type : "helper"}
38
+ ];
39
+ helper.load(storageDefinition, flow, function() {
40
+ const n=getAndTestNodeProperties(node);
41
+ const outHelper = helper.getNode("outHelper");
42
+ const errorHelper = helper.getNode("errorHelper");
43
+ outHelper.on("input", function(msg) {
44
+ console.log("outHelper "+JSON.stringify(msg.payload));
45
+ if(JSON.stringify(msg.payload)==JSON.stringify(result)) {
46
+ done();
47
+ } else {
48
+ console.log("mismatch expected: "+JSON.stringify(result) +" returned: "+JSON.stringify(msg.payload));
49
+ done("mismatch");
50
+ }
51
+ });
52
+ errorHelper.on("input", function(msg) {
53
+ console.log("errorHelper "+JSON.stringify(msg));
54
+ done("error check log output");
55
+ });
56
+ n.receive({
57
+ topic:"test",
58
+ payload : data
59
+ });
60
+ });
61
+ }
62
+
63
+ describe('Storage Defintion', function() {
64
+ beforeEach(function(done) {
65
+ helper.startServer(done);
66
+ });
67
+ afterEach(function(done) {
68
+ helper.unload();
69
+ helper.stopServer(done);
70
+ });
71
+ it("load config", function(done) {
72
+ helper.load(storageDefinition,[], function() {
73
+ const n=getAndTestNodeProperties(storageDefinition);
74
+ });
75
+ done();
76
+ });
77
+ it("load read", function(done) {
78
+ helper.load(storageDefinition,storageRead,[], function() {
79
+ const n=getAndTestNodeProperties(storageDefinition);
80
+ });
81
+ done();
82
+ });
83
+
84
+ it('read 1', function(done) {
85
+ const msg={topic:1}
86
+ testFlow(done,storageDefinition,msg,msg);
87
+ });
88
+ });