jam/js/simu/simu.js

1151 lines
35 KiB
JavaScript

/**
** ==============================
** O O O OOOO
** O O O O O O
** O O O O O O
** OOOO OOOO O OOO OOOO
** O O O O O O O
** O O O O O O O
** OOOO OOOO O O OOOO
** ==============================
** Dr. Stefan Bosse http://www.bsslab.de
**
** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED
** BY THE AUTHOR(S).
** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED,
** MODIFIED, OR OTHERWISE USED IN A CONTEXT
** OUTSIDE OF THE SOFTWARE SYSTEM.
** OUTSIDE OF THE SOFTWARE SYSTEM.
**
** $AUTHORS: Stefan Bosse
** $INITIAL: (C) 2006-2017 bLAB
** $CREATED: 02-10-16 by sbosse.
** $VERSION: 1.3.8
**
** $INFO:
**
** SEJAM: JavaScript AIOS JAM Agent Simluator
** - Terminal (curses) GUI
**
** $ENDOFINFO
*/
var Io = Require('com/io');
var Comp = Require('com/compat');
var Db = Require('db/db');
var blessed = Require('term/blessed');
var current=none;
var Aios = none;
var Papa = Require('parser/papaparse.js');
var Esprima = Require('parser/esprima');
/** Create a simulation world with visualization
*
* options: {x:number,y:number,id:string?,terminal:string,gui='term'?,
* nolimits:boolean is a disable flag for agent check poininting,
* connection:{random:number?},
* classes:{node:{..},ac1:{..},..}}
*
*/
var simuTerm = function (options) {
var self=this;
var node1,node2,row,row1,row2,i,j,p;
this.options=options||{};
if (this.options.x==_) this.options.x=6;
if (this.options.y==_) this.options.y=6;
if (this.options.id==_) this.options.id='Dark Universe World';
if (this.options.connections==_) this.options.connections={};
if (this.options.markings) this.options.nodebar=true;
if (this.options.nolimits) Aios.config({nolimits:true});
this.classes=this.options.classes||{};
delete this.options.classes;
this.run=false;
this.steps=0;
this.loop=none;
this.time=0;
this.time0=0;
this.log=[];
this.events=[];
this.err=function (msg,err) {
Aios.aios.log('Error: '+msg);
throw (err||'[SIM] Error');
}
this.warn=function (msg) {
Aios.aios.log('Warning: '+msg);
}
this.out=function (msg) {
Aios.aios.log(msg);
}
// PRINT: Smart print function
var print = function (msg,header,depth,nolog) {
var lines=[];
var line='';
if (depth==_) depth=1;
function isvec(obj) {return(Comp.obj.isArray(obj) && (obj.length == 0 || !Comp.obj.isArray(obj[0])))}
function ismat(obj) {return(Comp.obj.isArray(obj) && obj.length > 0 && Comp.obj.isArray(obj[0]))}
function mat(o,depth) {
// matrix
var lines=[];
var line = '';
if (header) {line=header; header=_};
for (var j in o) {
var row=o[j];
line += Comp.printf.list(row,function (v) {
return (Comp.obj.isArray(v)?(depth>0?'['+vec(v,depth-1)+']':'[..]'):
Comp.obj.isObj(v)?(depth>0?obj(v,depth-1):'{..}'):v);
});
lines.push(line);
line='';
}
return lines;
}
function vec(v,depth) {
// vector
var lines=[];
var line = '';
if (header) {line=header; header=_};
if (v.length==0) return(line+'[]');
else {
// can still contain matrix elements that must bes separated
var sep='',sepi='';
for (var p in v) {
if (ismat(v[p])) {
//self.log.log(line); line=' ';
if (depth>0) {
lines = mat(v[p],depth-1);
line += sep+'['; sepi='';
Comp.array.iter(lines,function (line2) {
line += sepi+'['+line2+']';
sepi=',';
});
line += ']';
sep=',';
} else {
line += sep+'[[..]]';
sep=',';
}
}
else if (isvec(v[p])) {
//self.log.log(line); line=' ';
line += sep+vec(v[p],depth-1);
sep=',';
}
else {
line += sep+(Comp.obj.isArray(v[p])?(depth>0?vec(v[p],depth-1):'[..]'):
Comp.obj.isObj(v[p])?(depth>0?obj(v[p],depth-1):'{..}'):v[p]);
sep=',';
}
}
if (line!='') return line;
}
}
function obj(o,depth) {
var line='';
var sep='';
if (header) {line=header; header=_};
line += '{';
for (var p in o) {
if (!Comp.obj.isFunction(o[p])) {
line += sep + p+':'+
(Comp.obj.isArray(o[p])?(depth>0?vec(o[p],depth-1):'[..]'):
Comp.obj.isObj(o[p])?(depth>0?obj(o[p],depth-1):'{..}'):o[p]);
sep=',';
} else {
line += sep + p+':'+'function()';
sep=',';
}
}
return line+'}';
}
function str(s) {
var line='';
var lines=[];
var lines2 = Comp.string.split('\n',msg);
if (header) {line=header; header=_};
if (lines2.length==1)
lines.push(line+msg);
else {
Comp.array.iter(lines2,function (line2,i) {
if (i==0) lines.push(line+line2);
else lines.push(line2);
});
}
return lines;
}
if (ismat(msg)) lines = Comp.array.concat(lines,
Comp.array.map(mat(msg,depth-1),function (line){
return ' '+line}));
else if (Comp.obj.isString(msg)) lines = Comp.array.concat(lines,str(msg));
else if (isvec(msg)) lines.push(vec(msg,depth-1));
else if (Comp.obj.isObj(msg)) lines.push(obj(msg,depth-1));
else {
if (header) {line=header; header=_};
line += msg;
lines.push(line);
}
if (nolog) return lines; else Comp.array.iter(lines,function (line) {self.log.log(line)});
};
var log = function(){
if (!current.node || !current.process) {
print(arguments[0]);
}
else if (arguments.length==1)
print(arguments[0],'['+current.node.id+':'+current.process.agent.id+':'+current.process.pid+':'+current.process.agent.ac+'] ');
else {
for (var i in arguments) {
if (i==0)
print(arguments[i],'['+current.node.id+':'+current.process.agent.id+':'+current.process.pid+':'+current.process.agent.ac+'] ');
else
print(arguments[i],_,2);
}
}
};
// Extended sandbox environment available for all agents
Aios.aios0.log=log;
Aios.aios1.log=log;
Aios.aios2.log=log;
Aios.aios0.print=function(msg,depth) {return print(msg,_,depth,false)};
Aios.aios1.print=function(msg,depth) {return print(msg,_,depth,false)};
Aios.aios2.print=function(msg,depth) {return print(msg,_,depth,false)};
Aios.aios0.sprint=function(msg,depth) {return print(msg,_,depth,true)};
Aios.aios1.sprint=function(msg,depth) {return print(msg,_,depth,true)};
Aios.aios2.sprint=function(msg,depth) {return print(msg,_,depth,true)};
Aios.config({TIMESCHED:1000});
this.world = Aios.World.World([],{id:this.options.id,classes:this.classes});
this.screen = blessed.screen({
smartCSR: false,
terminal: self.options.terminal||'xterm-color'
});
this.screen.title = 'SEJAM (c) Stefan Bosse - '+(this.options.id||'JAM Dark Universe Simulation World');
this.screen.cursor.color='red';
// Information bar
this.info = blessed.textbox({
top: 0,
left: 4*9+1,
width: self.screen.width-4*9-1,
height: 3,
label: 'Information',
focus:false,
//draggable:true,
border: {
type: 'line'
},
style: {
fg:'blue'
}
});
this.screen.append(this.info);
// Buttons
function but(options) {
var obj = blessed.button({
width: options.width||8,
left: options.left||0,
top: options.top||0,
height: 3,
align: 'center',
content: options.content||'?',
mouse:true,
focus:true,
border: {
type: 'line'
},
style: {
fg: 'white',
bg: 'blue',
bold:true,
border: {
fg: 'black'
},
hover: {
border: {
fg: 'red'
}
}
}
});
self.screen.append(obj);
return obj;
}
// Bt QUIT
this.but1 = but({left:1,content:'QUIT'});
this.but1.on('press', function(data) {
return process.exit(0);
});
// Bt RUN
this.but2 = but({left:9,content:'RUN'});
this.but2.on('press', function(data) {
if (self.run) return;
var curtime=Aios.time();
var lasttime=curtime;
if (self.time>0) current.world.lag=current.world.lag+(lasttime-self.time);
if (self.time0==0) self.time0=curtime;
self.time=curtime;
self.log.log('Running simulation at '+self.steps+ ' .. ');
self.but2.setStyle({bg:'red'});
Aios.config({iterations:1});
self.run=true;
var loop = function () {
var nexttime=Aios.scheduler();
self.steps++;
curtime=Aios.time();
if (!self.run) return;
//self.log.log(nexttime);
if (nexttime>0) self.loop=setTimeout(loop,nexttime);
else if (nexttime<0) self.loop=setTimeout(loop,0);
else {
self.but2.setStyle({bg:'blue'});
self.log.log('Stopping simulation at '+self.steps+ ' .. (d '+(Aios.time()-self.time)+' ms / t '+(Aios.time()-current.world.lag)+' ms)');
self.update(true);
self.time=curtime;
}
if ((curtime-lasttime)>100) {
self.update(true);
lasttime=curtime;
} else
self.update(false);
}
self.loop = setTimeout(loop,1);
});
// Bt STOP
this.but3 = but({left:17,content:'STOP'});
this.but3.on('press', function(data) {
if (!self.run) return;
self.log.log('Stopping simulation at '+self.steps+ ' .. (d '+(Aios.time()-self.time)+' ms / t '+(Aios.time()-current.world.lag)+' ms)');
self.time=Aios.time();
self.run=false;
if (self.loop!=none) clearTimeout(self.loop);
self.but2.setStyle({bg:'blue'});
self.update(true);
});
// Bt STEP
this.but4 = but({left:25,content:'STEP'});
this.but4.on('press', function(data) {
var start,stop;
var curtime=Aios.time();
var lasttime=curtime;
start=curtime;
if (self.time>0) current.world.lag=current.world.lag+(start-self.time);
if (self.time0==0) self.time0=start;
self.time=start;
self.run=true;
self.log.log('Stepping simulation ('+self.but5.steps+') at '+self.steps+ ' .. (t '+(Aios.time()-current.world.lag)+' ms)');
self.but2.setStyle({bg:'red'});
Aios.config({iterations:1});
var stepped=self.but5.steps;
var loop = function () {
var nexttime=Aios.scheduler();
self.steps++;
stepped--;
curtime=Aios.time();
if (!self.run) return;
if (stepped==0) {
stop=Aios.time();
self.run=false;
self.but2.setStyle({bg:'blue'});
self.log.log('Stopping simulation at '+self.steps+ ' .. (d '+(Aios.time()-self.time)+' ms / t '+(Aios.time()-current.world.lag)+' ms)');
self.time=stop;
self.update(true);
return;
}
if (nexttime>0) self.loop=setTimeout(loop,nexttime);
else if (nexttime<0) self.loop=setTimeout(loop,0);
else {
self.but2.setStyle({bg:'blue'});
self.log.log('Stopping simulation at '+self.steps+ ' .. (d '+(Aios.time()-self.time)+' ms / t '+(Aios.time()-current.world.lag)+' ms)');
self.update(true);
self.time=curtime;
}
if ((curtime-lasttime)>100) {
self.update(true);
lasttime=curtime;
} else
self.update(false);
}
self.loop = setTimeout(loop,0);
});
// Bt STEPS
this.but5 = blessed.button({
width:3,
top:1,
left:33,
height:1,
align: 'center',
mouse:true,
content: '1',
style: {
bold:true,
bg:'blue',
fg:'white',
hover: {
bg: 'red'
}
}
});
this.but5.steps=1;
var stepsall = [1,5,10,50,100,500];
this.but5.on('press', function(data) {
self.but5.steps=Comp.array.next(stepsall,self.but5.steps);
self.but5.setContent(Comp.pervasives.string_of_int(self.but5.steps));
self.screen.render();
});
self.screen.append(this.but5);
// GUI Update
this.update = function (full) {
var mem = Io.mem();
var info = self.world.info();
var curtime=Aios.time();
if (self.nodelast!=none)
self.info.setValue(Comp.printf.sprintf('%s / %d stp. / %d ag. / C %d kB / M %d MB / t %d / d %d',
self.node(self.nodelast.i,self.nodelast.j).id,
self.steps,
info.agents,
div(info.transferred,1024),
div(mem.data+mem.heap,1024),
curtime-current.world.lag,
self.run?curtime-current.world.lag-self.time0:self.time-current.world.lag-self.time0));
else
self.info.setValue(Comp.printf.sprintf('%d stp. / %d ag. / C %d kB / M %d MB / t %d / d %d',
self.steps,
info.agents,
div(info.transferred,1024),
div(mem.data+mem.heap,1024),
curtime-current.world.lag,
self.run?curtime-current.world.lag-self.time0:self.time-current.world.lag-self.time0));
if (full)
for (var j=0;j<self.options.y;j++) {
var row=self.nodebuts[j];
for (var i=0;i<self.options.x;i++) {
var nodebut=row[i];
var node=nodebut.object;
var tsn=0,procn=0;
// Node Stats
for (var t in node.ts.db) {
if (node.ts.db[t]) tsn += Aios.Ts.count(node.ts.db[t]);
}
if (tsn>99) tsn='>H';
procn=node.processes.used;
if (procn>999) procn='>k';
nodebut.setContent(Comp.printf.sprintf('%s\n%3s|%2s',self.node(i,j).id,
Comp.pervasives.string_of_int(procn),
Comp.pervasives.string_of_int(tsn)));
// Node Markings
if (self.options.markings) {
var marked=Comp.array.create(6,false);
for (var m in self.options.markings) {
// class:[index(0..),color,optional text]
// class.property:[index(0..),color,text mapping function]
var mark = self.options.markings[m];
var index=mark[0]; var color=mark[1];
var property = Comp.string.postfix(m);
var ac=Comp.string.prefix(m);
for (var p in node.processes.table) {
if (node.processes.table[p]!=_){
var agent=node.processes.table[p].agent;
if (agent.ac==ac) {
// Agent property marking
if (agent[property]!=_) {
var val=mark[2](agent[property]);
if (val!=none) {
marked[index]=true;
nodebut.markbuts[index].setStyle({bg:color});
if (Comp.obj.isString(val) && val!='') nodebut.markbuts[index].setContent(Comp.string.get(val,0));
}
} else if (ac==property) {
var text=mark[2];
marked[index]=true;
nodebut.markbuts[index].setStyle({bg:color});
if (text) nodebut.markbuts[index].setContent(text);
}
}
}
}
}
for (m in marked) {
if (!marked[m]) nodebut.markbuts[m].setStyle({bg:'blue'});
if (!marked[m]) nodebut.markbuts[m].setContent('');
}
}
}
}
//if (!self.run)
if (full) self.screen.render();
};
// Simulation World
this.worldframe = blessed.textbox({
top: 3,
left: 1,
width: self.options.x*8,
height: self.options.y*(self.options.nodebar?4:3)+1,
label: 'Simulation World',
focus:false,
border: {
type: 'line'
},
style: {
fg:'blue'
}
});
this.screen.append(this.worldframe);
this.nodebuts=[];
this.nodelast=none;
this.nodes=[];
// Get a node object
this.node = function (i,j) {
return this.nodes[j][i];
};
// Build the world
for (var j=0;j<this.options.y;j++) {
var nodebutrow=[];
var noderow=[];
for (var i=0;i<this.options.x;i++) {
var id = Comp.printf.sprintf('N%2d.%2d',i,j);
var node = Aios.Node.Node({id:id,position:{x:i,y:j}});
var nodebut = blessed.button({
width:6,
top:j*(self.options.nodebar?4:3)+4,
left:i*8+2,
height:self.options.nodebar?3:2,
align: 'left',
mouse:true,
content: id+'\n0',
object:node
});
nodebut.options.style.bg='blue';
this.screen.append(nodebut);
if (self.options.nodebar) {
nodebut.markbuts=[];
for (var m=0;m<6;m++) {
var markbut = blessed.button({
width:1,
top:j*4+6,
left:i*8+2+m,
height:1,
align: 'center',
mouse:true,
content: '',
object:node
});
markbut.options.style.bg='blue';
nodebut.markbuts.push(markbut);
this.screen.append(markbut);
}
}
self.world.addNode(node);
nodebutrow.push(nodebut);
noderow.push(node);
(function (i,j,node) {
nodebut.on('press', function(data) {
var id = self.node(i,j).id;
// self.info.setValue(Comp.printf.sprintf(' N%2d.%2d ',i,j));
self.info.setValue(Comp.printf.sprintf(' %s ',id));
//self.nodebuts[j][i].setContent('xxx');
//self.nodebuts[j][i].setStyle({bg:'red'});
if (self.nodelast!=none) self.nodebuts[self.nodelast.j][self.nodelast.i].setStyle({fg:'white'});
if (self.worldbut) self.worldbut.setStyle({fg:'white'})
self.nodelast={i:i,j:j};
self.nodebuts[j][i].setStyle({fg:'yellow'});
self.treeview.setLabel(Comp.printf.sprintf(' N%2d.%2d ',i,j));
var data = node.info();
for (var p in data) {
var element=data[p];
var content=self.maketree(element,data);
if (content) self.treeview.DATA.children[p]=content;
}
self.treeview.setData(self.treeview.DATA);
self.update();
})})(i,j,node);
}
this.nodebuts.push(nodebutrow);
this.nodes.push(noderow);
}
function link(n1,n2) {
var dx=n2.position.x-n1.position.x;
var dy=n2.position.y-n1.position.y;
var dir=Aios.DIR.ORIGIN;
if (self.options.connections.random &&
Comp.random.float(1.0) > self.options.connections.random) return;
if (dx==1 && dy==0) dir=Aios.DIR.EAST;
if (dx==-1 && dy==0) dir=Aios.DIR.WEST;
if (dx==0 && dy==1) dir=Aios.DIR.SOUTH;
if (dx==0 && dy==0) dir=Aios.DIR.NORTH;
self.world.connect(dir,n1,n2,self.options.connections);
var line = blessed.line({
orientation:dx!=0?'horizontal':'vertical',
top:dx==0?(dy<0?n1.position.y*(self.options.nodebar?4:3)+(self.options.nodebar?4:3):
n1.position.y*(self.options.nodebar?4:3)+(self.options.nodebar?4:3)+3):
n1.position.y*(self.options.nodebar?4:3)+(self.options.nodebar?5:4),
left:dy==0?(dx<0?n1.position.x*8:n1.position.x*8+8):(n1.position.x*8+5),
width:dy==0?2:0,
height:dx==0?1:0
});
self.screen.append(line);
}
// Create connections
for (j=0;j<self.options.y;j++) {
row1=self.nodebuts[j];
for (i=0;i<self.options.x;i++) {
if (i<self.options.x-1) {
node1=row1[i].object;
node2=row1[i+1].object;
link(node1,node2);
}
if (j<self.options.y-1) {
row2=self.nodebuts[j+1];
node1=row1[i].object;
node2=row2[i].object;
link(node1,node2);
}
}
}
// Tree Viewer
this.maketree = function (element,reference) {
var content,children;
children={};
if (Comp.obj.isObject(element) || Comp.obj.isArray(element)) {
if (element && element != null && element._update) element._update(element);
for (var p in element) {
if (p != '_update')
children[p]={};
}
content={
children : children,
data : element
}
} else if (element != undefined) {
var name = element.toString();
var funpat = /function[\s0-9a-zA-Z_$]*\(/i;
var isfun=Comp.obj.isFunction(element)||funpat.test(name);
if (isfun) {
element=Comp.string.sub(name,0,name.indexOf('{'));
}
if (!isfun || (isfun && self.options.showfun)) {
children[element]={};
content={children : children,reference:reference};
}
} else {
children[element]={};
content={children : children};
}
return content;
};
this.treeview = blessed.tree({
top: 3,
left: self.options.x*8+2,
width: self.screen.width-self.options.x*8-2,
height: self.options.y*(self.options.nodebar?4:3)+1,
label: self.options.info||'Info',
focus:true,
border: {
type: 'line'
},
style: {
border: {
fg: 'black'
},
hover: {
border: {
fg: 'red'
}
},
focus : {
border: {
fg: 'red'
}
}
}
});
this.treeviewbut1 = blessed.button({
width:7,
top:3,
left:self.screen.width-26,
height:1,
align: 'center',
mouse:true,
content: 'SIZE',
style: {
bold:true,
bg:'blue',
fg:'white',
hover: {
bg: 'red'
}
}
});
this.treeviewbut2 = blessed.button({
width:7,
top:3,
left:self.screen.width-18,
height:1,
align: 'center',
mouse:true,
content: 'PRINT',
style: {
bold:true,
bg:'blue',
fg:'white',
hover: {
bg: 'red'
}
}
});
this.treeviewbut3 = blessed.button({
width:7,
top:3,
left:self.screen.width-10,
height:1,
align: 'center',
mouse:true,
content: 'D1',
style: {
bold:true,
bg:'blue',
fg:'white',
hover: {
bg: 'red'
}
}
});
this.treeviewbut3.depth=1;
this.treeviewbut1.on('press', function(data) {
var item=self.treeview.nodeLines[self.treeview.list.getItemIndex(self.treeview.list.selected)];
try {
if (item.data) print(Aios.Code.size(item.data));
} catch (e) { print(0); }
});
this.treeviewbut2.on('press', function(data) {
var item=self.treeview.nodeLines[self.treeview.list.getItemIndex(self.treeview.list.selected)];
if (item.data) print(item.data,_,self.treeviewbut3.depth); else if (item.children) {
for (var p in item.children) {
print(p,_,self.treeviewbut3.depth);
}
} else print(item.name);
});
this.treeviewbut3.on('press', function(data) {
if (self.treeviewbut3.depth<3) self.treeviewbut3.depth++;
else self.treeviewbut3.depth=1;
self.treeviewbut3.setContent('D'+self.treeviewbut3.depth);
self.screen.render();
});
// Create sub-trees
this.treeview.on('preselect',function(node){
var content,children,element,data,name;
if (node.name != '/' && !node.extended) {
// Io.out(node.extended);
data = node.data;
if (data != none && (Comp.obj.isObject(data) || Comp.obj.isArray(data))) {
node.children = {};
if (Comp.obj.isArray(data) && Comp.array.empty(data) && Comp.hashtbl.empty(data)) {
node.children={'[]' : {}};
} else {
if (data._update) data._update(data);
for (var p in data) {
if (p != '_update') {
element = data[p];
content=self.maketree(element,data);
if (content) node.children[p]=content;
}
}
}
} else if (data == none && node.reference) {
node.children = {};
element=node.reference[node.name];
name=element.toString();
var funpat = /function[\s0-9a-zA-Z_$]*\(/i;
var isfun=Comp.obj.isFunction(element)||funpat.test(name);
if (isfun) {
element=Comp.string.sub(name,0,name.indexOf('{'));
}
node.children[element]={};
}
}
});
// Update preview
this.treeview.on('selected',function(node){
// self.screen.render();
});
this.screen.append(this.treeview);
this.screen.append(this.treeviewbut1);
this.screen.append(this.treeviewbut2);
this.screen.append(this.treeviewbut3);
this.treeview.DATA = {
name:'/',
extended:true,
children: {}
};
this.treeview.setData(this.treeview.DATA);
// this.tree.focus();
// Log window
this.log = blessed.Log({
top: 3+self.options.y*(self.options.nodebar?4:3)+1,
left: 1,
width: this.screen.width-1,
height: this.screen.height-self.options.y*(self.options.nodebar?4:3)-4,
label: 'Log',
mouse:true,
keys:true,
scrollback:100,
border: {
type: 'line'
},
scrollbar: {
ch: ' ',
track: {
bg: 'yellow'
},
style: {
fg: 'cyan',
inverse: true
}
},
alwaysScroll:true,
scrollOnInput:true,
style: {
fg: 'white',
bg: 'black',
border: {
fg: 'green'
},
focus: {
border: {
fg: 'red'
}
}
}
});
this.screen.append(this.log);
this.log.key('enter',function (ch,key) {
self.log.clear();
self.screen.render();
});
this.screen.key(['escape', 'q', 'C-c'], function(ch, key) {
return process.exit(0);
});
// DB connection?
if (this.options.db) {
if (this.options.db.path==_ || this.options.db.channel==_) Io.err('SIMU.DB: invalid options');
this.db=Db.Sqlc(this.options.db.path,this.options.db.channel);
if (this.db) {
this.db.setLog(function (msg) {self.log.log(msg)});
this.db.init();
}
}
this.csv = {
read: function (file,callback,verbose) {
var data;
var proc;
Aios.aios.B([
function () {
if (verbose) Aios.aios.log('Reading '+file);
data=Io.read_file(file);
if (!data) throw 'File read error: '+file;
},
function () {
var done=false,run=true;
if (verbose) Aios.aios.log('Parsing '+file);
Papa.parse(data,{
complete: function(results) {
if (verbose) Aios.aios.log('DEL="'+results.meta.delimiter+'" TRUNC='+results.meta.truncated+
' ABORT='+results.meta.aborted);
callback.call(current.process.agent,results.data);
if (!run) Aios.aios.wakeup();
done=true;
}
});
if (!done) {
run=false;
Aios.aios.sleep();
}
},
function () {
}
]);
}
};
// Agent AIOS simulation extensions
this.aiosX = {
csv:this.csv,
db:this.db,
createOn:function (x,y,ac,args,level) {
var node=self.nodes[y][x];
var agent=none;
if (level==undefined) level=2;
if (self.classes[ac])
agent = Aios.Code.createOn(node,self.classes[ac],args,level);
if (agent) {
agent.agent.ac=ac;
return agent.agent.id;
} else return none;
},
event: {
add: function (ev) {
self.events.push({step:self.steps,node:current.node.id,event:ev});
},
get: function () {
var evl = self.events;
self.events=[];
return evl;
}
},
getOn:function (x,y,agentid,property) {
var node=self.nodes[y][x];
var agent=node.processes.process(agentid);
if (agent) {
return agent.agent[property];
} else self.log.log('Cannot find agent '+agentid+' on node ['+x+','+y+']');
},
getNode:function () {return current.node.id},
getStats: function () {
var i,j;
var stats={steps:self.steps};
for (i in self.world.nodes) {
var node=self.world.nodes[i];
for(j in node.processes.table) {
var proc=node.processes.table[j];
if (proc && proc.agent.ac) {
if (stats[proc.agent.ac]==undefined) stats[proc.agent.ac]=1;
else stats[proc.agent.ac]++;
}
}
}
return stats;
},
getSteps:function () {return self.steps},
network: {
x:this.options.x,
y:this.options.y
},
options:this.options,
print:print,
setOn:function (x,y,agentid,properties) {
if (x<0 || x >= self.options.x || y<0 || y>=self.options.y) throw 'setOn: Invalid Argument';
var node=self.nodes[y][x];
var agent=node.processes.process(agentid);
if (agent) {
for (var p in properties) {
if (agent.agent[p]!=_) agent.agent[p]=properties[p];
}
} else self.log.log('Cannot find agent '+agentid+' on node ['+x+','+y+']');
},
setOnNode:function (x,y,properties) {
if (x<0 || x >= self.options.x || y<0 || y>=self.options.y) throw 'setOnNode: Invalid Argument';
var node=self.nodes[y][x];
if (node) {
for (var p in properties) {
if (node[p]!=_) node[p]=properties[p];
if (p=='id') {
var nodebut=self.nodebuts[y][x];
nodebut.setContent(properties[p]);
}
}
} else self.log.log('Cannot find agent '+agentid+' on node ['+x+','+y+']');
},
stop: function () {
if (!self.run) return;
self.log.log('Stopping simulation at '+self.steps+ ' .. (d '+(Aios.time()-self.time)+' ms / t '+(Aios.time()-current.world.lag)+' ms)');
self.time=Aios.time();
self.run=false;
if (self.loop!=none) clearTimeout(self.loop);
self.but2.setStyle({bg:'blue'});
self.update(true);
}
};
// Extended sandbox environment available for all agents in simulation
Aios.aios0.simu=this.aiosX;
Aios.aios1.simu=this.aiosX;
Aios.aios2.simu=this.aiosX;
if (options.aios) {
// Extend AIOS environment(s)
for (p in options.aios) {
if (!Aios.aios0[p]) Aios.aios0[p]=options.aios[p];
if (!Aios.aios1[p]) Aios.aios1[p]=options.aios[p];
if (!Aios.aios2[p]) Aios.aios2[p]=options.aios[p];
}
}
if (options.aios0) {
// Extend AIOS environment(s)
for (p in options.aios0) {
if (!Aios.aios0[p]) Aios.aios0[p]=options.aios[p];
}
}
if (options.aios1) {
// Extend AIOS environment(s)
for (p in options.aios1) {
if (!Aios.aios1[p]) Aios.aios1[p]=options.aios[p];
}
}
if (options.aios2) {
// Extend AIOS environment(s)
for (p in options.aios2) {
if (!Aios.aios2[p]) Aios.aios2[p]=options.aios[p];
}
}
// Start world agent - if world class is specified
if (self.classes['world']) {
// A virtual world node must be created.
this.worldnode=Aios.Node.Node({id:'World0'});
this.worldagent=Aios.Code.createOn(this.worldnode,self.classes['world'],[],2);
this.worldagent.agent.ac='world';
// Add additional attributes to world agent
//this.worldagent.agent.options=self.options;
//for (var p in this.agent) {
// this.worldagent.agent[p]=this.agent[p];
//}
this.world.addNode(this.worldnode);
this.worldbut = blessed.button({
width:1,
top:3,
left:self.options.x*8,
height:1,
align: 'left',
mouse:true,
content: 'W',
object:self.worldnode,
style: {
bold:true,
bg:'blue',
fg:'white',
hover: {
bg: 'red'
}
}
});
this.screen.append(this.worldbut);
(function (node) {
self.worldbut.on('press', function(data) {
//self.info.setValue(' World ');
if (self.nodelast!=none) self.nodebuts[self.nodelast.j][self.nodelast.i].setStyle({fg:'white'});
self.nodelast=none;
self.worldbut.setStyle({fg:'yellow'});
self.treeview.setLabel(' World ');
var data = node.info();
for (var p in data) {
var element=data[p];
var content=self.maketree(element,data);
if (content) self.treeview.DATA.children[p]=content;
}
self.treeview.setData(self.treeview.DATA);
self.update();
})})(this.worldnode);
}
// Start node agents - if node class is specified
else if (self.classes['node']) {
Comp.array.iter(self.world.nodes, function (node,i) {
var agent = Aios.Code.createOn(node,self.classes['node'],[node.position.x,node.position.y]);
agent.agent.ac='node';
});
}
}
simuTerm.prototype.start = function () {
this.screen.render();
this.out('Initializing ...');
// AC COMPILING
for(var c in this.classes) {
this.out('Compiling agent class '+c+'...');
this.compile(this.classes[c],c);
}
// CONNECTION LINKS
if(this.options.connections.link)
this.out('Setting up physical link(s) ...');
for(var c in this.options.connections.link) {
var link=this.options.connections.link[c];
if (!link.from || !link.to || !link.from.url || !link.to.url || link.from.x==undefined || link.from.y==undefined || !link.dir)
this.err('Invalid link: '+Io.inspect(link));
this.out(link.from.url+' ['+link.from.x+','+link.from.y+'] -> '+link.to.url+(link.to.x!=_?' ['+link.to.x+','+link.to.y+']':''));
var row = this.nodes[link.from.y];
var node = row?row[link.from.x]:_;
if (!node)
this.err('Invalid node reference in link: '+Io.inspect(link));
this.world.connectPhy(link.dir,node,{rcv:link.from.url,snd:link.to.url,verbose:1,out:this.out});
}
this.out('Ready.');
}
var simu = simuTerm;
var JamAnal = Require('jam/analyzer');
simu.prototype.analyze=JamAnal.jamc.prototype.analyze;
simu.prototype.syntax=JamAnal.jamc.prototype.syntax;
simu.prototype.compile = function (ac,name) {
var syntax,
modu,
content,
off;
try {
off=this.syntax.find(this.options.ast,'VariableDeclarator',name);
if (off && off.loc) this.syntax.offset=off.loc.start.line-1;
content = 'var ac = '+ac;
syntax = Esprima.parse(content, { tolerant: true, loc:true });
this.analyze(syntax,{classname:name,level:2,verbose:1});
if (this.options.verbose>=0) this.out('Agent class template '+name+' compiled successfully.');
this.syntax.offset=0;
} catch (e) {
this.out('Agent class template '+name+' not compiled successfully: '+e);
}
};
var Simu = function(options) {
var obj=none;
if (!options || (options && (options.gui=='term' || !options.gui))) obj = new simuTerm(options);
return obj;
}
module.exports = {
simu:simu,
Simu:Simu,
current:function (module) { current=module.current; Aios=module; JamAnal.current(module)}
}