[{"Config":{"clearAuto":true,"strictScope":true,"group":"anonymous","mode":"javascript","file":"workbook.experiments1","fontSize":14,"thisthat":true,"turbo":true,"user":"liheqoce","docUrl":"localhost:5558","projUrl":"192.168.0.45:5550","webclipTime":300,"webclipUrl":"localhost:9176","webxUrl":"localhost:9177","modules":[],"workdir":"/home/sbosse/proj/workbook","version":"1.5.15","wex":{"http":"http://localhost:11111","ws":"ws://localhost:11112"},"strict":true,"reload":"workbook.classes"}},{"Notes":[]},{"Library":"function Optional(x) { return { Optional:x } }\nfunction Select(x) { return { Select:x } }\nfunction Range (a,b,step,defval) { return { Range : [a,b,step,defval] } }\n\nasync function New (constructor,callback) {\n function quotes(s) { return '\"'+s+'\"' }\n var configuration = constructor.prototype.configuration;\n if (configuration) {\n // Create a configuration form\n // 1. Check for selectable sub-classes of this object\n var selections=[],common={};\n \n for(var p in configuration) {\n if (configuration[p].Select) selections.push(p);\n else common[p]=configuration[p];\n }\n var formDesc,form,close,id=Utils.uniqueID(16),content = '
';\n var panel = Common.openWin(content,{\n title : 'Setup Node',\n onclosed : close,\n });\n if (selections.length) {\n // Create Select Form\n var promoSel = new Promise(function (resolve,reject) {\n close=resolve;\n formDesc = \"{ 'Select Subclass':Radiobutton({choices:[\";\n formDesc = formDesc + selections.map(quotes).join(',') +']}),';\n formDesc += 'Okay:Button()}';\n // Code.print(formDesc)\n var choice;\n form = Form.compile(formDesc, \n function (name,value,answer) {\n // Code.print(name,value);\n if (name=='Okay') { form.close(); resolve(choice); return; }\n if (name=='Select Subclass' && value) choice=value;\n });\n $('#'+id).empty().html(form.cell);\n })\n var subclass=await promoSel;\n if (!subclass) return;\n var subclassConf = configuration[subclass].Select;\n for (var p in subclassConf) common[p]=subclassConf[p];\n \n }\n formDesc = \"{ \";\n var sep='',options={};\n // Code.print(common)\n function createPart(current,path) {\n for(var p in current) {\n var opt = current[p],\n optional='',\n choices = current[\"_\"+p];\n if (p[0]=='_') continue;\n if (typeof opt == 'object' && opt.Optional!=undefined) {optional='?';opt=opt.Optional};\n if (typeof opt == 'boolean') {\n formDesc += (sep+'\"'+path+p+optional+'\":'+opt); \n sep=',';\n if (!optional) options[p]=opt;\n }\n if (typeof opt == 'number') {\n formDesc += (sep+'\"'+path+p+optional+'\":'+opt); \n sep=',';\n if (!optional) options[p]=opt;\n }\n if (!choices && typeof opt=='string') {\n formDesc += (sep+'\"'+path+p+optional+'\":\"'+opt+'\"'); \n sep=',';\n if (!optional) options[p]=opt;\n }\n if (choices) {\n formDesc += (sep+'\"'+path+p+optional+'\":Radiobutton({choices:[');\n formDesc = formDesc + choices.map(quotes).join(',') +'],checked:'+\n choices.indexOf(opt)+'})';\n if (!optional) options[p]=opt;\n }\n if (typeof opt == 'object' && opt.Range) {\n var a=opt.Range[0],b=opt.Range[1],s=opt.Range[2]||1,v=opt.Range[3]==undefined?a:opt.Range[3];\n formDesc += (sep+'\"'+path+p+optional+'\":Slider({min:'+a+',max:'+b+',step:'+s+',value:'+v+'})');\n if (!optional) options[p]=v;\n } else if (typeof opt == 'object') {\n createPart(opt,p+'/');\n }\n }\n }\n createPart(common,'')\n formDesc += (sep+'Okay:Button()}');\n Code.print(formDesc)\n var promoConf = new Promise(function (resolve,reject) {\n form = Form.compile(formDesc, \n function (name,value,answer) {\n // Code.print(name,value);\n if (name=='Okay') { form.close(); resolve(); return; }\n if (name[name.length-1]=='?') name=name.slice(0,name.length-1);\n var parts = name.split('/'),root=options;\n parts.forEach(function (part,index) {\n if (index==(parts.length-1)) return;\n if (root[part]==undefined && index < (parts.length-1)) root[part]={}\n root=root[part];\n name=part;\n })\n root[parts[parts.length-1]]=value;\n });\n $('#'+id).empty().html(form.cell);\n })\n await promoConf;\n panel.close();\n if (configuration.finalize) options=configuration.finalize(options);\n return 'var '+constructor.name.toLowerCase()+' = new '+constructor.name+\n '('+(subclass?'\"'+subclass+'\",':'')+inspect(options)+')';\n }\n}\n\n\nclass Display {\n constructor(action,options) {\n options=options||{}\n this.options= options;\n this.history=[];\n this.action=action||'info';\n this.window=null;\n this.ConsoleId=ConsoleId;\n this.ConsoleOutput=ConsoleOutput;\n }\n get configuration () {\n return {\n console:Optional(false),\n accumulative:Optional(false),\n depth:Optional(0),\n plot : Select({\n width:Range(100,1200,50,600),\n type:'line',\n _type:['line','bar','image'],\n title:Optional(''),\n min:Optional(0),\n max:Optional(0),\n data: '[y]', // dataformat\n _data : ['[xy]','[y]','{xy}','[{yy}]','{xyy}','[yy]','Matrix','RGBA','Image'],\n labels : {\n x:Optional(''),\n y:Optional(''),\n data:Optional([]),\n },\n zoom:Optional(1),\n }),\n table : Select({\n size:Range(8,20,1,14),\n header : Optional([]),\n data: '[[a]]',\n _data : ['[[a]]','[{a}]'],\n }),\n finalize : function (options) {\n options.dataformat=options.data;\n delete options.data;\n return options\n }\n }\n }\n info (object,verbose) {\n var self=this;\n if (!this.options.console) {\n if (this.window) \n this.window.update(''+typeOf(object,verbose||this.options.verbose)+'');\n else\n this.window=Common.openWin('
'+typeOf(object,verbose||this.options.verbose)+'',{\n title:'Display.info '+(this.options.heading || this.options.title || ''),\n onclosed : function () {\n self.window=null;\n }\n })\n } else {\n print(typeOf(object,verbose||this.verbose))\n }\n }\n log (data) {\n var self=this;\n if (this.options.accumulative) {\n this.history.push(data);\n if (this.options.depth && this.history.length==this.options.depth) \n this.history=this.history.slice(1);\n }\n if (!this.options.console) {\n var content = this.options.accumulative?this.history.map(item => inspect(item)).join('\\n'):\n inspect(data);\n if (this.window) \n this.window.update('
'+content+'');\n else\n this.window=Common.openWin('
'+content+'',{\n title:'Display.log '+(this.options.heading || this.options.title || ''),\n onclosed : function () {\n self.window=null;\n }\n })\n } else {\n print(inspect(data))\n }\n \n }\n plot (data) {\n var self=this;\n if (this.options.accumulative) {\n this.history.push(data);\n if (this.options.depth && this.history.length==this.options.depth) \n this.history=this.history.slice(1);\n }\n var content = this.options.accumulative?this.history:data;\n if (this.options.filter) content=this.options.filter(content);\n if (!this.options.console) {\n if (this.window) {\n this.options.container.empty();\n Plot(content,self.options);\n } else {\n this.id=Utils.uniqueID(16);\n this.window=Common.openWin('',{\n title:'Display.plot '+(this.options.heading || this.options.title || ''),\n onclosed : function () {\n self.window=null;\n self.options.container=null;\n self.id=null;\n }\n })\n Code.later(1,() => {\n self.options.container=$('#'+self.id);\n this.plotID=Plot(content,self.options);\n })\n }\n } else {\n if (this.plotID) this.options.replace=this.plotID;\n this.plotID=Plot(content,this.options)\n } \n }\n table (data) {\n var self=this;\n if (this.options.accumulative) {\n this.history.push(data);\n if (this.options.depth && this.history.length==this.options.depth) \n this.history=this.history.slice(1);\n }\n var content = this.options.accumulative?this.history:data;\n if (this.options.filter) content=this.options.filter(content);\n if (!this.options.console) {\n if (this.window) {\n this.options.container.empty();\n this.tableID=Table(content,self.options);\n } else {\n this.id=Utils.uniqueID(16);\n this.window=Common.openWin('',{\n title:'Display.table '+(this.options.heading || this.options.title || ''),\n onclosed : function () {\n self.window=null;\n self.options.container=null;\n self.id=null;\n }\n })\n Code.later(1,() => {\n self.options.container=$('#'+self.id);\n this.tableID=Table(content,self.options);\n })\n }\n } else {\n if (this.tableID) this.options.replace=this.tableID;\n this.tableID=Table(content,this.options);\n } \n \n }\n input (data) {\n this.x=data;\n switch (this.action) {\n case 'info':\n this.info(data);\n break\n case 'log':\n this.log(data);\n break\n case 'plot':\n this.plot(data);\n break\n case 'table':\n this.table(data);\n break\n }\n }\n output (node) {\n // produces no output\n }\n}\n\n\nclass SignalGenerator {\n constructor (func,frequency,amplitude,samplefreq,options) {\n if (typeof samplefreq=='object') { options=samplefreq;samplefreq=undefined };\n options=options||{}\n this.next=[];\n this.interval=options.interval||1000;\n this.function = func;\n this.frequency=frequency||1;\n this.apmplitude=amplitude||1;\n this.samplefreq=samplefreq||this.frequency*10;\n this.step=this.frequency/this.samplefreq;\n this.options=options;\n }\n evaluate () {\n var x = this.x,\n y = this.function(x);\n this.x+=this.step;\n return this.options.data=='[xy]'?[x,y]:y\n }\n start (interval) {\n var self=this;\n if (interval) this.interval=interval;\n this.x=0;\n this.timer = Code.later(this.interval,function () {\n // Code.print(self.x)\n self.y=self.evaluate();\n self.next.forEach(function (node) {\n node.input(self.y);\n })\n return true;\n })\n }\n stop () {\n if (this.timer) {\n clearInterval(this.timer)\n this.timer=undefined;\n }\n }\n output (node) {\n this.next.push(node);\n }\n}\n\n\nclass Data {\n constructor (source,options) {\n this.source=source;\n this.options=options||{};\n this.next=[];\n }\n async start () {\n var result;\n switch (this.source) {\n case 'sql':\n this.db=DB.sqlA(this.options.url);\n if (this.options.database) {\n result=await this.db.open(this.options.database);\n if (DB.error(result).toString()=='ENOTEXIST') {\n result=await this.db.createDB(this.options.database);\n result=await this.db.open(this.options.database);\n }\n }\n if (DB.error(result)) {\n this.error=DB.error(result);\n if (this.options.on && this.options.on.error)\n this.options.on.error('db.open',this.error);\n return this.error;\n }\n this.tables = await this.db.tables();\n return result;\n break;\n }\n }\n // varargs\n async read () {\n var self=this;\n switch (this.source) {\n case 'sql':\n var result = await this.db.select(this.options.table,arguments[0]||'*',arguments[1]);\n if (DB.error(result)) {\n this.error=DB.error(result);\n if (this.options.on && this.options.on.error)\n this.options.on.error('db.select',this.error);\n return this.error;\n } \n if (this.options.filter) this.y=result.map(this.options.filter);\n else this.y=result;\n // Code.print(data)\n self.next.forEach(function (node) {\n node.input(self.y);\n })\n return this.y;\n break;\n }\n }\n output (node) {\n this.next.push(node);\n }\n}\nexport { Display, SignalGenerator, Data, New }"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Init !Important","heightC":100,"heightE":10,"collapsed":false,"overlay":2,"evalUser":"undefined"},"code":"load('math.plugin')\n"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Snippet Library Class: Active Node Network with Plot","heightC":20,"heightE":100,"collapsed":false,"overlay":false,"evalUser":"undefined"},"code":"import { Display, SignalGenerator }\nvar display = new Display('plot',{\n console:true,\n accumulative:true,\n type:'line',\n width:600,\n labels : {\n x:'time',\n y:'arb. units',\n },\n heading:'Sine wave monitor',\n title:'Time Signal Plot'\n})\n// display.info(Display,1)\nvar sinegen = new SignalGenerator(Math.sin,100,1);\nsinegen.output(display)\nsinegen.start(100)\n\nexport { sinegen }"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Snippet Library Class: Table","heightC":100,"heightE":100,"collapsed":false,"overlay":false,"evalUser":"undefined"},"code":"import { Display, SignalGenerator }\nvar display = new Display('table',{\n console:false,\n accumulative:true,\n type:'line',\n width:600,\n heading:'Sine wave monitor',\n header:['X','Y'],\n title:'Time Signal'\n})\n// display.info(Display,1)\nvar sinegen = new SignalGenerator(Math.sin,1000,1,{\n data:'[xy]'\n});\nsinegen.output(display)\nsinegen.start()\n\nexport { sinegen }"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Snippet Library Class: Data Source and Table","heightC":100,"heightE":100,"collapsed":false,"overlay":false,"evalUser":"undefined"},"code":"import { Display, Data }\nvar display = new Display('table',{\n console:true,\n accumulative:false,\n dataformat:'[{a}]',\n type:'line',\n width:600,\n title:'Data Table'\n})\nvar datasource1 = new Data('sql',{\n url:'localhost:9999',\n database : 'Examples1',\n table : 'straintest1',\n on : {\n error: (op,err) => {\n print(op,err)\n }\n }\n});\ndatasource1.output(display);\nawait datasource1.start();\n// print(datasource1.tables);\nawait datasource1.read('*')\nexport { datasource1 }"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Statistical Analysis (Strain-Force)","heightC":100,"heightE":100,"collapsed":false,"overlay":false,"evalUser":"undefined"},"code":"import { Display, datasource1 }\nvar display = new Display('table',{\n console:true,\n accumulative:false,\n dataformat:'[{a}]',\n title:'Statistical Anaylsis Force',\n filter : (data) => {\n return Math.statistics.analysis(data.pluck('Force'))\n }\n})\ndatasource1.output(display)\ndatasource1.read('*')"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Fire Data Source 1 Read Event","heightC":100,"heightE":10,"collapsed":false,"overlay":false,"evalUser":"undefined"},"code":"import { datasource1 }\nawait datasource1.read('*','rowid>3')"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Create Code from Library","heightC":100,"heightE":10,"collapsed":true,"overlay":false,"evalUser":"undefined"},"code":"import { New, Display }\nvar code = await New(Display);\nprint(code)"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Data Source and Image Plot","heightC":100,"heightE":100,"collapsed":false,"overlay":false,"evalUser":"undefined"},"code":"import { Display, Data }\nvar display = new Display('plot',{\n console:false,\n accumulative:false,\n dataformat:'Matrix',\n type:'image',\n // width:600,\n zoom:0.5,\n colorIndex:9,\n title:'Data Table',\n filter : (data) => {\n return data[0].data\n },\n})\nvar datasource2 = new Data('sql',{\n url:'localhost:9999',\n database : 'Examples2',\n table : 'crackimages1',\n filter : (row) => {\n row.dataspace=JSON.parse(row.dataspace);\n row.data=DB.toMatrix(row);\n return row\n },\n on : {\n error: (op,err) => {\n print(op,err)\n }\n }\n});\ndatasource2.output(display);\nvar result = await datasource2.start();\nvar image = await datasource2.read('*','rowid=1');\nexport { datasource2 }"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Statistical Analysis Data Source 2","heightC":100,"heightE":100,"collapsed":false,"overlay":false,"evalUser":"undefined"},"code":"import { Display, datasource2 }\nvar display = new Display('table',{\n console:false,\n accumulative:false,\n dataformat:'[{a}]',\n title:'Statistical Anaylsis Image',\n filter : (image) => {\n // Code.print(typeOf(image))\n return Math.statistics.analysis(image[0].data.toArray().flat())\n }\n})\ndatasource2.output(display)\ndatasource2.read('*')"},{"options":{"eval":"_PxEnUf_ZnVuY3Rpb24gKHRleHQsZW52KSB7CiAgICAgICAgICAgICBqc1Njb3BlLnJ1bih0ZXh0LGVudikKICAgICAgICAgIH0=","mode":"javascript","label":"Fire Data Source 2 read Event","heightC":100,"heightE":10,"collapsed":false,"overlay":false,"evalUser":"undefined"},"code":"import { datasource2 }\nawait datasource2.read('*','rowid=2')"}]