<commit_before>/* jslint node: true */
"use strict";

module.exports = Procedure;
function Procedure(data){
  this.data = data || {};
  this.jobs = [];
  this.main = new Queue();
  this.main.data = this.data;
}
  Procedure.prototype.add = function(func){
    var procedure = this;
    var args = Array.prototype.slice.call(arguments).slice(1);
    procedure.jobs.push({func:func,args:args});
    return procedure;
  };
  Procedure.prototype.queue = function(handler){
    var procedure = this;
    var queue = new Queue();
    queue.jobs = procedure.jobs;
    queue.data = procedure.data;
    procedure.jobs = [];
    queue.handler = function(error){
      if(handler){handler.call(queue,error);}
      if(error){
        procedure.main.handler(error);
      } else {
        procedure.main.done();
      }
    };
    procedure.main.jobs.push({func:queue.launch.bind(queue)});
    return procedure;
  };
  Procedure.prototype.race = function(handler){
    var procedure = this;
    var race = new Race();
    race.jobs = procedure.jobs;
    race.data = procedure.data;
    procedure.jobs = [];
    race.handler = function(error){
      if(handler){handler.call(race,error);}
      if(error){
        procedure.main.handler(error);
      } else {
        procedure.main.done();
      }
    };
    procedure.main.jobs.push({func:race.launch.bind(race)});
    return procedure;
  };
  Procedure.prototype.launch = function(handler){
    var procedure = this;
    procedure.main.handler = handler;
    procedure.main.jobs = procedure.main.jobs.concat(procedure.jobs);
    procedure.main.launch();
  };

Procedure.Race = Race;
function Race(){
  this.jobs = [];
  this.data= {};
  this.counter = 0;
}
  Race.prototype.launch = function(){
    this.counter = this.jobs.length;
    for(var i = 0,l=this.jobs.length;i<l;i++){
      Procedure.Launcher(this,this.jobs[i]);
    }
  };
  Race.prototype.done = function(){
    if(--this.counter === 0){
     this.handler();
    }
  };
  Race.prototype.error = function(error){
    this.handler(error);
  };

Procedure.Queue = Queue;
function Queue(){
  this.jobs = [];
  this.data= {};
}
  Queue.prototype.launch = function(){
    if(this.jobs.length > 0){
      Procedure.Launcher(this,this.jobs[0]);
    } else {
      this.handler();
    }
  };
  Queue.prototype.done = function(){
    this.jobs.shift();
    this.launch();
  };
  Queue.prototype.error = function(error){
    this.handler(error);
  };

Procedure.Launcher = Launcher;
function Launcher(context,job){
  try {
    job.func.apply(context,job.args);
  } catch (error) {
    context.handler(error);
  }
}

/* ---------------------------- *

// Launcher MOD for browser version.
Procedure.Launcher = function jobLauncher(context,job){
  setTimeout(function(){
    try {
      job.func.apply(context,job.args);
    } catch (error) {
      context.handler(error);
    }
  },Math.round(Math.random()*500));
};

/* ---------------------------- *

// Test Procedure.Race & Procedure.Queue:

function Myhand(a,b,c){
  var job = this;
  console.log(a,b,c);
  job.done();
}

var race = new Race();
race.jobs.push({func:Myhand,args:['A1','A2','A3']});
race.jobs.push({func:Myhand,args:['A4','A5','A6']});
race.jobs.push({func:Myhand,args:['A7','A8','A9']});
race.handler = function(error){
  console.log("Finished!",error);
};
race.launch();

var queue = new Queue();
queue.jobs.push({func:Myhand,args:['B1','B2','B3']});
queue.jobs.push({func:Myhand,args:['B4','B5','B6']});
queue.jobs.push({func:Myhand,args:['B7','B8','B9']});
queue.handler = function(error){
  console.log("Finished!",error);
};
queue.launch();

/* ---------------------------- *

// Test Procedure:

var procedure = new Procedure({counter:10}); // <- Initial data for share.

// Add handlers inline...
procedure
.add(function(){
  var job = this;
  var name = "Race[A][1]";
  console.log(name);
  job.data.counter++;
  job.done();
})
.add(function(){
  var job = this;
  var name = "Race[A][2]";
  console.log(name);
  job.data.counter++;
  job.done();
})
.add(function(){
  var job = this;
  var name = "Race[A][3]";
  console.log(name);
  job.data.counter++;
  job.done();
})
.add(function(){
  var job = this;
  var name = "Race[A][4]";
  console.log(name);
  job.data.counter++;
  job.done();
})
.add(function(){
  var job = this;
  var name = "Race[A][5]";
  console.log(name);
  job.data.counter++;
  job.done();
})
// Concurrent execution of pending jobs.
.race(function(error){
  if(!error){
    console.log("Race[A] finished!");
    console.log("Counter:",this.data.counter);
  }
});

// Add hanlers by reference with params [.add(handler,param1,param2,...)].
var Myhand = function(name){
  var job = this;
  console.log(name);
  job.data.counter++;
  job.done();
};

procedure
.add(Myhand,"Queue[A][1]")
.add(Myhand,"Queue[A][2]")
.add(Myhand,"Queue[A][3]")
.add(Myhand,"Queue[A][4]")
.add(Myhand,"Queue[A][5]")
// Queue execution (in order) of pending jobs.
.queue(function(error){
  if(!error){
    console.log("Queue[A] finished!");
    console.log("Counter:",this.data.counter);
  }
})
;

// Add repetitive jobs - Race version
for(var i=0;i<10;i++){ // <- Add repetitive jobs whith variable arguments.
  procedure.add(Myhand,"Race[B]["+i+"]");
}
procedure.race(function(error){
  if(!error){
    console.log("Race[B] finished!");
    console.log("Counter:",this.data.counter);
  }
});

// Add repetitive jobs - Queue version
for(var i=0;i<10;i++){
  procedure.add(Myhand,"Queue[B]["+i+"]");
}
procedure.queue(function(error){
  if(!error){
    console.log("Queue[B] finished!");
    console.log("Counter:",this.data.counter);
  }
});

// Add independent jobs
procedure.add(Myhand,"independent[X]");
procedure.add(Myhand,"independent[Y]");
procedure.add(Myhand,"independent[Z]");

// And finally launch!
procedure
.launch(function(error){
  if(error){ // Called by each error.
    console.log("One Error:",error);
  } else { // Called only if finished whitout errors.
    console.log("All finished");
    console.log("Counter:",this.data.counter);
  }
});

/* ---------------------------- *

var Myhand = function(name){
  var job = this;
  console.log(name);
  job.data.counter++;
  job.done();
};

// Errors management

var procedure = new Procedure({counter:10}); // <- Initial data for share.

procedure
.add(Myhand,"Queue[C][1]")
.add(Myhand,"Queue[C][2]")
.add(function(){
  var job = this;
  console.log("Queue[C][3] Throw Error!...");
  try {
    var a = b;
    job.done();
  } catch(error) {
    job.error(error);
  }
})
.add(Myhand,"Queue[C][4]")
.add(Myhand,"Queue[C][5]")
.launch(function(error){
  if(error){
    console.log("One Error:",error);
  } else {
    console.log("All finished");
    console.log("Counter:",this.data.counter);
  }
});

/* ---------------------------- */<commit_msg>Extended methodology, better error handling and chained results<commit_after>/* jslint node: true */
"use strict";

module.exports = Procedure;
function Procedure(){
  this.jobs = [];
  this.main = new Queue();
  this.main.main = true;
  this.main.procedure = this;
  //console.log("- Creando procedimiento...");
}
  Procedure.prototype.add = function(name,func){
    var procedure = this;
    var args = Array.prototype.slice.call(arguments);
    if(typeof name !== "string"){
        func = name;
        name = "Job-"+procedure.jobs.length;
        args = args.slice(1);
    } else {
        args = args.slice(2);
    }
    //console.log("-- Añadida tarea.",args);
    procedure.jobs.push({name:name,func:func,args:args});
    return procedure;
  };
  Procedure.prototype.queue = function(){
    return this.resolve('queue');
  };
  Procedure.prototype.race = function(){
    return this.resolve('race');
  };
  Procedure.prototype.resolve = function(mode){
    var procedure = this;
    var resolve;
    resolve = mode === 'race' ? new Race() : new Queue();
    resolve.jobs = procedure.jobs;
    //console.log("-- Nueva resolución ("+mode+") de "+resolve.jobs.length+" tareas.");
    resolve.procedure = procedure;
    procedure.jobs = [];
    resolve.handler = function(error){
      var data = Array.prototype.slice.call(arguments);
      if(error){
        //console.log("-- Terminado "+mode+" con error",data);
        procedure.main.handler.apply(procedure.main,data);
      } else {
        //console.log("-- Terminado "+mode+" sin errores",data);
        procedure.main.done.apply(procedure.main,[undefined].concat(data));
      }
    };
    procedure.main.jobs.push({func:resolve.launch.bind(resolve),args:[]});
    return procedure;
  };
  Procedure.prototype.launch = function(handler){
    var procedure = this;
    procedure.main.handler = handler;
    procedure.main.jobs = procedure.main.jobs.concat(procedure.jobs);
    //console.log("-- Iniciado procedimiento con "+procedure.main.jobs.length+" tareas.");
    procedure.main.launch();
  };

Procedure.Race = Race;
function Race(){
  this.handler = undefined;
  this.jobs = [];
  this.results = {};
  this.errors = [];
}
  Race.prototype.launch = function(){
    var data = Array.prototype.slice.call(arguments);
    //console.log("--- Iniciando race...",data);
    //console.log("-- Elimina el callback sobrante del main Queue");
    data = data.slice(0,-1);
    if(this.jobs.length===0){
      this.handler(undefined,this.results);
    } else {
      for(var i = 0,l=this.jobs.length;i<l;i++){
        var job = this.jobs[i];
        Procedure.Launcher(this,job.name,job.func,job.args);
      }
    }
  };
  Race.prototype.done = function Done(name,error){
    //console.log("--- Terminada tarea race",arguments);
    var data = Array.prototype.slice.call(arguments).slice(1);
    if(error){
      this.errors.push(error);
      data = data.slice(1);
    }
    this.results[name] = data;
    if(this.jobs.length===Object.keys(this.results).length){
      if(this.errors.length>0){
        this.handler(this.errors);
      } else {
        this.handler(undefined,this.results);
      }
    }
  };

Procedure.Queue = Queue;
function Queue(){
  this.handler = undefined;
  this.jobs = [];
}
  Queue.prototype.launch = function(){
    var data = Array.prototype.slice.call(arguments);
    //console.log("--- Iniciando queue...",data);
    if(!this.main){
      //console.log("-- Elimina el callback sobrante del main Queue");
      data = data.slice(0,-1);
    }
    if(this.jobs.length > 0){
      var job = this.jobs[0];
      Procedure.Launcher(this,job.name,job.func,data.concat(job.args));
    } else {
      this.handler.apply(this,data);
    }
  };
  Queue.prototype.done = function Done(name,error){
    //console.log("--- Terminada tarea queue",arguments);
    var data = Array.prototype.slice.call(arguments).slice(1);
    if(error){
      error = [error];
      this.handler.apply(this,[error].concat(data.slice(1)));
    } else {
      this.jobs.shift();
      if(this.jobs.length > 0){
        var job = this.jobs[0];
        Procedure.Launcher(this,job.name,job.func,data.slice(1).concat(job.args));
      } else {
        this.handler.apply(this,data);
      }
    }
  };

Procedure.Launcher = Launcher;
Procedure.Launcher.method = global.setImmediate;
function Launcher(context,name,func,args){
  return Procedure.Launcher.method(function(){
    var catcher = context.done.bind(context,name);
    catcher.result = catcher.bind(context,undefined);
    try {
      func.apply(context,args.concat([catcher]));
    } catch (error) {
      error.message = "Procedure error in '"+name+"' > "+error.name+" "+error.message;
      error.name = "ProcedureError";
      catcher(error);
    }
  });
}

/* ---------------------------- *

// Launcher MOD for browser version.

Procedure.Launcher.method = function(task){
    return setTimeout(task,Math.round(Math.random()*100));
}

/* ---------------------------- *

function fileLoader(path,done){                        // File loader simulation.
  console.log("Opening file:'"+path+"'...");
  if(path==='./secundary2.key'){
    //throw new Error("Ops!");                         // Error simulation
  }
  done.result({file:path});                            // Finalize task & return result
}
var shared = {};                                       // Shared closure

var procedure = new Procedure();                       // Create procedure
procedure
.add("Load primary",fileLoader,'./primary.key')        // Add new task
.add("Load secundary",fileLoader,'./secundary.key')    // Add new task
.add("Load shared",fileLoader,'./shared.key')          // Add new task
.race()                                                // Resolve tasks in race mode
.add(function(files,done){                             // Add new task
    shared.files1 = files;
    console.log(shared);
    done();                                            // Finalize task
})
.queue()                                               // Resolve tasks in queue mode
.add("Load primary",fileLoader,'./primary2.key')       // Add new task
.add("Load secundary",fileLoader,'./secundary2.key')   // Add new task
.add("Load shared",fileLoader,'./shared2.key')         // Add new task
.race()                                                // Resolve tasks in race mode
.add(function(files,done){                             // Add new task
    shared.files2 = files;
    console.log(shared);
    done.result(shared);                                 // Finalize task & return result
})
.launch(function(errors){                              // Procedure controller.
    if(errors){                                        // Array of Errors || undefined
        console.log("END[ERROR]",arguments);
    } else {
        console.log("END[OK]",arguments);
    }
})
;

/* ---------------------------- */
<|endoftext|>


<commit_before>(function()
{
    "use strict";

    var math = require('mathjs');

    var R = require('ramda');
    var Rp = require('./plus-fp/plus-fp');

    // additional functions beyond the traditional z^2 + c

    var applyFnMultC = function(fn, z, c)
    {
        var a = fn(z);
        var z2 = math.multiply(a, c);

        return this.finite(z2);
    };

    var applyFnMultZ = function(fn, z, zr, c)
    {
        var a = fn(zr);
        var z2 = math.chain(a).multiply(z).add(c).done();

        return this.finite(z2);

    };

    exports.processes = [
        {
            name: 'z2plusc',
            weight: 1,
            fn: function(z, c)
            {
                return math.chain(z)
                    .square()
                    .add(c)
                    .done();
            }
        },
        {
            name: 'znplusc',
            weight: 1,
            fn: function(z, c)
            {
                return math.chain(z)
                    .pow(this.pow)
                    .add(c)
                    .done();
            }
        },
        {
            name: 'zc',
            weight: 1,
            fn: function(z, c)
            {
                return math.multiply(z, c);
            }
        },
        {
            name: 'coszc',
            weight: 1,
            fn: function(z, c)
            {
                // convert to radians up to 2pi
                var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));

                // pass this (the functal object) as the context
                return applyFnMultC.call(this, math.cos, zr, c);
            }
        },
        {
            name: 'acoszc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.acos, z, c);
            }
        },
        {
            name: 'cotzc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.cot, z, c);
            }
        },
        {
            name: 'cothzc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.coth, z, c);
            }
        },
        {
            name: 'csczc',
            weight: 0.2, // good, but too easily picked
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.csc, z, c);
            }
        },
        {
            name: 'cschzc',
            weight: 0.2, // good, but too easily picked
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.csch, z, c);
            }
        },
        {
            name: 'expzc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.exp, z, c);
            }
        },
        {
            name: 'logzc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.log, z, c);
            }
        },
        {
            name: 'zsinz',
            weight: 1,
            fn: function(z, c)
            {
                var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));

                return applyFnMultZ.call(this, math.sin, z, zr, c);
            }
        },
        {
            name: 'z2sinz',
            weight: 0.5,
            fn: function(z, c)
            {
                var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));

                return applyFnMultZ.call(this, math.sin, math.multiply(z, z), zr, c);
            }
        },
        {
            name: 'z2plussinzplusc',
            weight: 1,
            fn: function(z, c)
            {
                var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));
                var szr = this.finite(math.sin(zr));

                return math.chain(z)
                    .pow(2)
                    .add(szr)
                    .add(c)
                    .done();
            }
        },

        {
            name: 'znplusxyplusc',
            weight: 1,
            fn: (function()
            {
                var znplusxyplusc = {
                    xfactor: math.random(5),
                    yfactor: math.random(5)
                };

                return function(z, c)
                {
                    if (!this.znplusxyplusc)
                    {
                        this.znplusxyplusc = znplusxyplusc;
                    }

                    return this.finite(math.chain(z)
                        .pow(this.pow)
                        .add(znplusxyplusc.xfactor * z.re)
                        .add(znplusxyplusc.yfactor * z.im)
                        .add(c)
                        .done());
                };
            })()
        },
        {
            // adjust real & imag parts with function of the opposite
            name: 'fxtrigy',
            weight: 0.01, // good, but too easily chosen, so reduce weight
            fn: (function()
            {
                // options will be the same for the entire run
                var trig = Rp.wandom([math.sin, math.cos]);

                // keep inside anon function so they are constant
                var fxtrigy = {
                    ampl1: math.random(0.2),
                    ampl2: math.random(0.2),
                    freq1: math.random(20),
                    freq2: math.random(20),
                    fn: trig,
                    name: Rp.nameOf(trig)
                };

                // the actual process function

                return function(z /*, c */ )
                {
                    // store options on first call
                    if (!this.fxtrigy)
                    {
                        this.fxtrigy = fxtrigy;
                    }

                    var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));

                    var fim = fxtrigy.ampl1 * fxtrigy.fn(fxtrigy.freq1 * zr.im);
                    var fre = fxtrigy.ampl2 * fxtrigy.fn(fxtrigy.freq2 * zr.re);

                    var z2 = math.complex(z.re - fim, z.im - fre);

                    return this.finite(z2);
                };
            })()
        },
        {
            // adjust real & imag parts with function of the opposite
            name: 'fxfny',
            weight: 0.06, // good, but too easily chosen, so reduce weight
            fn: (function()
            {
                var funcs = R.times(function()
                {
                    // todo: add ampl & freq to sin
                    return Rp.wandom([math.square, math.sin, R.compose(math.log, math.abs)]);
                }, 2);

                var fxfny = R.map(Rp.nameOf, funcs);

                // the actual process function

                return function(z /*, c */ )
                {
                    // store options on first call
                    if (!this.fxfny)
                    {
                        this.fxfny = fxfny;
                    }

                    var z2 = math.complex(this.finite(z.re + funcs[0](z.im)), this.finite(z.im + funcs[1](z.re)));

                    return this.finite(z2);
                };
            })()
        },
        {
            name: 'z2plusc on z - c',
            weight: 1,
            fn: function(z, c)
            {
                return math.chain(z)
                    .square()
                    .add(c)
                    .divide(z - c)
                    .done();
            }
        },

    ];

}());
<commit_msg>revert formulae<commit_after>(function()
{
    "use strict";

    var math = require('mathjs');

    var R = require('ramda');
    var Rp = require('./plus-fp/plus-fp');

    // additional functions beyond the traditional z^2 + c

    var applyFnMultC = function(fn, z, c)
    {
        var a = fn(z);
        var z2 = math.multiply(a, c);

        return this.finite(z2);
    };

    var applyFnSubtractC = function(fn, z, c)
    {
        var a = fn(z);
        var z2 = math.subtract(a, c);

        return this.finite(z2);
    };

    var applyFnMultZ = function(fn, z, zr, c)
    {
        var a = fn(zr);
        var z2 = math.chain(a).multiply(z).add(c).done();

        return this.finite(z2);

    };

    exports.processes = [
        {
            name: 'z2plusc',
            weight: 1,
            fn: function(z, c)
            {
                return math.chain(z)
                    .square()
                    .add(c)
                    .done();
            }
        },
        {
            name: 'znplusc',
            weight: 1,
            fn: function(z, c)
            {
                return math.chain(z)
                    .pow(this.pow)
                    .add(c)
                    .done();
            }
        },
        {
            name: 'zc',
            weight: 1,
            fn: function(z, c)
            {
                return math.multiply(z, c);
            }
        },
        {
            name: 'coszc',
            weight: 1,
            fn: function(z, c)
            {
                // convert to radians up to 2pi
                var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));

                // pass this (the functal object) as the context
                return applyFnMultC.call(this, math.cos, zr, c);
            }
        },
        {
            name: 'acoszc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.acos, z, c);
            }
        },
        {
            name: 'cotzc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.cot, z, c);
            }
        },
        {
            name: 'cothzc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.coth, z, c);
            }
        },
        {
            name: 'csczc',
            weight: 0.2, // good, but too easily picked
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.csc, z, c);
            }
        },
        {
            name: 'cschzc',
            weight: 0.2, // good, but too easily picked
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.csch, z, c);
            }
        },
        {
            name: 'expz*c',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.exp, z, c);
            }
        },
        {
            name: 'expz-c',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnSubtractC.call(this, math.exp, z, c);
            }
        },
        {
            name: 'logzc',
            weight: 1,
            fn: function(z, c)
            {
                return applyFnMultC.call(this, math.log, z, c);
            }
        },
        {
            name: 'zsinz',
            weight: 1,
            fn: function(z, c)
            {
                var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));

                return applyFnMultZ.call(this, math.sin, z, zr, c);
            }
        },
        {
            name: 'z2sinz',
            weight: 0.5,
            fn: function(z, c)
            {
                var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));

                return applyFnMultZ.call(this, math.sin, math.multiply(z, z), zr, c);
            }
        },
        {
            name: 'z2+sinz+c',
            weight: 1,
            fn: function(z, c)
            {
                var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));
                var szr = this.finite(math.sin(zr));

                return math.chain(z)
                    .pow(2)
                    .add(szr)
                    .add(c)
                    .done();
            }
        },

        {
            name: 'znplusxyplusc',
            weight: 1,
            fn: (function()
            {
                var znplusxyplusc = {
                    xfactor: math.random(5),
                    yfactor: math.random(5)
                };

                return function(z, c)
                {
                    if (!this.znplusxyplusc)
                    {
                        this.znplusxyplusc = znplusxyplusc;
                    }

                    return this.finite(math.chain(z)
                        .pow(this.pow)
                        .add(znplusxyplusc.xfactor * z.re)
                        .add(znplusxyplusc.yfactor * z.im)
                        .add(c)
                        .done());
                };
            })()
        },
        {
            // adjust real & imag parts with function of the opposite
            name: 'fxtrigy',
            weight: 0.01, // good, but too easily chosen, so reduce weight
            fn: (function()
            {
                // options will be the same for the entire run
                var trig = Rp.wandom([math.sin, math.cos]);

                // keep inside anon function so they are constant
                var fxtrigy = {
                    ampl1: math.random(0.2),
                    ampl2: math.random(0.2),
                    freq1: math.random(20),
                    freq2: math.random(20),
                    fn: trig,
                    name: Rp.nameOf(trig)
                };

                // the actual process function

                return function(z /*, c */ )
                {
                    // store options on first call
                    if (!this.fxtrigy)
                    {
                        this.fxtrigy = fxtrigy;
                    }

                    var zr = math.complex(math.mod(z.re, math.pi * 2), math.mod(z.im, math.pi * 2));

                    var fim = fxtrigy.ampl1 * fxtrigy.fn(fxtrigy.freq1 * zr.im);
                    var fre = fxtrigy.ampl2 * fxtrigy.fn(fxtrigy.freq2 * zr.re);

                    var z2 = math.complex(z.re - fim, z.im - fre);

                    return this.finite(z2);
                };
            })()
        },
        {
            // adjust real & imag parts with function of the opposite
            name: 'fxfny',
            weight: 0.06, // good, but too easily chosen, so reduce weight
            fn: (function()
            {
                var funcs = R.times(function()
                {
                    // todo: add ampl & freq to sin
                    return Rp.wandom([math.square, math.sin, R.compose(math.log, math.abs)]);
                }, 2);

                var fxfny = R.map(Rp.nameOf, funcs);

                // the actual process function

                return function(z /*, c */ )
                {
                    // store options on first call
                    if (!this.fxfny)
                    {
                        this.fxfny = fxfny;
                    }

                    var z2 = math.complex(this.finite(z.re + funcs[0](z.im)), this.finite(z.im + funcs[1](z.re)));

                    return this.finite(z2);
                };
            })()
        },

    ];

}());
<|endoftext|>


<commit_before>var util = (function() {
  function interpolateColors(color1, color2, weight1, weight2) {
    return {
      h: getWeightedAverage(color1.h, color2.h, weight1, weight2),
      s: getWeightedAverage(color1.s, color2.s, weight1, weight2),
      l: getWeightedAverage(color1.l, color2.l, weight1, weight2)
    };
  }

  function colorToString(color) {
    return 'hsl(' + color.h + ',' + color.s + '%,' + color.l + '%)';
  }

  function getWeightedAverage(number1, number2, weight1, weight2) {
    return number1 * weight1 + number2 * weight2;
  }

  function getRandom(min, max, easingFunction) {
    var r;
    if (typeof easingFunction != 'undefined') {
      r = applyEasing(Math.random(), easingFunction);
      return min + r * (max - min);
    } else {
      return min + Math.random() * (max - min);
    }
  }

  function applyEasing(t, easingFunction) {
    switch (easingFunction) {
      case 'linear': return t;
      case 'easeInQuad': return t * t;
      case 'easeOutQuad': return t * (2 - t);
      case 'easeInOutQuad': return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
      case 'easeInCubic': return t * t * t;
      case 'easeOutCubic': return 1 + --t * t * t;
      case 'easeInOutCubic': return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
      case 'easeInQuart': return t * t * t * t;
      case 'easeOutQuart': return 1 - --t * t * t * t;
      case 'easeInOutQuart': return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
      case 'easeInQuint': return t * t * t * t * t;
      case 'easeOutQuint': return 1 + --t * t * t * t * t;
      case 'easeInOutQuint': return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
      default: return t;
    }
  }

  function getDistance(x1, y1, x2, y2) {
    var deltaX, deltaY;
    deltaX = x2 - x1;
    deltaY = y2 - y1;
    return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
  }

  // Awesomely helpful page: http://stackoverflow.com/questions/345838/ball-to-ball-collision-detection-and-handling
  function inellasticCollision(p1, vi1, m1, p2, vi2, m2) {
    var normalizedCoaxialVector, perpSpeedI1, perpSpeedI2, tangVelocity1, tangVelocity2, perpSpeedF1, perpSpeedF2, tmp1, tmp2, vf1, vf2;
    // Get the components of the velocity vectors that are parallel to the collision (the perpendicular components will
    // remain constant across the collision)
    normalizedCoaxialVector = normalize(vectorDifference(p2, p1));
    perpSpeedI1 = dotProduct(vi1, normalizedCoaxialVector);
    perpSpeedI2 = dotProduct(vi2, normalizedCoaxialVector);
    tangVelocity1 = vectorDifference(vi1, scalarVectorProduct(perpSpeedI1, normalizedCoaxialVector));
    tangVelocity2 = vectorDifference(vi2, scalarVectorProduct(perpSpeedI2, normalizedCoaxialVector));
    // Solve for new velocities using the 1-dimensional inelastic collision equation
    tmp1 = perpSpeedI1 * m1 + perpSpeedI2 * m2;
    tmp2 = m1 + m2;
    perpSpeedF1 = (PARAMS.COEFF_OF_RESTITUTION * m2 * (perpSpeedI2 - perpSpeedI1) + tmp1) / tmp2;
    perpSpeedF2 = (PARAMS.COEFF_OF_RESTITUTION * m1 * (perpSpeedI1 - perpSpeedI2) + tmp1) / tmp2;
    // Add the tangential velocity changes to the original velocities
    vf1 = vectorAddition(vi1, scalarVectorProduct((perpSpeedF1 - perpSpeedI1), normalizedCoaxialVector));
    vf2 = vectorAddition(vi2, scalarVectorProduct((perpSpeedF2 - perpSpeedI2), normalizedCoaxialVector));
    return {
      vf1: vf1,
      vf2: vf2,
      tangVelocity1: tangVelocity1,
      tangVelocity2: tangVelocity2,
      perpSpeedI1: perpSpeedI1,
      perpSpeedI2: perpSpeedI2,
      perpSpeedF1: perpSpeedF1,
      perpSpeedF2: perpSpeedF2
    };
  }

  function getTangVelocityAndPerpSpeed(p1, p2, v1) {
    var normalizedCoaxialVector, perpSpeed, tangVelocity;
    normalizedCoaxialVector = normalize(vectorDifference(p2, p1));
    perpSpeed = dotProduct(v1, normalizedCoaxialVector);
    tangVelocity = vectorDifference(v1, scalarVectorProduct(perpSpeed, normalizedCoaxialVector));
    return {
      tangVelocity: tangVelocity,
      perpSpeed: perpSpeed
    };
  }

  function reflect(v, reflectionLine) {
    reflectionLine = normalize(reflectionLine);
    return vectorDifference(v, scalarVectorProduct(2 * dotProduct(v, reflectionLine), reflectionLine));
  }

  function dotProduct(v1, v2) {
    return v1.x * v2.x + v1.y * v2.y;
  }

  function magnitude(v) {
    return Math.sqrt(v.x * v.x + v.y * v.y);
  }

  function scalarVectorProduct(s, v) {
    return {
      x: s * v.x,
      y: s * v.y
    };
  }

  function vectorDifference(v1, v2) {
    return {
      x: v1.x - v2.x,
      y: v1.y - v2.y
    };
  }

  function vectorAddition(v1, v2) {
    return {
      x: v1.x + v2.x,
      y: v1.y + v2.y
    };
  }

  function normalize(v) {
    var mag = magnitude(v);
    return {
      x: v.x / mag,
      y: v.y / mag
    };
  }

  function changeStartAndEndTimeFromBlur(transitionObj, timeLapse) {
    transitionObj.startTime = timeLapse + transitionObj.startTime;
    transitionObj.endTime = timeLapse + transitionObj.endTime;
  }

  function getPageXY(element) {
    var cumulativeX = 0,
        cumulativeY = 0;
    while (element) {
      cumulativeX += element.offsetLeft;
      cumulativeY += element.offsetTop;
      element = element.offsetParent;
    }
    return { x: cumulativeX, y: cumulativeY };
  }

  function determineViewportDimensions(viewport) {
    viewport.width = document.documentElement.clientWidth;
    viewport.height = document.documentElement.clientHeight;
  }

  var myRequestAnimationFrame =
      window.requestAnimationFrame || // the standard
          window.webkitRequestAnimationFrame || // chrome/safari
          window.mozRequestAnimationFrame || // firefox
          window.oRequestAnimationFrame || // opera
          window.msRequestAnimationFrame || // ie
          function(callback) { // default
            window.setTimeout(callback, 16); // 60fps
          };

  return {
    interpolateColors: interpolateColors,
    colorToString: colorToString,
    getWeightedAverage: getWeightedAverage,
    getRandom: getRandom,
    applyEasing: applyEasing,
    getDistance: getDistance,
    inellasticCollision: inellasticCollision,
    getTangVelocityAndPerpSpeed: getTangVelocityAndPerpSpeed,
    reflect: reflect,
    dotProduct: dotProduct,
    magnitude: magnitude,
    scalarVectorProduct: scalarVectorProduct,
    vectorDifference: vectorDifference,
    vectorAddition: vectorAddition,
    normalize: normalize,
    changeStartAndEndTimeFromBlur: changeStartAndEndTimeFromBlur,
    getPageXY: getPageXY,
    determineViewportDimensions: determineViewportDimensions,
    myRequestAnimationFrame: function(callback) {
      myRequestAnimationFrame.call(window, callback);
    }
  };
})();
<commit_msg>Update util.js<commit_after>var util = (function() {
  function interpolateColors(color1, color2, weight1, weight2) {
    return {
      h: getWeightedAverage(color1.h, color2.h, weight1, weight2),
      s: getWeightedAverage(color1.s, color2.s, weight1, weight2),
      l: getWeightedAverage(color1.l, color2.l, weight1, weight2)
    };
  }

  function colorToString(color) {
    return 'hsl(' + color.h + ',' + color.s + '%,' + color.l + '%)';
  }

  function getWeightedAverage(number1, number2, weight1, weight2) {
    return number1 * weight1 + number2 * weight2;
  }

  function getRandom(min, max, easingFunction) {
    var r;
    if (typeof easingFunction != 'undefined') {
      r = applyEasing(Math.random(), easingFunction);
      return min + r * (max - min);
    } else {
      return min + Math.random() * (max - min);
    }
  }

  function applyEasing(t, easingFunction) {
    switch (easingFunction) {
      case 'linear': return t;
      case 'easeInQuad': return t * t;
      case 'easeOutQuad': return t * (2 - t);
      case 'easeInOutQuad': return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
      case 'easeInCubic': return t * t * t;
      case 'easeOutCubic': return 1 + --t * t * t;
      case 'easeInOutCubic': return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
      case 'easeInQuart': return t * t * t * t;
      case 'easeOutQuart': return 1 - --t * t * t * t;
      case 'easeInOutQuart': return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * --t * t * t * t;
      case 'easeInQuint': return t * t * t * t * t;
      case 'easeOutQuint': return 1 + --t * t * t * t * t;
      case 'easeInOutQuint': return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * --t * t * t * t * t;
      default: return t;
    }
  }

  function getDistance(x1, y1, x2, y2) {
    var deltaX, deltaY;
    deltaX = x2 - x1;
    deltaY = y2 - y1;
    return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
  }

  // Awesomely helpful page: http://stackoverflow.com/questions/345838/ball-to-ball-collision-detection-and-handling
  function inellasticCollision(p1, vi1, m1, p2, vi2, m2) {
    var normalizedCoaxialVector, perpSpeedI1, perpSpeedI2, tangVelocity1, tangVelocity2, perpSpeedF1, perpSpeedF2, tmp1, tmp2, vf1, vf2;
    // Get the components of the velocity vectors that are parallel to the collision (the perpendicular components will
    // remain constant across the collision)
    normalizedCoaxialVector = normalize(vectorDifference(p2, p1));
    perpSpeedI1 = dotProduct(vi1, normalizedCoaxialVector);
    perpSpeedI2 = dotProduct(vi2, normalizedCoaxialVector);
    tangVelocity1 = vectorDifference(vi1, scalarVectorProduct(perpSpeedI1, normalizedCoaxialVector));
    tangVelocity2 = vectorDifference(vi2, scalarVectorProduct(perpSpeedI2, normalizedCoaxialVector));
    // Solve for new velocities using the 1-dimensional inelastic collision equation
    tmp1 = perpSpeedI1 * m1 + perpSpeedI2 * m2;
    tmp2 = m1 + m2;
    perpSpeedF1 = (PARAMS.COEFF_OF_RESTITUTION * m2 * (perpSpeedI2 - perpSpeedI1) + tmp1) / tmp2;
    perpSpeedF2 = (PARAMS.COEFF_OF_RESTITUTION * m1 * (perpSpeedI1 - perpSpeedI2) + tmp1) / tmp2;
    // Add the tangential velocity changes to the original velocities
    vf1 = vectorAddition(vi1, scalarVectorProduct((perpSpeedF1 - perpSpeedI1), normalizedCoaxialVector));
    vf2 = vectorAddition(vi2, scalarVectorProduct((perpSpeedF2 - perpSpeedI2), normalizedCoaxialVector));
    return {
      vf1: vf1,
      vf2: vf2,
      tangVelocity1: tangVelocity1,
      tangVelocity2: tangVelocity2,
      perpSpeedI1: perpSpeedI1,
      perpSpeedI2: perpSpeedI2,
      perpSpeedF1: perpSpeedF1,
      perpSpeedF2: perpSpeedF2
    };
  }

  function getTangVelocityAndPerpSpeed(p1, p2, v1) {
    var normalizedCoaxialVector, perpSpeed, tangVelocity;
    normalizedCoaxialVector = normalize(vectorDifference(p2, p1));
    perpSpeed = dotProduct(v1, normalizedCoaxialVector);
    tangVelocity = vectorDifference(v1, scalarVectorProduct(perpSpeed, normalizedCoaxialVector));
    return {
      tangVelocity: tangVelocity,
      perpSpeed: perpSpeed
    };
  }

  function reflect(v, reflectionLine) {
    reflectionLine = normalize(reflectionLine);
    return vectorDifference(v, scalarVectorProduct(2 * dotProduct(v, reflectionLine), reflectionLine));
  }

  function dotProduct(v1, v2) {
    return v1.x * v2.x + v1.y * v2.y;
  }

  function magnitude(v) {
    return Math.sqrt(v.x * v.x + v.y * v.y);
  }

  function scalarVectorProduct(s, v) {
    return {
      x: s * v.x,
      y: s * v.y
    };
  }

  function vectorDifference(v1, v2) {
    return {
      x: v1.x - v2.x,
      y: v1.y - v2.y
    };
  }

  function vectorAddition(v1, v2) {
    return {
      x: v1.x + v2.x,
      y: v1.y + v2.y
    };
  }

  function normalize(v) {
    var mag = magnitude(v);
    return {
      x: v.x / mag,
      y: v.y / mag
    };
  }

  function changeStartAndEndTimeFromBlur(transitionObj, timeLapse) {
    transitionObj.startTime = timeLapse + transitionObj.startTime;
    transitionObj.endTime = timeLapse + transitionObj.endTime;
  }

  function getPageXY(element) {
    var cumulativeX = 0,
        cumulativeY = 0;
    while (element) {
      cumulativeX += element.getBoundingClientRect().left;
      cumulativeY += element.getBoundingClientRect().top;
      element = element.offsetParent;
    }
    return { x: cumulativeX, y: cumulativeY };
  }

  function determineViewportDimensions(viewport) {
    viewport.width = document.documentElement.clientWidth;
    viewport.height = document.documentElement.clientHeight;
  }

  var myRequestAnimationFrame =
      window.requestAnimationFrame || // the standard
          window.webkitRequestAnimationFrame || // chrome/safari
          window.mozRequestAnimationFrame || // firefox
          window.oRequestAnimationFrame || // opera
          window.msRequestAnimationFrame || // ie
          function(callback) { // default
            window.setTimeout(callback, 16); // 60fps
          };

  return {
    interpolateColors: interpolateColors,
    colorToString: colorToString,
    getWeightedAverage: getWeightedAverage,
    getRandom: getRandom,
    applyEasing: applyEasing,
    getDistance: getDistance,
    inellasticCollision: inellasticCollision,
    getTangVelocityAndPerpSpeed: getTangVelocityAndPerpSpeed,
    reflect: reflect,
    dotProduct: dotProduct,
    magnitude: magnitude,
    scalarVectorProduct: scalarVectorProduct,
    vectorDifference: vectorDifference,
    vectorAddition: vectorAddition,
    normalize: normalize,
    changeStartAndEndTimeFromBlur: changeStartAndEndTimeFromBlur,
    getPageXY: getPageXY,
    determineViewportDimensions: determineViewportDimensions,
    myRequestAnimationFrame: function(callback) {
      myRequestAnimationFrame.call(window, callback);
    }
  };
})();
<|endoftext|>


<commit_before>import HomeSocket from './home_socket'
import Inferno from 'inferno'
import List from 'inferno-virtual-list'
import { createHomeChart, createAddressChart } from './create_charts'
import { getClass, getName, getIcon, formatterZero, formatterTwo, formatBTC, formatBTCLarge } from './helpers'

const moment = require('moment')

const blocksContainer = document.getElementById('blocks-wrapper')
const transactionsContainer = document.getElementById('transactions-wrapper')

const blockRow = row => (

      {row.index.toLocaleString()}

Size: {row.size.toLocaleString()} bytes

Transactions: {row.tx_count.toLocaleString()}

Created: { moment.unix(row.time).format('DD-MM-YYYY') + ' | ' + moment.unix(row.time).format('HH:mm:ss')}

)

const transactionRow = row => (

{getName(row.type)}

Txid: {row.txid}

Created: { moment.unix(row.time).format('DD-MM-YYYY') + ' | ' + moment.unix(row.time).format('HH:mm:ss')}

)

window.onload = function () {
  // homepage javascript
  if (window.location.pathname === '/') {
    let displayCoin = 'neo'
    let displayChart = 'usd'
    let displayTime = '1m'

    let payload = {
      blocks: [],
      transactions: [],
      stats: {},
      price: {}
    }
    let home = new HomeSocket(payload)

    setInterval(function () {
      Inferno.render((
        <List class='blocks-list' sync={false} data={home.payload.blocks} rowHeight={15} rowRender={blockRow} />
      ), blocksContainer)
      Inferno.render((
        <List class='transactions-list' sync={false} data={home.payload.transactions} rowHeight={15} rowRender={transactionRow} />
      ), transactionsContainer)
      if (home.payload.price && home.payload.price.neo && home.payload.price.gas) {
        const coinPayload = displayCoin === 'neo' ? home.payload.price.neo[displayChart] : home.payload.price.gas[displayChart]
        document.getElementById('total-tx').innerHTML = home.payload.stats.total_transactions.toLocaleString()
        document.getElementById('total-blocks').innerHTML = home.payload.stats.total_blocks.toLocaleString()
        document.getElementById('total-addresses').innerHTML = home.payload.stats.total_addresses.toLocaleString()
        document.getElementById('mkt-graph-coin-price').innerHTML = displayChart === 'usd' ? formatterTwo.format(coinPayload.PRICE) : `฿ ${formatBTC(coinPayload.PRICE)}`
        document.getElementById('mkt-cap-us').innerHTML = displayChart === 'usd' ? formatterZero.format(coinPayload.MKTCAP) : `฿ ${formatBTCLarge(coinPayload.MKTCAP)}`
        document.getElementById('24hvol').innerHTML = displayChart === 'usd' ? formatterZero.format(coinPayload.TOTALVOLUME24HTO) : `฿ ${formatBTCLarge(coinPayload.TOTALVOLUME24HTO)}`

        document.getElementById('24hchange').innerHTML = coinPayload.CHANGEPCT24HOUR.toFixed(2) +'%'

        if (coinPayload.TOTALVOLUME24HTO.toFixed(0) > 0) {
          document.getElementById('24hvol').setAttribute('class', 'large-stat-number remove-margin-bottom')
        } else {
          document.getElementById('24hvol').setAttribute('class', 'large-stat-number remove-margin-bottom')
        }

        if (coinPayload.CHANGEPCT24HOUR.toFixed(2) > 0) {
          document.getElementById('24hchange').setAttribute('class', 'large-stat-number large-number-positive remove-margin-bottom')
        } else {
          document.getElementById('24hchange').setAttribute('class', 'large-stat-number large-number-negative remove-margin-bottom')
        }
      }
    }, 500)
    home.connect()

    createHomeChart(displayCoin, displayChart, displayTime)

    const priceDropdown = document.getElementById('price-chart')
    const comparisonDropdown = document.getElementById('comparison-chart')
    const zoomInChart = document.getElementById('zoom-in-chart')
    const zoomOutChart = document.getElementById('zoom-out-chart')

    const coinClickHandler = (coin) => {
      displayCoin = coin
      document.getElementById('mkt-graph-coin').innerHTML = coin.toUpperCase()
      return createHomeChart(coin, displayChart, displayTime)
    }

    const compareClickHandler = (compare) => {
      displayChart = compare
      return createHomeChart(displayCoin, compare, displayTime)
    }

    const zoomHandler = (zoom) => {
      if (displayTime === '1d') {
        if (zoom === 'in') return
        displayTime = '1w'
      } else if (displayTime === '1w') {
        displayTime = zoom === 'out' ? '1m' : '1d'
      } else if (displayTime === '1m') {
        displayTime = zoom === 'out' ? '3m' : '1w'
      } else if (displayTime === '3m') {
        if (zoom === 'out') return
        displayTime = '1m'
      }
      return createHomeChart(displayCoin, displayChart, displayTime)
    }

    priceDropdown.onchange = function () {
      coinClickHandler(this.value)
    }
    comparisonDropdown.onchange = function () {
      compareClickHandler(this.value)
    }
    zoomInChart.onclick = () => zoomHandler('in')
    zoomOutChart.onclick = () => zoomHandler('out')
  }

  // address page javascript
  if (window.location.pathname.startsWith('/address/')) {
    const graph_elem = document.getElementById('graph_data')
    const graph_data = JSON.parse(graph_elem.dataset.graphData)
    const count = graph_data.length
    const assetsList = {}
    const dates = ['date']
    graph_data.forEach(({time, assets}) => {
      const date = new Date(time*1000)
      const formattedDate = moment(date).format('YYYY-MM-DD HH:MM:SS')
      if (formattedDate === dates[dates.length-1]) return
      dates.push(formattedDate)

      return assets.forEach((asset) => {
        const assetName = Object.keys(asset)
        if (!assetsList[assetName]) {
          return assetsList[assetName] = [assetName, asset[assetName]]
        } else {
          return assetsList[assetName].push(asset[assetName])
        }
      })
    })

    const transactionsTextElem = document.getElementById('last-x-transactions')
    let transactionText = `Last ${count} Transactions for `

    const assetDropdown = document.getElementById('select-address-chart')
    const assetNames = Object.keys(assetsList)
    assetNames.forEach((name, idx) => {
      const option = document.createElement("option");
      option.text = name;
      option.value = name;
      assetDropdown.add(option);
      if (!assetNames[idx+1] && !assetNames[idx-1] ) {
        transactionText += `${name}`
      } else if (assetNames[idx+1]) {
        transactionText += `${name}, `
      } else {
        transactionText = transactionText.slice(0,-2)
        transactionText += ` and ${name}`
      }

    })

    transactionsTextElem.innerHTML = transactionText

    if (assetsList['NEO']) {
      createAddressChart('NEO', dates, assetsList['NEO'], count)
    } else if (assetsList['GAS']) {
      createAddressChart('GAS', dates, assetsList['GAS'], count)
    } else if (assetNames.length > 0) {
      createAddressChart(assetNames[0], dates, assetsList[assetNames[0]], count)
    }

    assetDropdown.onchange = function () {
      createAddressChart(this.value, dates, assetsList[this.value], count)
    }

    const address_hash = document.getElementById('address_hash').innerHTML
    fetch(`/api/main_net/v1/get_unclaimed/${address_hash}`).then(res => res.json()).then(results => {
      document.getElementsByClassName('loading-gas')[0].innerHTML = ''
      document.getElementsByClassName('unclaimed-gas')[0].innerHTML = `${results.unclaimed} Unclaimed Gas`
    })
  }
}

const acc = document.getElementsByClassName('btn-accordion')
let i

for (i = 0; i < acc.length; i++) {
  acc[i].onclick = function () {
    this.classList.toggle('active')
    let panel = this.nextElementSibling

    if (panel.style.maxHeight) {
      panel.style.maxHeight = null
    } else {
      panel.style.maxHeight = panel.scrollHeight + 'px'
    }
  }
}

$('document').ready(function () {
  $('#language-dropdown').simpleselect()
  $('#tooltip-dropdown').simpleselect()
  $('#price-chart').simpleselect()
  $('#comparison-chart').simpleselect()

  const $hamburger = $('.hamburger')
  $hamburger.on('click', function (e) {
    $hamburger.toggleClass('is-active')

    if ($hamburger.hasClass('is-active')) {
      $('.nav-wrapper').addClass('active-wrapper')
    } else {
      $('.nav-wrapper').removeClass('active-wrapper')
    }

    if (window.matchMedia('(max-width: 660px)').matches && ($hamburger.hasClass('is-active'))) {
      $('.searchbar').addClass('mobile-active')
      $('.search-btn').addClass('mobile-active')
    } else {
      $('.searchbar').removeClass('mobile-active')
      $('.search-btn').removeClass('mobile-active')
    }
  })
})
<commit_msg>fix total blocks<commit_after>import HomeSocket from './home_socket'
import Inferno from 'inferno'
import List from 'inferno-virtual-list'
import { createHomeChart, createAddressChart } from './create_charts'
import { getClass, getName, getIcon, formatterZero, formatterTwo, formatBTC, formatBTCLarge } from './helpers'

const moment = require('moment')

const blocksContainer = document.getElementById('blocks-wrapper')
const transactionsContainer = document.getElementById('transactions-wrapper')

const blockRow = row => (

      {row.index.toLocaleString()}

Size: {row.size.toLocaleString()} bytes

Transactions: {row.tx_count.toLocaleString()}

Created: { moment.unix(row.time).format('DD-MM-YYYY') + ' | ' + moment.unix(row.time).format('HH:mm:ss')}

)

const transactionRow = row => (

{getName(row.type)}

Txid: {row.txid}

Created: { moment.unix(row.time).format('DD-MM-YYYY') + ' | ' + moment.unix(row.time).format('HH:mm:ss')}

)

window.onload = function () {
  // homepage javascript
  if (window.location.pathname === '/') {
    let displayCoin = 'neo'
    let displayChart = 'usd'
    let displayTime = '1m'

    let payload = {
      blocks: [],
      transactions: [],
      stats: {},
      price: {}
    }
    let home = new HomeSocket(payload)

    setInterval(function () {
      Inferno.render((
        <List class='blocks-list' sync={false} data={home.payload.blocks} rowHeight={15} rowRender={blockRow} />
      ), blocksContainer)
      Inferno.render((
        <List class='transactions-list' sync={false} data={home.payload.transactions} rowHeight={15} rowRender={transactionRow} />
      ), transactionsContainer)
      if (home.payload.price && home.payload.price.neo && home.payload.price.gas) {
        const coinPayload = displayCoin === 'neo' ? home.payload.price.neo[displayChart] : home.payload.price.gas[displayChart]
        document.getElementById('total-tx').innerHTML = home.payload.stats.total_transactions.toLocaleString()
        document.getElementById('total-blocks').innerHTML = (home.payload.stats.total_blocks - 1).toLocaleString()
        document.getElementById('total-addresses').innerHTML = home.payload.stats.total_addresses.toLocaleString()
        document.getElementById('mkt-graph-coin-price').innerHTML = displayChart === 'usd' ? formatterTwo.format(coinPayload.PRICE) : `฿ ${formatBTC(coinPayload.PRICE)}`
        document.getElementById('mkt-cap-us').innerHTML = displayChart === 'usd' ? formatterZero.format(coinPayload.MKTCAP) : `฿ ${formatBTCLarge(coinPayload.MKTCAP)}`
        document.getElementById('24hvol').innerHTML = displayChart === 'usd' ? formatterZero.format(coinPayload.TOTALVOLUME24HTO) : `฿ ${formatBTCLarge(coinPayload.TOTALVOLUME24HTO)}`

        document.getElementById('24hchange').innerHTML = coinPayload.CHANGEPCT24HOUR.toFixed(2) +'%'

        if (coinPayload.TOTALVOLUME24HTO.toFixed(0) > 0) {
          document.getElementById('24hvol').setAttribute('class', 'large-stat-number remove-margin-bottom')
        } else {
          document.getElementById('24hvol').setAttribute('class', 'large-stat-number remove-margin-bottom')
        }

        if (coinPayload.CHANGEPCT24HOUR.toFixed(2) > 0) {
          document.getElementById('24hchange').setAttribute('class', 'large-stat-number large-number-positive remove-margin-bottom')
        } else {
          document.getElementById('24hchange').setAttribute('class', 'large-stat-number large-number-negative remove-margin-bottom')
        }
      }
    }, 500)
    home.connect()

    createHomeChart(displayCoin, displayChart, displayTime)

    const priceDropdown = document.getElementById('price-chart')
    const comparisonDropdown = document.getElementById('comparison-chart')
    const zoomInChart = document.getElementById('zoom-in-chart')
    const zoomOutChart = document.getElementById('zoom-out-chart')

    const coinClickHandler = (coin) => {
      displayCoin = coin
      document.getElementById('mkt-graph-coin').innerHTML = coin.toUpperCase()
      return createHomeChart(coin, displayChart, displayTime)
    }

    const compareClickHandler = (compare) => {
      displayChart = compare
      return createHomeChart(displayCoin, compare, displayTime)
    }

    const zoomHandler = (zoom) => {
      if (displayTime === '1d') {
        if (zoom === 'in') return
        displayTime = '1w'
      } else if (displayTime === '1w') {
        displayTime = zoom === 'out' ? '1m' : '1d'
      } else if (displayTime === '1m') {
        displayTime = zoom === 'out' ? '3m' : '1w'
      } else if (displayTime === '3m') {
        if (zoom === 'out') return
        displayTime = '1m'
      }
      return createHomeChart(displayCoin, displayChart, displayTime)
    }

    priceDropdown.onchange = function () {
      coinClickHandler(this.value)
    }
    comparisonDropdown.onchange = function () {
      compareClickHandler(this.value)
    }
    zoomInChart.onclick = () => zoomHandler('in')
    zoomOutChart.onclick = () => zoomHandler('out')
  }

  // address page javascript
  if (window.location.pathname.startsWith('/address/')) {
    const graph_elem = document.getElementById('graph_data')
    const graph_data = JSON.parse(graph_elem.dataset.graphData)
    const count = graph_data.length
    const assetsList = {}
    const dates = ['date']
    graph_data.forEach(({time, assets}) => {
      const date = new Date(time*1000)
      const formattedDate = moment(date).format('YYYY-MM-DD HH:MM:SS')
      if (formattedDate === dates[dates.length-1]) return
      dates.push(formattedDate)

      return assets.forEach((asset) => {
        const assetName = Object.keys(asset)
        if (!assetsList[assetName]) {
          return assetsList[assetName] = [assetName, asset[assetName]]
        } else {
          return assetsList[assetName].push(asset[assetName])
        }
      })
    })

    const transactionsTextElem = document.getElementById('last-x-transactions')
    let transactionText = `Last ${count} Transactions for `

    const assetDropdown = document.getElementById('select-address-chart')
    const assetNames = Object.keys(assetsList)
    assetNames.forEach((name, idx) => {
      const option = document.createElement("option");
      option.text = name;
      option.value = name;
      assetDropdown.add(option);
      if (!assetNames[idx+1] && !assetNames[idx-1] ) {
        transactionText += `${name}`
      } else if (assetNames[idx+1]) {
        transactionText += `${name}, `
      } else {
        transactionText = transactionText.slice(0,-2)
        transactionText += ` and ${name}`
      }

    })

    transactionsTextElem.innerHTML = transactionText

    if (assetsList['NEO']) {
      createAddressChart('NEO', dates, assetsList['NEO'], count)
    } else if (assetsList['GAS']) {
      createAddressChart('GAS', dates, assetsList['GAS'], count)
    } else if (assetNames.length > 0) {
      createAddressChart(assetNames[0], dates, assetsList[assetNames[0]], count)
    }

    assetDropdown.onchange = function () {
      createAddressChart(this.value, dates, assetsList[this.value], count)
    }

    const address_hash = document.getElementById('address_hash').innerHTML
    fetch(`/api/main_net/v1/get_unclaimed/${address_hash}`).then(res => res.json()).then(results => {
      document.getElementsByClassName('loading-gas')[0].innerHTML = ''
      document.getElementsByClassName('unclaimed-gas')[0].innerHTML = `${results.unclaimed} Unclaimed Gas`
    })
  }
}

const acc = document.getElementsByClassName('btn-accordion')
let i

for (i = 0; i < acc.length; i++) {
  acc[i].onclick = function () {
    this.classList.toggle('active')
    let panel = this.nextElementSibling

    if (panel.style.maxHeight) {
      panel.style.maxHeight = null
    } else {
      panel.style.maxHeight = panel.scrollHeight + 'px'
    }
  }
}

$('document').ready(function () {
  $('#language-dropdown').simpleselect()
  $('#tooltip-dropdown').simpleselect()
  $('#price-chart').simpleselect()
  $('#comparison-chart').simpleselect()

  const $hamburger = $('.hamburger')
  $hamburger.on('click', function (e) {
    $hamburger.toggleClass('is-active')

    if ($hamburger.hasClass('is-active')) {
      $('.nav-wrapper').addClass('active-wrapper')
    } else {
      $('.nav-wrapper').removeClass('active-wrapper')
    }

    if (window.matchMedia('(max-width: 660px)').matches && ($hamburger.hasClass('is-active'))) {
      $('.searchbar').addClass('mobile-active')
      $('.search-btn').addClass('mobile-active')
    } else {
      $('.searchbar').removeClass('mobile-active')
      $('.search-btn').removeClass('mobile-active')
    }
  })
})
<|endoftext|>


<commit_before>define([
    'jquery',
    'underscore',
    'knockout',
    'knockout-mapping',
    'models/card',
    'models/card-widget',
    'arches',
    'require',
    'uuid',
    'utils/dispose',
    'viewmodels/tile'
], function($, _, ko, koMapping, CardModel, CardWidgetModel, arches, require, uuid, dispose) {
    /**
    * A viewmodel used for generic cards
    *
    * @constructor
    * @name CardViewModel
    *
    * @param  {string} params - a configuration object
    */
    var isChildSelected = function(parent) {
        var childSelected = false;
        var children = [];
        if ('tileid' in parent) {
            children = ko.unwrap(parent.cards);
        } else if ('model' in parent) {
            children = ko.unwrap(parent.cards).concat(
                ko.unwrap(parent.tiles),
                ko.unwrap(parent.widgets)
            );
        }
        children.forEach(function(child) {
            if (child.selected && child.selected() || isChildSelected(child)) {
                childSelected = true;
            }
        });
        return childSelected;
    };

    var isDirty = function(){
        if(self.tile) {
            return true;
        }
        return false;
    };

    var doesChildHaveProvisionalEdits = function(parent) {
        var hasEdits = false;
        var childrenKey = 'tileid' in parent ? 'cards': 'tiles';
        ko.unwrap(parent[childrenKey]).forEach(function(child) {
            if (child.hasprovisionaledits && child.hasprovisionaledits() || doesChildHaveProvisionalEdits(child)) {
                hasEdits = true;
            }
        });
        return hasEdits;
    };

    var updateDisplayName = function(resourceId, displayname) {
        $.get(
            arches.urls.resource_descriptors + resourceId(),
            function(descriptors) {
                displayname(descriptors.displayname);
            }
        );
    };

    var CardViewModel = function(params) {
        var TileViewModel = require('viewmodels/tile');
        var self = this;
        var hover = params.hover || ko.observable();
        var scrollTo = params.scrollTo || ko.observable();
        var filter = params.filter || ko.observable();
        var loading = params.loading || ko.observable();
        var perms = ko.observableArray();
        var permsLiteral = ko.observableArray();
        var allowProvisionalEditRerender = ko.observable(true);
        var nodegroups = params.graphModel.get('nodegroups');
        var multiselect = params.multiselect || false;
        var isWritable = params.card.is_writable || false;
        var selection;
        var emptyConstraint = [{
            uniquetoallinstances: false,
            nodes:[],
            cardid: self.cardid,
            constraintid:  uuid.generate()
        }];

        var appliedFunctions = params.appliedFunctions;

        if (params.multiselect) {
            selection = params.selection || ko.observableArray([]);
        } else {
            selection = params.selection || ko.observable();
        }
        var nodegroup = _.find(ko.unwrap(nodegroups), function(group) {
            return ko.unwrap(group.nodegroupid) === ko.unwrap(params.card.nodegroup_id);
        });
        var cardModel = new CardModel({
            data: _.extend(params.card, {
                widgets: params.cardwidgets,
                nodes: params.graphModel.get('nodes'),
                nodegroup: nodegroup,
                constraints: params.constraints
            }),
            datatypelookup: params.graphModel.get('datatypelookup'),
        });

        var applySelectedComputed = function(widgets){
            widgets.forEach(function(widget){
                widget.parent = self;
                widget.selected = ko.pureComputed({
                    read: function() {
                        return selection() === this;
                    },
                    write: function(value) {
                        if (value) {
                            selection(this);
                        }
                    },
                    owner: widget
                });
                widget.hovered = ko.pureComputed({
                    read: function() {
                        return hover() === this;
                    },
                    write: function(value) {
                        if (value === true) {
                            hover(this);
                        }
                        if (value === null) {
                            hover(null);
                        }
                    },
                    owner: widget
                });
            });
        };

        applySelectedComputed(cardModel.widgets());

        var widgetsSubscription = cardModel.widgets.subscribe(function(widgets){
            applySelectedComputed(widgets);
        });

        _.extend(this, nodegroup, {
            isWritable: isWritable,
            model: cardModel,
            appliedFunctions: appliedFunctions,
            allowProvisionalEditRerender: allowProvisionalEditRerender,
            multiselect: params.multiselect,
            widgets: cardModel.widgets,
            parent: params.tile,
            parentCard: params.parentCard,
            expanded: ko.observable(false),
            topCards: params.topCards,
            perms: perms,
            constraints: params.constraints || emptyConstraint,
            permsLiteral: permsLiteral,
            scrollTo: ko.pureComputed(function() {
                return scrollTo() === this;
            }, this),
            fullyProvisional: ko.pureComputed(function(){
                var res;
                var provisionalindex;
                var summary = _.map(this.tiles(), function(tile){
                    var dataEmpty = _.keys(koMapping.toJS(tile.data)).length === 0;
                    if (tile.provisionaledits() !== null && dataEmpty) {
                        return 2;
                    } else if (tile.provisionaledits() !== null && !dataEmpty) {
                        return 1;
                    } else {
                        return 0;
                    }
                });
                provisionalindex = _.reduce(summary, function(a, b){return a + b;});
                if (provisionalindex > 0) {
                    if (_.every(summary, function(val){return val === 2;})) {
                        res = 'fullyprovisional';
                    }
                    else {
                        res = 'provisional';
                    }
                }
                return res;
            }, this),
            highlight: ko.computed(function() {
                var filterText = filter();
                if (!filterText) {
                    return false;
                }
                filterText = filterText.toLowerCase();
                if (params.card.name.toLowerCase().indexOf(filterText) > -1) {
                    return true;
                }
            }, this),
            tiles: ko.observableArray(
                _.filter(params.tiles, function(tile) {
                    return (
                        params.tile ? (tile.parenttile_id === params.tile.tileid) : true
                    ) && ko.unwrap(tile.nodegroup_id) === ko.unwrap(params.card.nodegroup_id);
                }).map(function(tile) {
                    return new TileViewModel({
                        tile: tile,
                        card: self,
                        graphModel: params.graphModel,
                        resourceId: params.resourceId,
                        displayname: params.displayname,
                        handlers: params.handlers,
                        userisreviewer: params.userisreviewer,
                        cards: params.cards,
                        tiles: params.tiles,
                        provisionalTileViewModel: params.provisionalTileViewModel,
                        selection: selection,
                        scrollTo: scrollTo,
                        loading: loading,
                        filter: filter,
                        cardwidgets: params.cardwidgets,
                    });
                })
            ),
            cards: ko.observableArray(_.filter(params.cards, function(card) {
                var nodegroup = _.find(ko.unwrap(nodegroups), function(group) {
                    return ko.unwrap(group.nodegroupid) === ko.unwrap(card.nodegroup_id);
                });
                return ko.unwrap(nodegroup.parentnodegroup_id) === ko.unwrap(params.card.nodegroup_id);
            }).map(function(card) {
                return new CardViewModel({
                    card: _.clone(card),
                    graphModel: params.graphModel,
                    tile: null,
                    resourceId: params.resourceId,
                    displayname: params.displayname,
                    handlers: params.handlers,
                    cards: params.cards,
                    tiles: params.tiles,
                    selection: selection,
                    multiselect: multiselect,
                    scrollTo: scrollTo,
                    loading: loading,
                    filter: filter,
                    provisionalTileViewModel: params.provisionalTileViewModel,
                    cardwidgets: params.cardwidgets,
                    perms: perms,
                    permsLiteral: permsLiteral,
                    parentCard: self,
                    topCards: params.topCards
                });
            })),
            hasprovisionaledits: ko.computed(function() {
                return _.filter(params.tiles, function(tile) {
                    return (params.tile ? (tile.parenttile_id === params.tile.tileid) : true)
                        && ko.unwrap(tile.nodegroup_id) === ko.unwrap(params.card.nodegroup_id)
                        && ko.unwrap(tile.provisionaledits)
                        && _.keys(ko.unwrap(tile.provisionaledits)).length !== 0;
                }).length;
            }),
            selected: ko.pureComputed({
                read: function() {
                    if (self.multiselect) {
                        return _.contains(selection(), this);
                    } else {
                        return selection() === this;
                    }
                },
                write: function(value) {
                    if (self.multiselect){
                        if (value === true){
                            if (_.contains(selection(), this) === false){
                                selection.push(this);
                            }
                        } else if (value === false) {
                            if (_.contains(selection(), this) === true) {
                                selection.remove(this);
                            }
                        }
                    } else if (value) {
                        selection(this);
                    }
                },
                owner: this
            }),
            canAdd: ko.pureComputed({
                read: function() {
                    return this.cardinality === 'n' || this.tiles().length === 0;
                },
                owner: this
            }),
            reorderTiles: function() {
                loading(true);
                var tiles = _.map(self.tiles(), function(tile) {
                    return tile.getAttributes();
                });
                $.ajax({
                    type: 'POST',
                    data: JSON.stringify({
                        tiles: tiles
                    }),
                    url: arches.urls.reorder_tiles,
                    complete: function() {
                        loading(false);
                        updateDisplayName(params.resourceId, params.displayname);
                    }
                });
            },
            reorderCards: function() {
                loading(true);
                var cards = _.map(self.cards(), function(card, i) {
                    card.model.get('sortorder')(i);
                    return {
                        id: card.model.id,
                        name: card.model.get('name')(),
                        sortorder: i
                    };
                });
                $.ajax({
                    type: 'POST',
                    data: JSON.stringify({
                        cards: cards
                    }),
                    url: arches.urls.reorder_cards,
                    complete: function() {
                        loading(false);
                    }
                });
            },
            getNewTile: function() {
                if (!this.newTile) this.newTile = new TileViewModel({
                    tile: {
                        tileid: '',
                        resourceinstance_id: ko.unwrap(params.resourceId),
                        nodegroup_id: ko.unwrap(self.model.nodegroup_id),
                        parenttile_id: self.parent ? self.parent.tileid : null,
                        data: _.reduce(self.widgets(), function(data, widget) {
                            data[widget.node_id()] = null;
                            return data;
                        }, {})
                    },
                    card: self,
                    graphModel: params.graphModel,
                    resourceId: params.resourceId,
                    displayname: params.displayname,
                    handlers: params.handlers,
                    userisreviewer: params.userisreviewer,
                    cards: params.cards,
                    tiles: params.tiles,
                    selection: selection,
                    scrollTo: scrollTo,
                    filter: filter,
                    provisionalTileViewModel: params.provisionalTileViewModel,
                    loading: loading,
                    cardwidgets: params.cardwidgets,
                });
                return this.newTile;
            },
            isFuncNode: function() {
                var appFuncDesc = false, appFuncName = false, nodegroupId = null;
                if(params.appliedFunctions && params.card) {
                    for(var i=0; i < self.appliedFunctions.length; i++) {
                        if(self.appliedFunctions[i]['function_id'] == "60000000-0000-0000-0000-000000000001") {
                            if(self.appliedFunctions[i]['config']['description']['nodegroup_id']) {
                                appFuncDesc = self.appliedFunctions[i]['config']['description']['nodegroup_id'];
                            }
                            if(self.appliedFunctions[i]['config']['name']['nodegroup_id']) {
                                appFuncName = self.appliedFunctions[i]['config']['name']['nodegroup_id'];
                            }
                            nodegroupId = params.card.nodegroup_id;
                            if(nodegroupId === appFuncDesc) {
                                return "(This card data will define the resource description.)";
                            } else if(nodegroupId === appFuncName) {
                                return "(This card data will define the resource name.)";
                            }
                        }
                    }
                }
                return false;
            }
        });

        this.selected.subscribe(function(selected) {
            if (selected) this.expanded(true);
        }, this);
        this.expanded.subscribe(function(expanded) {
            if (expanded && this.parent) this.parent.expanded(true);
        }, this);

        this.isChildSelected = ko.computed(function() {
            return isChildSelected(this);
        }, this);
        this.doesChildHaveProvisionalEdits = ko.computed(function() {
            return doesChildHaveProvisionalEdits(this);
        }, this);

        var expandParents = function(item) {
            if (item.parent) {
                item.parent.expanded(true);
                expandParents(item.parent);
            }
        };

       this.isDirty = function(){
            if(self.newTile) {
                if(self.newTile.dirty()) { return true; }
            }
            return false;
        };

        this.selectChildCards = function(value) {
            if (value !== undefined){
                this.selected(value);
            } else {
                if (this.selected() === false) {
                    value = true;
                    this.selected(true);
                } else {
                    value = false;
                    this.selected(false);
                }
            }
            if (this.cards().length > 0) {
                this.expanded(true);

                this.cards().forEach(function(childCard){
                    childCard.selectChildCards(value);
                }, this);
            }
        };

        var higlightSubscription = this.highlight.subscribe(function(highlight) {
            if (highlight) {
                this.expanded(true);
                expandParents(this);
            }
        }, this);

        this.disposables = [];
        this.disposables.push(higlightSubscription);
        this.disposables.push(widgetsSubscription);
        this.disposables.push(this.scrollTo);
        this.disposables.push(this.highlight);
        this.disposables.push(this.hasprovisionaledits);
        this.disposables.push(this.selected);
        this.disposables.push(this.canAdd);
        this.disposables.push(this.isChildSelected);
        this.disposables.push(this.doesChildHaveProvisionalEdits);
        this.disposables.push(
            this.cards.subscribe(function() {
                this.model.parseNodes.call(this.model);
            }, this)
        );
        this.disposables.push(this.model);

        this.dispose = function() {
            dispose(self);
        };

    };
    return CardViewModel;
});
<commit_msg>Fixes error when saving provisional tiles in file viewer. re #81, #82<commit_after>define([
    'jquery',
    'underscore',
    'knockout',
    'knockout-mapping',
    'models/card',
    'models/card-widget',
    'arches',
    'require',
    'uuid',
    'utils/dispose',
    'viewmodels/tile'
], function($, _, ko, koMapping, CardModel, CardWidgetModel, arches, require, uuid, dispose) {
    /**
    * A viewmodel used for generic cards
    *
    * @constructor
    * @name CardViewModel
    *
    * @param  {string} params - a configuration object
    */
    var isChildSelected = function(parent) {
        var childSelected = false;
        var children = [];
        if ('tileid' in parent) {
            children = ko.unwrap(parent.cards);
        } else if ('model' in parent) {
            children = ko.unwrap(parent.cards).concat(
                ko.unwrap(parent.tiles),
                ko.unwrap(parent.widgets)
            );
        }
        children.forEach(function(child) {
            if (child.selected && child.selected() || isChildSelected(child)) {
                childSelected = true;
            }
        });
        return childSelected;
    };

    var isDirty = function(){
        if(self.tile) {
            return true;
        }
        return false;
    };

    var doesChildHaveProvisionalEdits = function(parent) {
        var hasEdits = false;
        var childrenKey = 'tileid' in parent ? 'cards': 'tiles';
        ko.unwrap(parent[childrenKey]).forEach(function(child) {
            if (child.hasprovisionaledits && child.hasprovisionaledits() || doesChildHaveProvisionalEdits(child)) {
                hasEdits = true;
            }
        });
        return hasEdits;
    };

    var updateDisplayName = function(resourceId, displayname) {
        $.get(
            arches.urls.resource_descriptors + resourceId(),
            function(descriptors) {
                displayname(descriptors.displayname);
            }
        );
    };

    var CardViewModel = function(params) {
        var TileViewModel = require('viewmodels/tile');
        var self = this;
        var hover = params.hover || ko.observable();
        var scrollTo = params.scrollTo || ko.observable();
        var filter = params.filter || ko.observable();
        var loading = params.loading || ko.observable();
        var perms = ko.observableArray();
        var permsLiteral = ko.observableArray();
        var allowProvisionalEditRerender = ko.observable(true);
        var nodegroups = params.graphModel.get('nodegroups');
        var multiselect = params.multiselect || false;
        var isWritable = params.card.is_writable || false;
        var selection;
        var emptyConstraint = [{
            uniquetoallinstances: false,
            nodes:[],
            cardid: self.cardid,
            constraintid:  uuid.generate()
        }];

        var appliedFunctions = params.appliedFunctions;

        if (params.multiselect) {
            selection = params.selection || ko.observableArray([]);
        } else {
            selection = params.selection || ko.observable();
        }
        var nodegroup = _.find(ko.unwrap(nodegroups), function(group) {
            return ko.unwrap(group.nodegroupid) === ko.unwrap(params.card.nodegroup_id);
        });
        var cardModel = new CardModel({
            data: _.extend(params.card, {
                widgets: params.cardwidgets,
                nodes: params.graphModel.get('nodes'),
                nodegroup: nodegroup,
                constraints: params.constraints
            }),
            datatypelookup: params.graphModel.get('datatypelookup'),
        });

        var applySelectedComputed = function(widgets){
            widgets.forEach(function(widget){
                widget.parent = self;
                widget.selected = ko.pureComputed({
                    read: function() {
                        return selection() === this;
                    },
                    write: function(value) {
                        if (value) {
                            selection(this);
                        }
                    },
                    owner: widget
                });
                widget.hovered = ko.pureComputed({
                    read: function() {
                        return hover() === this;
                    },
                    write: function(value) {
                        if (value === true) {
                            hover(this);
                        }
                        if (value === null) {
                            hover(null);
                        }
                    },
                    owner: widget
                });
            });
        };

        applySelectedComputed(cardModel.widgets());

        var widgetsSubscription = cardModel.widgets.subscribe(function(widgets){
            applySelectedComputed(widgets);
        });

        _.extend(this, nodegroup, {
            isWritable: isWritable,
            model: cardModel,
            appliedFunctions: appliedFunctions,
            allowProvisionalEditRerender: allowProvisionalEditRerender,
            multiselect: params.multiselect,
            widgets: cardModel.widgets,
            parent: params.tile,
            parentCard: params.parentCard,
            expanded: ko.observable(false),
            topCards: params.topCards,
            perms: perms,
            constraints: params.constraints || emptyConstraint,
            permsLiteral: permsLiteral,
            scrollTo: ko.pureComputed(function() {
                return scrollTo() === this;
            }, this),
            fullyProvisional: ko.pureComputed(function(){
                var res;
                var provisionalindex;
                var summary = _.map(this.tiles(), function(tile){
                    var dataEmpty = _.keys(koMapping.toJS(tile.data)).length === 0;
                    if (ko.unwrap(tile.provisionaledits) !== null && dataEmpty) {
                        return 2;
                    } else if (tile.provisionaledits() !== null && !dataEmpty) {
                        return 1;
                    } else {
                        return 0;
                    }
                });
                provisionalindex = _.reduce(summary, function(a, b){return a + b;});
                if (provisionalindex > 0) {
                    if (_.every(summary, function(val){return val === 2;})) {
                        res = 'fullyprovisional';
                    }
                    else {
                        res = 'provisional';
                    }
                }
                return res;
            }, this),
            highlight: ko.computed(function() {
                var filterText = filter();
                if (!filterText) {
                    return false;
                }
                filterText = filterText.toLowerCase();
                if (params.card.name.toLowerCase().indexOf(filterText) > -1) {
                    return true;
                }
            }, this),
            tiles: ko.observableArray(
                _.filter(params.tiles, function(tile) {
                    return (
                        params.tile ? (tile.parenttile_id === params.tile.tileid) : true
                    ) && ko.unwrap(tile.nodegroup_id) === ko.unwrap(params.card.nodegroup_id);
                }).map(function(tile) {
                    return new TileViewModel({
                        tile: tile,
                        card: self,
                        graphModel: params.graphModel,
                        resourceId: params.resourceId,
                        displayname: params.displayname,
                        handlers: params.handlers,
                        userisreviewer: params.userisreviewer,
                        cards: params.cards,
                        tiles: params.tiles,
                        provisionalTileViewModel: params.provisionalTileViewModel,
                        selection: selection,
                        scrollTo: scrollTo,
                        loading: loading,
                        filter: filter,
                        cardwidgets: params.cardwidgets,
                    });
                })
            ),
            cards: ko.observableArray(_.filter(params.cards, function(card) {
                var nodegroup = _.find(ko.unwrap(nodegroups), function(group) {
                    return ko.unwrap(group.nodegroupid) === ko.unwrap(card.nodegroup_id);
                });
                return ko.unwrap(nodegroup.parentnodegroup_id) === ko.unwrap(params.card.nodegroup_id);
            }).map(function(card) {
                return new CardViewModel({
                    card: _.clone(card),
                    graphModel: params.graphModel,
                    tile: null,
                    resourceId: params.resourceId,
                    displayname: params.displayname,
                    handlers: params.handlers,
                    cards: params.cards,
                    tiles: params.tiles,
                    selection: selection,
                    multiselect: multiselect,
                    scrollTo: scrollTo,
                    loading: loading,
                    filter: filter,
                    provisionalTileViewModel: params.provisionalTileViewModel,
                    cardwidgets: params.cardwidgets,
                    perms: perms,
                    permsLiteral: permsLiteral,
                    parentCard: self,
                    topCards: params.topCards
                });
            })),
            hasprovisionaledits: ko.computed(function() {
                return _.filter(params.tiles, function(tile) {
                    return (params.tile ? (tile.parenttile_id === params.tile.tileid) : true)
                        && ko.unwrap(tile.nodegroup_id) === ko.unwrap(params.card.nodegroup_id)
                        && ko.unwrap(tile.provisionaledits)
                        && _.keys(ko.unwrap(tile.provisionaledits)).length !== 0;
                }).length;
            }),
            selected: ko.pureComputed({
                read: function() {
                    if (self.multiselect) {
                        return _.contains(selection(), this);
                    } else {
                        return selection() === this;
                    }
                },
                write: function(value) {
                    if (self.multiselect){
                        if (value === true){
                            if (_.contains(selection(), this) === false){
                                selection.push(this);
                            }
                        } else if (value === false) {
                            if (_.contains(selection(), this) === true) {
                                selection.remove(this);
                            }
                        }
                    } else if (value) {
                        selection(this);
                    }
                },
                owner: this
            }),
            canAdd: ko.pureComputed({
                read: function() {
                    return this.cardinality === 'n' || this.tiles().length === 0;
                },
                owner: this
            }),
            reorderTiles: function() {
                loading(true);
                var tiles = _.map(self.tiles(), function(tile) {
                    return tile.getAttributes();
                });
                $.ajax({
                    type: 'POST',
                    data: JSON.stringify({
                        tiles: tiles
                    }),
                    url: arches.urls.reorder_tiles,
                    complete: function() {
                        loading(false);
                        updateDisplayName(params.resourceId, params.displayname);
                    }
                });
            },
            reorderCards: function() {
                loading(true);
                var cards = _.map(self.cards(), function(card, i) {
                    card.model.get('sortorder')(i);
                    return {
                        id: card.model.id,
                        name: card.model.get('name')(),
                        sortorder: i
                    };
                });
                $.ajax({
                    type: 'POST',
                    data: JSON.stringify({
                        cards: cards
                    }),
                    url: arches.urls.reorder_cards,
                    complete: function() {
                        loading(false);
                    }
                });
            },
            getNewTile: function() {
                if (!this.newTile) this.newTile = new TileViewModel({
                    tile: {
                        tileid: '',
                        resourceinstance_id: ko.unwrap(params.resourceId),
                        nodegroup_id: ko.unwrap(self.model.nodegroup_id),
                        parenttile_id: self.parent ? self.parent.tileid : null,
                        data: _.reduce(self.widgets(), function(data, widget) {
                            data[widget.node_id()] = null;
                            return data;
                        }, {})
                    },
                    card: self,
                    graphModel: params.graphModel,
                    resourceId: params.resourceId,
                    displayname: params.displayname,
                    handlers: params.handlers,
                    userisreviewer: params.userisreviewer,
                    cards: params.cards,
                    tiles: params.tiles,
                    selection: selection,
                    scrollTo: scrollTo,
                    filter: filter,
                    provisionalTileViewModel: params.provisionalTileViewModel,
                    loading: loading,
                    cardwidgets: params.cardwidgets,
                });
                return this.newTile;
            },
            isFuncNode: function() {
                var appFuncDesc = false, appFuncName = false, nodegroupId = null;
                if(params.appliedFunctions && params.card) {
                    for(var i=0; i < self.appliedFunctions.length; i++) {
                        if(self.appliedFunctions[i]['function_id'] == "60000000-0000-0000-0000-000000000001") {
                            if(self.appliedFunctions[i]['config']['description']['nodegroup_id']) {
                                appFuncDesc = self.appliedFunctions[i]['config']['description']['nodegroup_id'];
                            }
                            if(self.appliedFunctions[i]['config']['name']['nodegroup_id']) {
                                appFuncName = self.appliedFunctions[i]['config']['name']['nodegroup_id'];
                            }
                            nodegroupId = params.card.nodegroup_id;
                            if(nodegroupId === appFuncDesc) {
                                return "(This card data will define the resource description.)";
                            } else if(nodegroupId === appFuncName) {
                                return "(This card data will define the resource name.)";
                            }
                        }
                    }
                }
                return false;
            }
        });

        this.selected.subscribe(function(selected) {
            if (selected) this.expanded(true);
        }, this);
        this.expanded.subscribe(function(expanded) {
            if (expanded && this.parent) this.parent.expanded(true);
        }, this);

        this.isChildSelected = ko.computed(function() {
            return isChildSelected(this);
        }, this);
        this.doesChildHaveProvisionalEdits = ko.computed(function() {
            return doesChildHaveProvisionalEdits(this);
        }, this);

        var expandParents = function(item) {
            if (item.parent) {
                item.parent.expanded(true);
                expandParents(item.parent);
            }
        };

       this.isDirty = function(){
            if(self.newTile) {
                if(self.newTile.dirty()) { return true; }
            }
            return false;
        };

        this.selectChildCards = function(value) {
            if (value !== undefined){
                this.selected(value);
            } else {
                if (this.selected() === false) {
                    value = true;
                    this.selected(true);
                } else {
                    value = false;
                    this.selected(false);
                }
            }
            if (this.cards().length > 0) {
                this.expanded(true);

                this.cards().forEach(function(childCard){
                    childCard.selectChildCards(value);
                }, this);
            }
        };

        var higlightSubscription = this.highlight.subscribe(function(highlight) {
            if (highlight) {
                this.expanded(true);
                expandParents(this);
            }
        }, this);

        this.disposables = [];
        this.disposables.push(higlightSubscription);
        this.disposables.push(widgetsSubscription);
        this.disposables.push(this.scrollTo);
        this.disposables.push(this.highlight);
        this.disposables.push(this.hasprovisionaledits);
        this.disposables.push(this.selected);
        this.disposables.push(this.canAdd);
        this.disposables.push(this.isChildSelected);
        this.disposables.push(this.doesChildHaveProvisionalEdits);
        this.disposables.push(
            this.cards.subscribe(function() {
                this.model.parseNodes.call(this.model);
            }, this)
        );
        this.disposables.push(this.model);

        this.dispose = function() {
            dispose(self);
        };

    };
    return CardViewModel;
});
<|endoftext|>