<commit_before>;(function($$){ 'use strict';

  // default layout options
  var defaults = {
    animate: true, // whether to show the layout as it's running
    refresh: 1, // number of ticks per frame; higher is faster but more jerky
    maxSimulationTime: 4000, // max length in ms to run the layout
    ungrabifyWhileSimulating: false, // so you can't drag nodes during layout
    fit: true, // on every layout reposition of nodes, fit the viewport
    padding: 30, // padding around the simulation
    boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }

    // layout event callbacks
    ready: function(){}, // on layoutready
    stop: function(){}, // on layoutstop

    // positioning options
    randomize: false, // use random node positions at beginning of layout
    avoidOverlap: true, // if true, prevents overlap of node bounding boxes
    handleDisconnected: true, // if true, avoids disconnected components from overlapping
    nodeSpacing: function( node ){ return 10; }, // extra spacing around nodes
    flow: undefined, // use DAG/tree flow layout if specified, e.g. { axis: 'y', minSeparation: 30 }
    alignment: undefined, // relative alignment constraints on nodes, e.g. function( node ){ return { x: 0, y: 1 } }

    // different methods of specifying edge length
    // each can be a constant numerical value or a function like `function( edge ){ return 2; }`
    edgeLength: undefined, // sets edge length directly in simulation
    edgeSymDiffLength: undefined, // symmetric diff edge length in simulation
    edgeJaccardLength: undefined, // jaccard edge length in simulation

    // iterations of cola algorithm; uses default values on undefined
    unconstrIter: undefined, // unconstrained initial layout iterations
    userConstIter: undefined, // initial layout iterations with user-specified constraints
    allConstIter: undefined, // initial layout iterations with all constraints including non-overlap

    // infinite layout options
    infinite: false // overrides all other options for a forces-all-the-time mode
  };

  // constructor
  // options : object containing layout options
  function ColaLayout( options ){
    this.options = $$.util.extend(true, {}, defaults, options);
  }

  // runs the layout
  ColaLayout.prototype.run = function(){
    var layout = this;
    var options = this.options;

    layout.manuallyStopped = false;

    $$.util.require('cola', function(cola){

      var cy = options.cy; // cy is automatically populated for us in the constructor
      var eles = options.eles;
      var nodes = eles.nodes();
      var edges = eles.edges();
      var ready = false;

      var bb = $$.util.makeBoundingBox( options.boundingBox ? options.boundingBox : {
        x1: 0, y1: 0, w: cy.width(), h: cy.height()
      } );

      var getOptVal = function( val, ele ){
        if( $$.is.fn(val) ){
          var fn = val;
          return fn.apply( ele, [ ele ] );
        } else {
          return val;
        }
      };

      var updateNodePositions = function(){
        var x = { min: Infinity, max: -Infinity };
        var y = { min: Infinity, max: -Infinity };

        for( var i = 0; i < nodes.length; i++ ){
          var node = nodes[i];
          var scratch = node._private.scratch.cola;

          x.min = Math.min( x.min, scratch.x || 0 );
          x.max = Math.max( x.max, scratch.x || 0 );

          y.min = Math.min( y.min, scratch.y || 0 );
          y.max = Math.max( y.max, scratch.y || 0 );

          // update node dims
          if( !scratch.updatedDims ){
            var nbb = node.boundingBox();
            var padding = getOptVal( options.nodeSpacing, node );

            scratch.width = nbb.w + 2*padding;
            scratch.height = nbb.h + 2*padding;
          }
        }

        nodes.positions(function(i, node){
          var scratch = node._private.scratch.cola;
          var retPos;

          if( !node.grabbed() && !node.isParent() ){
            retPos = {
              x: bb.x1 + scratch.x - x.min,
              y: bb.y1 + scratch.y - y.min
            };

            if( !$$.is.number(retPos.x) || !$$.is.number(retPos.y) ){
              retPos = undefined;
            }
          }

          return retPos;
        });

        nodes.updateCompoundBounds(); // because the way this layout sets positions is buggy for some reason; ref #878

        if( !ready ){
          onReady();
          ready = true;
        }

        if( options.fit ){
          cy.fit( options.padding );
        }
      };

      var onDone = function(){
        if( options.ungrabifyWhileSimulating ){
          grabbableNodes.grabify();
        }

        nodes.off('grab free position', grabHandler);
        nodes.off('lock unlock', lockHandler);

        // trigger layoutstop when the layout stops (e.g. finishes)
        layout.one('layoutstop', options.stop);
        layout.trigger({ type: 'layoutstop', layout: layout });
      };

      var onReady = function(){
        // trigger layoutready when each node has had its position set at least once
        layout.one('layoutready', options.ready);
        layout.trigger({ type: 'layoutready', layout: layout });
      };

      var ticksPerFrame = options.refresh;
      var tickSkip = 1; // frames until a tick; used to slow down sim for debugging

      if( options.refresh < 0 ){
        tickSkip = Math.abs( options.refresh );
        ticksPerFrame = 1;
      } else {
        ticksPerFrame = Math.max( 1, ticksPerFrame ); // at least 1
      }

      var adaptor = layout.adaptor = cola.adaptor({
        trigger: function( e ){ // on sim event
          var TICK = cola.EventType ? cola.EventType.tick : null;
          var END = cola.EventType ? cola.EventType.end : null;

          switch( e.type ){
            case 'tick':
            case TICK:
              if( options.animate ){
                updateNodePositions();
              }
              break;

            case 'end':
            case END:
              updateNodePositions();
              if( !options.infinite ){ onDone(); }
              break;
          }
        },

        kick: function(){ // kick off the simulation
          var skip = 0;

          var inftick = function(){
            if( layout.manuallyStopped ){
              onDone();

              return true;
            }

            var ret = adaptor.tick();

            if( ret && options.infinite ){ // resume layout if done
              adaptor.resume(); // resume => new kick
            }

            return ret; // allow regular finish b/c of new kick
          };

          var multitick = function(){ // multiple ticks in a row
            var ret;

            // skip ticks to slow down layout for debugging
            // var thisSkip = skip;
            // skip = (skip + 1) % tickSkip;
            // if( thisSkip !== 0 ){
            //   return false;
            // }

            for( var i = 0; i < ticksPerFrame && !ret; i++ ){
              ret = ret || inftick(); // pick up true ret vals => sim done
            }

            return ret;
          };

          if( options.animate ){
            var frame = function(){
              if( multitick() ){ return; }

              $$.util.requestAnimationFrame( frame );
            };

            $$.util.requestAnimationFrame( frame );
          } else {
            while( !inftick() ){}
          }
        },

        on: function( type, listener ){}, // dummy; not needed

        drag: function(){} // not needed for our case
      });
      layout.adaptor = adaptor;

      // if set no grabbing during layout
      var grabbableNodes = nodes.filter(':grabbable');
      if( options.ungrabifyWhileSimulating ){
        grabbableNodes.ungrabify();
      }

      // handle node dragging
      var grabHandler;
      nodes.on('grab free position', grabHandler = function(e){
        var node = this;
        var scrCola = node._private.scratch.cola;
        var pos = node._private.position;

        if( node.grabbed() ){
          scrCola.x = pos.x - bb.x1;
          scrCola.y = pos.y - bb.y1;

          adaptor.dragstart( scrCola );
        } else if( $$.is.number(scrCola.x) && $$.is.number(scrCola.y) ){
          pos.x = scrCola.x + bb.x1;
          pos.y = scrCola.y + bb.y1;
        }

        switch( e.type ){
          case 'grab':
            adaptor.dragstart( scrCola );
            adaptor.resume();
            break;
          case 'free':
            adaptor.dragend( scrCola );
            break;
        }

      });

      var lockHandler;
      nodes.on('lock unlock', lockHandler = function(e){
        var node = this;
        var scrCola = node._private.scratch.cola;

        if( node.locked() ){
          adaptor.dragstart( scrCola );
        } else {
          adaptor.dragend( scrCola );
        }
      });

      var nonparentNodes = nodes.stdFilter(function( node ){
        return !node.isParent();
      });

      // add nodes to cola
      adaptor.nodes( nonparentNodes.map(function( node, i ){
        var padding = getOptVal( options.nodeSpacing, node );
        var pos = node.position();
        var nbb = node.boundingBox();

        var struct = node._private.scratch.cola = {
          x: options.randomize || pos.x === undefined ? Math.round( Math.random() * bb.w ) : pos.x,
          y: options.randomize || pos.y === undefined ? Math.round( Math.random() * bb.h ) : pos.y,
          width: nbb.w + 2*padding,
          height: nbb.h + 2*padding,
          index: i
        };

        console.log(struct)

        return struct;
      }) );

      if( options.alignment ){ // then set alignment constraints

        var offsetsX = [];
        var offsetsY = [];

        nonparentNodes.forEach(function( node ){
          var align = getOptVal( options.alignment, node );
          var scrCola = node._private.scratch.cola;
          var index = scrCola.index;

          if( !align ){ return; }

          if( align.x != null ){
            offsetsX.push({
              node: index,
              offset: align.x
            });
          }

          if( align.y != null ){
            offsetsY.push({
              node: index,
              offset: align.y
            });
          }
        });

        // add alignment constraints on nodes
        var constraints = [];

        if( offsetsX.length > 0 ){
          constraints.push({
            type: 'alignment',
            axis: 'x',
            offsets: offsetsX
          });
        }

        if( offsetsY.length > 0 ){
          constraints.push({
            type: 'alignment',
            axis: 'y',
            offsets: offsetsY
          });
        }

        adaptor.constraints( constraints );

      }

      // add compound nodes to cola
      adaptor.groups( nodes.stdFilter(function( node ){
        return node.isParent();
      }).map(function( node, i ){ // add basic group incl leaf nodes
        var style = node._private.style;

        var optPadding = getOptVal( options.nodeSpacing, node );

        var pleft = style['padding-left'].pxValue + optPadding;
        var pright = style['padding-right'].pxValue + optPadding;
        var ptop = style['padding-top'].pxValue + optPadding;
        var pbottom = style['padding-bottom'].pxValue + optPadding;

        node._private.scratch.cola = {
          index: i,

          padding: Math.max( pleft, pright, ptop, pbottom ),

          leaves: node.descendants().stdFilter(function( child ){
            return !child.isParent();
          }).map(function( child ){
            return child[0]._private.scratch.cola.index;
          })
        };

        return node;
      }).map(function( node ){ // add subgroups
        node._private.scratch.cola.groups = node.descendants().stdFilter(function( child ){
          return child.isParent();
        }).map(function( child ){
          return child._private.scratch.cola.index;
        });

        return node._private.scratch.cola;
      }) );

      // get the edge length setting mechanism
      var length;
      var lengthFnName;
      if( options.edgeLength != null ){
        length = options.edgeLength;
        lengthFnName = 'linkDistance';
      } else if( options.edgeSymDiffLength != null ){
        length = options.edgeSymDiffLength;
        lengthFnName = 'symmetricDiffLinkLengths';
      } else if( options.edgeJaccardLength != null ){
        length = options.edgeJaccardLength;
        lengthFnName = 'jaccardLinkLengths';
      } else {
        length = 100;
        lengthFnName = 'linkDistance';
      }

      var lengthGetter = function( link ){
        return link.calcLength;
      };

      // add the edges to cola
      adaptor.links( edges.stdFilter(function( edge ){
        return !edge.source().isParent() && !edge.target().isParent();
      }).map(function( edge, i ){
        var c = edge._private.scratch.cola = {
          source: edge.source()[0]._private.scratch.cola.index,
          target: edge.target()[0]._private.scratch.cola.index
        };

        if( length != null ){
          c.calcLength = getOptVal( length, edge );
        }

        return c;
      }) );

      adaptor.size([ bb.w, bb.h ]);

      if( length != null ){
        adaptor[ lengthFnName ]( lengthGetter );
      }

      // set the flow of cola
      if( options.flow ){
        var flow;
        var defAxis = 'y';
        var defMinSep = 50;

        if( $$.is.string(options.flow) ){
          flow = {
            axis: options.flow,
            minSeparation: defMinSep
          };
        } else if( $$.is.number(options.flow) ){
          flow = {
            axis: defAxis,
            minSeparation: options.flow
          };
        } else if( $$.is.plainObject(options.flow) ){
          flow = options.flow;

          flow.axis = flow.axis || defAxis;
          flow.minSeparation = flow.minSeparation != null ? flow.minSeparation : defMinSep;
        } else { // e.g. options.flow: true
          flow = {
            axis: defAxis,
            minSeparation: defMinSep
          };
        }

        adaptor.flowLayout( flow.axis , flow.minSeparation );
      }

      layout.trigger({ type: 'layoutstart', layout: layout });

      adaptor
        .avoidOverlaps( options.avoidOverlap )
        .handleDisconnected( options.handleDisconnected )
        .start( options.unconstrIter, options.userConstIter, options.allConstIter)
      ;

      if( !options.infinite ){
        setTimeout(function(){
          if( !layout.manuallyStopped ){
            adaptor.stop();
          }
        }, options.maxSimulationTime);
      }

    }); // require

    return this; // chaining
  };

  // called on continuous layouts to stop them before they finish
  ColaLayout.prototype.stop = function(){
    if( this.adaptor ){
      this.manuallyStopped = true;
      this.adaptor.stop();
    }

    return this; // chaining
  };

  // register the layout
  $$('layout', 'cola', ColaLayout);

})(cytoscape);
<commit_msg>remove console.log() for #1013<commit_after>;(function($$){ 'use strict';

  // default layout options
  var defaults = {
    animate: true, // whether to show the layout as it's running
    refresh: 1, // number of ticks per frame; higher is faster but more jerky
    maxSimulationTime: 4000, // max length in ms to run the layout
    ungrabifyWhileSimulating: false, // so you can't drag nodes during layout
    fit: true, // on every layout reposition of nodes, fit the viewport
    padding: 30, // padding around the simulation
    boundingBox: undefined, // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h }

    // layout event callbacks
    ready: function(){}, // on layoutready
    stop: function(){}, // on layoutstop

    // positioning options
    randomize: false, // use random node positions at beginning of layout
    avoidOverlap: true, // if true, prevents overlap of node bounding boxes
    handleDisconnected: true, // if true, avoids disconnected components from overlapping
    nodeSpacing: function( node ){ return 10; }, // extra spacing around nodes
    flow: undefined, // use DAG/tree flow layout if specified, e.g. { axis: 'y', minSeparation: 30 }
    alignment: undefined, // relative alignment constraints on nodes, e.g. function( node ){ return { x: 0, y: 1 } }

    // different methods of specifying edge length
    // each can be a constant numerical value or a function like `function( edge ){ return 2; }`
    edgeLength: undefined, // sets edge length directly in simulation
    edgeSymDiffLength: undefined, // symmetric diff edge length in simulation
    edgeJaccardLength: undefined, // jaccard edge length in simulation

    // iterations of cola algorithm; uses default values on undefined
    unconstrIter: undefined, // unconstrained initial layout iterations
    userConstIter: undefined, // initial layout iterations with user-specified constraints
    allConstIter: undefined, // initial layout iterations with all constraints including non-overlap

    // infinite layout options
    infinite: false // overrides all other options for a forces-all-the-time mode
  };

  // constructor
  // options : object containing layout options
  function ColaLayout( options ){
    this.options = $$.util.extend(true, {}, defaults, options);
  }

  // runs the layout
  ColaLayout.prototype.run = function(){
    var layout = this;
    var options = this.options;

    layout.manuallyStopped = false;

    $$.util.require('cola', function(cola){

      var cy = options.cy; // cy is automatically populated for us in the constructor
      var eles = options.eles;
      var nodes = eles.nodes();
      var edges = eles.edges();
      var ready = false;

      var bb = $$.util.makeBoundingBox( options.boundingBox ? options.boundingBox : {
        x1: 0, y1: 0, w: cy.width(), h: cy.height()
      } );

      var getOptVal = function( val, ele ){
        if( $$.is.fn(val) ){
          var fn = val;
          return fn.apply( ele, [ ele ] );
        } else {
          return val;
        }
      };

      var updateNodePositions = function(){
        var x = { min: Infinity, max: -Infinity };
        var y = { min: Infinity, max: -Infinity };

        for( var i = 0; i < nodes.length; i++ ){
          var node = nodes[i];
          var scratch = node._private.scratch.cola;

          x.min = Math.min( x.min, scratch.x || 0 );
          x.max = Math.max( x.max, scratch.x || 0 );

          y.min = Math.min( y.min, scratch.y || 0 );
          y.max = Math.max( y.max, scratch.y || 0 );

          // update node dims
          if( !scratch.updatedDims ){
            var nbb = node.boundingBox();
            var padding = getOptVal( options.nodeSpacing, node );

            scratch.width = nbb.w + 2*padding;
            scratch.height = nbb.h + 2*padding;
          }
        }

        nodes.positions(function(i, node){
          var scratch = node._private.scratch.cola;
          var retPos;

          if( !node.grabbed() && !node.isParent() ){
            retPos = {
              x: bb.x1 + scratch.x - x.min,
              y: bb.y1 + scratch.y - y.min
            };

            if( !$$.is.number(retPos.x) || !$$.is.number(retPos.y) ){
              retPos = undefined;
            }
          }

          return retPos;
        });

        nodes.updateCompoundBounds(); // because the way this layout sets positions is buggy for some reason; ref #878

        if( !ready ){
          onReady();
          ready = true;
        }

        if( options.fit ){
          cy.fit( options.padding );
        }
      };

      var onDone = function(){
        if( options.ungrabifyWhileSimulating ){
          grabbableNodes.grabify();
        }

        nodes.off('grab free position', grabHandler);
        nodes.off('lock unlock', lockHandler);

        // trigger layoutstop when the layout stops (e.g. finishes)
        layout.one('layoutstop', options.stop);
        layout.trigger({ type: 'layoutstop', layout: layout });
      };

      var onReady = function(){
        // trigger layoutready when each node has had its position set at least once
        layout.one('layoutready', options.ready);
        layout.trigger({ type: 'layoutready', layout: layout });
      };

      var ticksPerFrame = options.refresh;
      var tickSkip = 1; // frames until a tick; used to slow down sim for debugging

      if( options.refresh < 0 ){
        tickSkip = Math.abs( options.refresh );
        ticksPerFrame = 1;
      } else {
        ticksPerFrame = Math.max( 1, ticksPerFrame ); // at least 1
      }

      var adaptor = layout.adaptor = cola.adaptor({
        trigger: function( e ){ // on sim event
          var TICK = cola.EventType ? cola.EventType.tick : null;
          var END = cola.EventType ? cola.EventType.end : null;

          switch( e.type ){
            case 'tick':
            case TICK:
              if( options.animate ){
                updateNodePositions();
              }
              break;

            case 'end':
            case END:
              updateNodePositions();
              if( !options.infinite ){ onDone(); }
              break;
          }
        },

        kick: function(){ // kick off the simulation
          var skip = 0;

          var inftick = function(){
            if( layout.manuallyStopped ){
              onDone();

              return true;
            }

            var ret = adaptor.tick();

            if( ret && options.infinite ){ // resume layout if done
              adaptor.resume(); // resume => new kick
            }

            return ret; // allow regular finish b/c of new kick
          };

          var multitick = function(){ // multiple ticks in a row
            var ret;

            // skip ticks to slow down layout for debugging
            // var thisSkip = skip;
            // skip = (skip + 1) % tickSkip;
            // if( thisSkip !== 0 ){
            //   return false;
            // }

            for( var i = 0; i < ticksPerFrame && !ret; i++ ){
              ret = ret || inftick(); // pick up true ret vals => sim done
            }

            return ret;
          };

          if( options.animate ){
            var frame = function(){
              if( multitick() ){ return; }

              $$.util.requestAnimationFrame( frame );
            };

            $$.util.requestAnimationFrame( frame );
          } else {
            while( !inftick() ){}
          }
        },

        on: function( type, listener ){}, // dummy; not needed

        drag: function(){} // not needed for our case
      });
      layout.adaptor = adaptor;

      // if set no grabbing during layout
      var grabbableNodes = nodes.filter(':grabbable');
      if( options.ungrabifyWhileSimulating ){
        grabbableNodes.ungrabify();
      }

      // handle node dragging
      var grabHandler;
      nodes.on('grab free position', grabHandler = function(e){
        var node = this;
        var scrCola = node._private.scratch.cola;
        var pos = node._private.position;

        if( node.grabbed() ){
          scrCola.x = pos.x - bb.x1;
          scrCola.y = pos.y - bb.y1;

          adaptor.dragstart( scrCola );
        } else if( $$.is.number(scrCola.x) && $$.is.number(scrCola.y) ){
          pos.x = scrCola.x + bb.x1;
          pos.y = scrCola.y + bb.y1;
        }

        switch( e.type ){
          case 'grab':
            adaptor.dragstart( scrCola );
            adaptor.resume();
            break;
          case 'free':
            adaptor.dragend( scrCola );
            break;
        }

      });

      var lockHandler;
      nodes.on('lock unlock', lockHandler = function(e){
        var node = this;
        var scrCola = node._private.scratch.cola;

        if( node.locked() ){
          adaptor.dragstart( scrCola );
        } else {
          adaptor.dragend( scrCola );
        }
      });

      var nonparentNodes = nodes.stdFilter(function( node ){
        return !node.isParent();
      });

      // add nodes to cola
      adaptor.nodes( nonparentNodes.map(function( node, i ){
        var padding = getOptVal( options.nodeSpacing, node );
        var pos = node.position();
        var nbb = node.boundingBox();

        var struct = node._private.scratch.cola = {
          x: options.randomize || pos.x === undefined ? Math.round( Math.random() * bb.w ) : pos.x,
          y: options.randomize || pos.y === undefined ? Math.round( Math.random() * bb.h ) : pos.y,
          width: nbb.w + 2*padding,
          height: nbb.h + 2*padding,
          index: i
        };

        return struct;
      }) );

      if( options.alignment ){ // then set alignment constraints

        var offsetsX = [];
        var offsetsY = [];

        nonparentNodes.forEach(function( node ){
          var align = getOptVal( options.alignment, node );
          var scrCola = node._private.scratch.cola;
          var index = scrCola.index;

          if( !align ){ return; }

          if( align.x != null ){
            offsetsX.push({
              node: index,
              offset: align.x
            });
          }

          if( align.y != null ){
            offsetsY.push({
              node: index,
              offset: align.y
            });
          }
        });

        // add alignment constraints on nodes
        var constraints = [];

        if( offsetsX.length > 0 ){
          constraints.push({
            type: 'alignment',
            axis: 'x',
            offsets: offsetsX
          });
        }

        if( offsetsY.length > 0 ){
          constraints.push({
            type: 'alignment',
            axis: 'y',
            offsets: offsetsY
          });
        }

        adaptor.constraints( constraints );

      }

      // add compound nodes to cola
      adaptor.groups( nodes.stdFilter(function( node ){
        return node.isParent();
      }).map(function( node, i ){ // add basic group incl leaf nodes
        var style = node._private.style;

        var optPadding = getOptVal( options.nodeSpacing, node );

        var pleft = style['padding-left'].pxValue + optPadding;
        var pright = style['padding-right'].pxValue + optPadding;
        var ptop = style['padding-top'].pxValue + optPadding;
        var pbottom = style['padding-bottom'].pxValue + optPadding;

        node._private.scratch.cola = {
          index: i,

          padding: Math.max( pleft, pright, ptop, pbottom ),

          leaves: node.descendants().stdFilter(function( child ){
            return !child.isParent();
          }).map(function( child ){
            return child[0]._private.scratch.cola.index;
          })
        };

        return node;
      }).map(function( node ){ // add subgroups
        node._private.scratch.cola.groups = node.descendants().stdFilter(function( child ){
          return child.isParent();
        }).map(function( child ){
          return child._private.scratch.cola.index;
        });

        return node._private.scratch.cola;
      }) );

      // get the edge length setting mechanism
      var length;
      var lengthFnName;
      if( options.edgeLength != null ){
        length = options.edgeLength;
        lengthFnName = 'linkDistance';
      } else if( options.edgeSymDiffLength != null ){
        length = options.edgeSymDiffLength;
        lengthFnName = 'symmetricDiffLinkLengths';
      } else if( options.edgeJaccardLength != null ){
        length = options.edgeJaccardLength;
        lengthFnName = 'jaccardLinkLengths';
      } else {
        length = 100;
        lengthFnName = 'linkDistance';
      }

      var lengthGetter = function( link ){
        return link.calcLength;
      };

      // add the edges to cola
      adaptor.links( edges.stdFilter(function( edge ){
        return !edge.source().isParent() && !edge.target().isParent();
      }).map(function( edge, i ){
        var c = edge._private.scratch.cola = {
          source: edge.source()[0]._private.scratch.cola.index,
          target: edge.target()[0]._private.scratch.cola.index
        };

        if( length != null ){
          c.calcLength = getOptVal( length, edge );
        }

        return c;
      }) );

      adaptor.size([ bb.w, bb.h ]);

      if( length != null ){
        adaptor[ lengthFnName ]( lengthGetter );
      }

      // set the flow of cola
      if( options.flow ){
        var flow;
        var defAxis = 'y';
        var defMinSep = 50;

        if( $$.is.string(options.flow) ){
          flow = {
            axis: options.flow,
            minSeparation: defMinSep
          };
        } else if( $$.is.number(options.flow) ){
          flow = {
            axis: defAxis,
            minSeparation: options.flow
          };
        } else if( $$.is.plainObject(options.flow) ){
          flow = options.flow;

          flow.axis = flow.axis || defAxis;
          flow.minSeparation = flow.minSeparation != null ? flow.minSeparation : defMinSep;
        } else { // e.g. options.flow: true
          flow = {
            axis: defAxis,
            minSeparation: defMinSep
          };
        }

        adaptor.flowLayout( flow.axis , flow.minSeparation );
      }

      layout.trigger({ type: 'layoutstart', layout: layout });

      adaptor
        .avoidOverlaps( options.avoidOverlap )
        .handleDisconnected( options.handleDisconnected )
        .start( options.unconstrIter, options.userConstIter, options.allConstIter)
      ;

      if( !options.infinite ){
        setTimeout(function(){
          if( !layout.manuallyStopped ){
            adaptor.stop();
          }
        }, options.maxSimulationTime);
      }

    }); // require

    return this; // chaining
  };

  // called on continuous layouts to stop them before they finish
  ColaLayout.prototype.stop = function(){
    if( this.adaptor ){
      this.manuallyStopped = true;
      this.adaptor.stop();
    }

    return this; // chaining
  };

  // register the layout
  $$('layout', 'cola', ColaLayout);

})(cytoscape);
<|endoftext|>


<commit_before>const CODE_RED = '#E58';
const CODE_YELLOW = '#EE8';
const CODE_GREEN = '#AE4';
const CODE_BLUE = '#6CE';
const CODE_PURPLE = '#C6E';
const CODE_GRAY = '#999';

function highlightJSCode(match) {
  var replaced = ['', match, ''];

  if (!isNaN(parseInt(match))) {
    replaced[1] = CODE_PURPLE;
  }
  else if (/\/\//.test(match)) {
    replaced[1] = CODE_GRAY;
  }
  else if (/('.+'|".+")/.test(match)) {
    replaced[1] = CODE_YELLOW;
  }
  else if (/[!<>\&|+\-*/=]|if|new|else|case|break|switch|default|return/.test(match)) {
    replaced[1] = CODE_RED;
  }
  else {
    switch (match) {
      case 'function':
      case 'document':
      case 'window':
        replaced[1] = CODE_BLUE + 'font-style:italic';
        break;
      default:
        replaced[1] = CODE_BLUE;
        break;
    }
  }

  return replaced.join('');
}

function highlightHTMLCode(original) {
  var highlighted = [];
  var word = '';
  var flags = {
    tag: false,
    tagName: false,
    doubleQuotes: false
  };

  let length = original.length;
  for (let i = 0; i < length; i++) {
    if (!flags.tag) {
      if (original.slice(i, i + 4) == '<') {
        if (word) {
          highlighted.push(word);
        }
        if (original[i + 4] == '/') {
          highlighted.push('</');
          i += 5;
        }
        else {
          highlighted.push('<');
          i += 4;
        }
        word = '';
        flags.tag = true;
        flags.tagName = true;
      }
      word += original[i];
    }
    else {
      if (flags.tagName) {
        if (!/[a-zA-Z]/.test(original[i])) {
          if (original[i] == ' ') {
            highlighted.push(word + ' ');
            i++;
          }
          else {
            highlighted.push(word + '');
          }
          word = '';
          flags.tagName = false;
        }
      }
      else {
        if (!flags.doubleQuotes) {
          if (original[i] == '"') {
            flags.doubleQuotes = true;
            highlighted.push('="');
            word = '';
            i++;
          }
          else if (original[i] == '=') {
            highlighted.push('');
            highlighted.push(word);
            highlighted.push('');
            word = '';
          }
        }
        else {
          if (original[i] == '"') {
            flags.doubleQuotes = false;
            highlighted.push('');
            highlighted.push(word);
            highlighted.push('"');
            word = '';
            i++;
          }
        }
      }

      if (original.slice(i, i + 4) == '>') {
        flags.tag = false;
        highlighted.push('>');
        i += 3;
      }
      else {
        word += original[i];
      }
    }
  }

  return highlighted.join('');
}

ready(function() {
  var jsRegex = /(\/\/.+(\r|\n|\r\n)|(\b|\s)(\d+|[!<>+\-*/=]|[\&\|]{1,2}|if|new|else|case|break|switch|default|return|var|function|document|window|[a-z][a-zA-Z\_]+(?=\(.*\)))(\b|\s)|'[^']+'|"[^']+")/g;

  var preTags = document.getElementsByTagName('pre');
  var preTagsLength = preTags.length;

  for (var i = 0; i < preTagsLength; i++) {
    var originalHTML = preTags[i].innerHTML;

    if (preTags[i].className.includes('code-javascript')) {
      preTags[i].innerHTML = originalHTML.replace(jsRegex, highlightJSCode);
    }
    else if (preTags[i].className.includes('code-html')) {
      preTags[i].innerHTML = highlightHTMLCode(originalHTML);
    }
  }
});
<commit_msg>Update code highlighter script to also highlight decimals in numbers<commit_after>const CODE_RED = '#E58';
const CODE_YELLOW = '#EE8';
const CODE_GREEN = '#AE4';
const CODE_BLUE = '#6CE';
const CODE_PURPLE = '#C6E';
const CODE_GRAY = '#999';

function highlightJSCode(match) {
  var replaced = ['', match, ''];

  if (!isNaN(parseInt(match))) {
    replaced[1] = CODE_PURPLE;
  }
  else if (/\/\//.test(match)) {
    replaced[1] = CODE_GRAY;
  }
  else if (/('.+'|".+")/.test(match)) {
    replaced[1] = CODE_YELLOW;
  }
  else if (/[!<>\&|+\-*/=]|if|new|else|case|break|switch|default|return/.test(match)) {
    replaced[1] = CODE_RED;
  }
  else {
    switch (match) {
      case 'function':
      case 'document':
      case 'window':
        replaced[1] = CODE_BLUE + 'font-style:italic';
        break;
      default:
        replaced[1] = CODE_BLUE;
        break;
    }
  }

  return replaced.join('');
}

function highlightHTMLCode(original) {
  var highlighted = [];
  var word = '';
  var flags = {
    tag: false,
    tagName: false,
    doubleQuotes: false
  };

  let length = original.length;
  for (let i = 0; i < length; i++) {
    if (!flags.tag) {
      if (original.slice(i, i + 4) == '<') {
        if (word) {
          highlighted.push(word);
        }
        if (original[i + 4] == '/') {
          highlighted.push('</');
          i += 5;
        }
        else {
          highlighted.push('<');
          i += 4;
        }
        word = '';
        flags.tag = true;
        flags.tagName = true;
      }
      word += original[i];
    }
    else {
      if (flags.tagName) {
        if (!/[a-zA-Z]/.test(original[i])) {
          if (original[i] == ' ') {
            highlighted.push(word + ' ');
            i++;
          }
          else {
            highlighted.push(word + '');
          }
          word = '';
          flags.tagName = false;
        }
      }
      else {
        if (!flags.doubleQuotes) {
          if (original[i] == '"') {
            flags.doubleQuotes = true;
            highlighted.push('="');
            word = '';
            i++;
          }
          else if (original[i] == '=') {
            highlighted.push('');
            highlighted.push(word);
            highlighted.push('');
            word = '';
          }
        }
        else {
          if (original[i] == '"') {
            flags.doubleQuotes = false;
            highlighted.push('');
            highlighted.push(word);
            highlighted.push('"');
            word = '';
            i++;
          }
        }
      }

      if (original.slice(i, i + 4) == '>') {
        flags.tag = false;
        highlighted.push('>');
        i += 3;
      }
      else {
        word += original[i];
      }
    }
  }

  return highlighted.join('');
}

ready(function() {
  var jsRegex = /(\/\/.+(\r|\n|\r\n)|(\b|\s)(\d+\.\d+|\d+|[!<>+\-*/=]|[\&\|]{1,2}|if|new|else|case|break|switch|default|return|var|function|document|window|[a-z][a-zA-Z\_]+(?=\(.*\)))(\b|\s)|'[^']+'|"[^']+")/g;

  var preTags = document.getElementsByTagName('pre');
  var preTagsLength = preTags.length;

  for (var i = 0; i < preTagsLength; i++) {
    var originalHTML = preTags[i].innerHTML;

    if (preTags[i].className.includes('code-javascript')) {
      preTags[i].innerHTML = originalHTML.replace(jsRegex, highlightJSCode);
    }
    else if (preTags[i].className.includes('code-html')) {
      preTags[i].innerHTML = highlightHTMLCode(originalHTML);
    }
  }
});
<|endoftext|>


<commit_before>import {default as React, Component} from 'react';
import { manager } from '../middleware/ChannelManager.js';
var helper = require('../middleware/helper.js');

export class ResultList extends Component {
	constructor(props, context) {
		super(props);
		this.state = {
			markers: [],
			query: {},
			rawData:  [],
			resultMarkup: []
		};
		this.sortInfo = {
			order: this.props.sortBy
		};
		this.nextPage = this.nextPage.bind(this);
		this.appliedQuery = {};
	}

	componentDidMount() {
		this.createChannel();
		this.listComponent();
	}

	// Create a channel which passes the depends and receive results whenever depends changes
	createChannel() {
		// Set the depends - add self aggs query as well with depends
		let depends = this.props.depends ? this.props.depends : {};
		this.enableSort(depends);
		// create a channel and listen the changes
		var channelObj = manager.create(this.context.appbaseRef, this.context.type, depends, this.props.size, this.props.from);
		this.channelId = channelObj.channelId;
		channelObj.emitter.addListener(channelObj.channelId, function(res) {
			let data = res.data;
			let rawData, markersData, newData = [], currentData = [];
			this.streamFlag = false;
			if (res.mode === 'streaming') {
				this.channelMethod = 'streaming';
				let modData = this.streamDataModify(this.state.rawData, res);
				rawData = modData.rawData;
				newData = res;
				currentData = this.state.rawData;
				res = modData.res;
				this.streamFlag = true;
				markersData = this.setMarkersData(rawData);
			} else if (res.mode === 'historic') {
				this.channelMethod = 'historic';
				newData = res.data.hits && res.data.hits.hits ? res.data.hits.hits : [];
				let normalizeCurrentData = this.normalizeCurrentData(res, this.state.rawData, newData);
				newData = normalizeCurrentData.newData;
				currentData = normalizeCurrentData.currentData;
				rawData = currentData.concat(newData);
			}
			this.setState({
				rawData: rawData,
				newData: newData,
				currentData: currentData,
				markersData: markersData
			}, function() {
				// Pass the historic or streaming data in index method
				res.allMarkers = rawData;
				let modifiedData = JSON.parse(JSON.stringify(res));
				modifiedData.newData = this.state.newData;
				modifiedData.currentData = this.state.currentData;
				delete modifiedData.data;
				let generatedData = this.props.onData ? this.props.onData(modifiedData) : this.defaultonData(res);
				this.setState({
					resultMarkup: generatedData
				});
				if (this.streamFlag) {
					this.streamMarkerInterval();
				}
			}.bind(this));
		}.bind(this));
	}

	// normalize current data
	normalizeCurrentData(res, rawData, newData) {
		let appliedQuery = JSON.parse(JSON.stringify(res.appliedQuery));
		delete appliedQuery.body.from;
		delete appliedQuery.body.size;
		let currentData = JSON.stringify(appliedQuery) === JSON.stringify(this.appliedQuery) ? rawData : [];
		if(!currentData.length) {
			this.appliedQuery = appliedQuery;
		} else {
			newData = newData.filter((newRecord) => {
				let notExits = true;
				currentData.forEach((oldRecord) => {
					if(newRecord._id+'-'+newRecord._type === oldRecord._id+'-'+oldRecord._type) {
						notExits = false;
					}
				});
				return notExits;
			});
		}
		return {
			currentData: currentData,
			newData: newData
		};
	}

	// enable sort
	enableSort(depends) {
		depends['ResultSort'] = { operation: "must" };
		let sortObj = {
			key: "ResultSort",
			value: {
				[this.props.appbaseField]: {
					'order': this.props.sortBy
				}
			}
		};
		helper.selectedSensor.setSortInfo(sortObj);
	}

	// append data if pagination is applied
	appendData(data) {
		let rawData = this.state.rawData;
		let hits = rawData.hits.hits.concat(data.hits.hits);
		rawData.hits.hits = _.uniqBy(hits, '_id');;
		return rawData;
	}

	// append stream boolean flag and also start time of stream
	streamDataModify(rawData, res) {
		if (res.data) {
			res.data.stream = true;
			res.data.streamStart = new Date();
			if (res.data._deleted) {
				let hits = rawData.hits.hits.filter((hit) => {
					return hit._id !== res.data._id;
				});
				rawData.hits.hits = hits;
			} else {
				let prevData = rawData.hits.hits.filter((hit) => {
					return hit._id === res.data._id;
				});
				let hits = rawData.hits.hits.filter((hit) => {
					return hit._id !== res.data._id;
				});
				rawData.hits.hits = hits;
				rawData.hits.hits.push(res.data);
			}
		}
		return {
			rawData: rawData,
			res: res,
			streamFlag: true
		};
	}

	// tranform the raw data to marker data
	setMarkersData(hits) {
		var self = this;
		if (hits) {
			return hits;
		} else {
			return [];
		}
	}

	// default markup
	defaultonData(res) {
		let result;
		if (res.newData) {
			result = res.newData.map((marker, index) => {
				return (
{JSON.stringify(marker)}
);
			});
		}
		return result;
	}

	nextPage() {
		let channelOptionsObj = manager.channels[this.channelId].previousSelectedSensor['channel-options-' + this.channelId];
		let obj = {
			key: 'channel-options-' + this.channelId,
			value: {
				size: this.props.size,
				from: channelOptionsObj.from + this.props.size
			}
		};
		manager.nextPage(this.channelId);
	}

	listComponent() {
		let node = this.refs.ListContainer;
		if (node) {
			node.addEventListener('scroll', () => {
				if ($(node).scrollTop() + $(node).innerHeight() >= node.scrollHeight) {
					this.nextPage();
				}
			});
		}
	}

	render() {
		let title = null,
			titleExists = false;
		if(this.props.title) {
			titleExists = true;
			title = (
{this.props.title}
);
		}
		return (
			<div ref="ListContainer" className={`rbc rbc-resultlist card thumbnail title-${titleExists}`} style={this.props.containerStyle}>
				{title}
				{this.state.resultMarkup}

		)
	}
}

ResultList.propTypes = {
	sensorId: React.PropTypes.string,
	appbaseField: React.PropTypes.string,
	title: React.PropTypes.string,
	sortBy: React.PropTypes.string,
	from: React.PropTypes.number,
	onData: React.PropTypes.func,
	size: React.PropTypes.number,
	requestOnScroll: React.PropTypes.bool,
	containerStyle: React.PropTypes.any
};

ResultList.defaultProps = {
	from: 0,
	size: 20,
	requestOnScroll: true,
	containerStyle: {
		height: '700px',
		overflow: 'auto'
	}
};

// context type
ResultList.contextTypes = {
	appbaseRef: React.PropTypes.any.isRequired,
	type: React.PropTypes.any.isRequired
};
<commit_msg>fix defaultOnload in ResultList<commit_after>import {default as React, Component} from 'react';
import { manager } from '../middleware/ChannelManager.js';
var helper = require('../middleware/helper.js');
var $ = require('jquery');

export class ResultList extends Component {
	constructor(props, context) {
		super(props);
		this.state = {
			markers: [],
			query: {},
			rawData:  [],
			resultMarkup: []
		};
		this.sortInfo = {
			order: this.props.sortBy
		};
		this.nextPage = this.nextPage.bind(this);
		this.appliedQuery = {};
	}

	componentDidMount() {
		this.createChannel();
		this.listComponent();
	}

	// Create a channel which passes the depends and receive results whenever depends changes
	createChannel() {
		// Set the depends - add self aggs query as well with depends
		let depends = this.props.depends ? this.props.depends : {};
		this.enableSort(depends);
		// create a channel and listen the changes
		var channelObj = manager.create(this.context.appbaseRef, this.context.type, depends, this.props.size, this.props.from);
		this.channelId = channelObj.channelId;
		channelObj.emitter.addListener(channelObj.channelId, function(res) {
			let data = res.data;
			let rawData, markersData, newData = [], currentData = [];
			this.streamFlag = false;
			if (res.mode === 'streaming') {
				this.channelMethod = 'streaming';
				let modData = this.streamDataModify(this.state.rawData, res);
				rawData = modData.rawData;
				newData = res;
				currentData = this.state.rawData;
				res = modData.res;
				this.streamFlag = true;
				markersData = this.setMarkersData(rawData);
			} else if (res.mode === 'historic') {
				this.channelMethod = 'historic';
				newData = res.data.hits && res.data.hits.hits ? res.data.hits.hits : [];
				let normalizeCurrentData = this.normalizeCurrentData(res, this.state.rawData, newData);
				newData = normalizeCurrentData.newData;
				currentData = normalizeCurrentData.currentData;
				rawData = currentData.concat(newData);
			}
			this.setState({
				rawData: rawData,
				newData: newData,
				currentData: currentData,
				markersData: markersData
			}, function() {
				// Pass the historic or streaming data in index method
				res.allMarkers = rawData;
				let modifiedData = JSON.parse(JSON.stringify(res));
				modifiedData.newData = this.state.newData;
				modifiedData.currentData = this.state.currentData;
				delete modifiedData.data;
				let generatedData = this.props.onData ? this.props.onData(modifiedData) : this.defaultonData(res);
				this.setState({
					resultMarkup: generatedData
				});
				if (this.streamFlag) {
					this.streamMarkerInterval();
				}
			}.bind(this));
		}.bind(this));
	}

	// normalize current data
	normalizeCurrentData(res, rawData, newData) {
		let appliedQuery = JSON.parse(JSON.stringify(res.appliedQuery));
		delete appliedQuery.body.from;
		delete appliedQuery.body.size;
		let currentData = JSON.stringify(appliedQuery) === JSON.stringify(this.appliedQuery) ? rawData : [];
		if(!currentData.length) {
			this.appliedQuery = appliedQuery;
		} else {
			newData = newData.filter((newRecord) => {
				let notExits = true;
				currentData.forEach((oldRecord) => {
					if(newRecord._id+'-'+newRecord._type === oldRecord._id+'-'+oldRecord._type) {
						notExits = false;
					}
				});
				return notExits;
			});
		}
		return {
			currentData: currentData,
			newData: newData
		};
	}

	// enable sort
	enableSort(depends) {
		depends['ResultSort'] = { operation: "must" };
		let sortObj = {
			key: "ResultSort",
			value: {
				[this.props.appbaseField]: {
					'order': this.props.sortBy
				}
			}
		};
		helper.selectedSensor.setSortInfo(sortObj);
	}

	// append data if pagination is applied
	appendData(data) {
		let rawData = this.state.rawData;
		let hits = rawData.hits.hits.concat(data.hits.hits);
		rawData.hits.hits = _.uniqBy(hits, '_id');;
		return rawData;
	}

	// append stream boolean flag and also start time of stream
	streamDataModify(rawData, res) {
		if (res.data) {
			res.data.stream = true;
			res.data.streamStart = new Date();
			if (res.data._deleted) {
				let hits = rawData.hits.hits.filter((hit) => {
					return hit._id !== res.data._id;
				});
				rawData.hits.hits = hits;
			} else {
				let prevData = rawData.hits.hits.filter((hit) => {
					return hit._id === res.data._id;
				});
				let hits = rawData.hits.hits.filter((hit) => {
					return hit._id !== res.data._id;
				});
				rawData.hits.hits = hits;
				rawData.hits.hits.push(res.data);
			}
		}
		return {
			rawData: rawData,
			res: res,
			streamFlag: true
		};
	}

	// tranform the raw data to marker data
	setMarkersData(hits) {
		var self = this;
		if (hits) {
			return hits;
		} else {
			return [];
		}
	}

	// default markup
	defaultonData(res) {
		let result;
		if (res.allMarkers) {
			result = res.allMarkers.map((marker, index) => {
				return (

{JSON.stringify(Object.values(marker._source))}

				);
			});
		}
		result = (

				{result}

		)
		return result;
	}

	nextPage() {
		let channelOptionsObj = manager.channels[this.channelId].previousSelectedSensor['channel-options-' + this.channelId];
		let obj = {
			key: 'channel-options-' + this.channelId,
			value: {
				size: this.props.size,
				from: channelOptionsObj.from + this.props.size
			}
		};
		manager.nextPage(this.channelId);
	}

	listComponent() {
		let node = this.refs.ListContainer;
		if (node) {
			node.addEventListener('scroll', () => {
				if ($(node).scrollTop() + $(node).innerHeight() >= node.scrollHeight) {
					this.nextPage();
				}
			});
		}
	}

	render() {
		let title = null,
			titleExists = false;
		if(this.props.title) {
			titleExists = true;
			title = (
{this.props.title}
);
		}
		return (
			<div ref="ListContainer" className={`rbc rbc-resultlist card thumbnail title-${titleExists}`} style={this.props.containerStyle}>
				{title}
				{this.state.resultMarkup}

		)
	}
}

ResultList.propTypes = {
	sensorId: React.PropTypes.string,
	appbaseField: React.PropTypes.string,
	title: React.PropTypes.string,
	sortBy: React.PropTypes.string,
	from: React.PropTypes.number,
	onData: React.PropTypes.func,
	size: React.PropTypes.number,
	requestOnScroll: React.PropTypes.bool,
	containerStyle: React.PropTypes.any
};

ResultList.defaultProps = {
	from: 0,
	size: 20,
	requestOnScroll: true,
	containerStyle: {
		height: '700px',
		overflow: 'auto'
	}
};

// context type
ResultList.contextTypes = {
	appbaseRef: React.PropTypes.any.isRequired,
	type: React.PropTypes.any.isRequired
};
<|endoftext|>


<commit_before>var bigchainManger = require("./bigchain_manager.js"),
  Ajv = require('ajv')

var ajv = new Ajv();

var setSchema = {
  //"$schema": "http://json-schema.org/draft-06/schema#",
  "title": "Set setSchema",
  "type": "object",
  "properties": {
    "name": {
      "description": "name",
      "type": "string"
    },
    "schema": {
      "description": "schema",
      "type": "object"
    }
  },
  "required": ["schema", "name"],
  "additionalProperties": false
};

// singleton https://team.goodeggs.com/export-this-interface-design-patterns-for-node-js-modules-b48a3b1f8f40
function PIMaasManger () {
   console.log("New PIMaasManger Instance")
}

PIMaasManger.prototype.getEd25519Keypair = function() {
    bigchainManger.getEd25519Keypair();
}

PIMaasManger.prototype.signTxAndPost = function(data, publicKey, privateKey, func) {
    pimaasManger = this
    pimaasManger.signTx(data, publicKey, privateKey, function(signed) {
       pimaasManger.postTx(signed, func);
    })
}

PIMaasManger.prototype.signTx = function(data, publicKey, privateKey, func) {
    var txMeta = {};
    var pimaasManger = this
    txMeta.isSet = ajv.validate(setSchema, data);
    console.log("!!!!!!!!!!!!!!!!1");

   console.log(txMeta.isSet);
    if (txMeta.isSet == true) {
        txMeta.setName = data.name;
        func(bigchainManger.signTx(data, txMeta, publicKey, privateKey));
    }
    else {
        console.log(data);
        txMeta.schemaId = data.schemaId;
        pimaasManger.getSchema(data.schemaId, function(pimSet) {
            console.log(ajv.validate(pimSet.schema,data.metadata))
            txMeta.setName = pimSet.name
            console.log("!!!!!!!!!!!!!!!!2");
            console.log(txMeta);
            console.log("!!!!!!!!!!!!!!!!3");

            if (ajv.validate(pimSet.schema,data.metadata))
                func(bigchainManger.signTx(data, txMeta, publicKey, privateKey));
            else
                throw new Error("Doesn't validate");
        })
    }
}

PIMaasManger.prototype.getSet = function(txId, func) {
    this.getTx(txId, function(tx) {func(tx.asset.data)})
}

PIMaasManger.prototype.getSchema = function(schemaId, func) {
    this.getTx(schemaId, function(tx) {func(tx.asset.data)})
}

PIMaasManger.prototype.validate = function(schemaId, metadata, func) {
    bigchainManger.getTx(schemaId, function(tx) {
        func(ajv.validate(tx.asset.data.schema, metadata))
    })
}

PIMaasManger.prototype.getTx = function(tx, func) {
    bigchainManger.getTx(tx, func);
}

PIMaasManger.prototype.postTx = function(tx, func) {
    bigchainManger.postTx(tx, func);
}

module.exports = exports = new PIMaasManger();<commit_msg>set where<commit_after>var bigchainManger = require("./bigchain_manager.js"),
  Ajv = require('ajv')

var ajv = new Ajv();

var setSchema = {
  //"$schema": "http://json-schema.org/draft-06/schema#",
  "title": "Set setSchema",
  "type": "object",
  "properties": {
    "name": {
      "description": "name",
      "type": "string"
    },
    "schema": {
      "description": "schema",
      "type": "object"
    }
  },
  "required": ["schema", "name"],
  "additionalProperties": false
};

// singleton https://team.goodeggs.com/export-this-interface-design-patterns-for-node-js-modules-b48a3b1f8f40
function PIMaasManger () {
   console.log("New PIMaasManger Instance")
}

PIMaasManger.prototype.getEd25519Keypair = function() {
    bigchainManger.getEd25519Keypair();
}

PIMaasManger.prototype.signTxAndPost = function(data, publicKey, privateKey, func) {
    pimaasManger = this
    pimaasManger.signTx(data, publicKey, privateKey, function(signed) {
       pimaasManger.postTx(signed, func);
    })
}

PIMaasManger.prototype.signTx = function(data, publicKey, privateKey, func) {
    var txMeta = {};
    var pimaasManger = this
    txMeta.isSet = ajv.validate(setSchema, data);
    if (txMeta.isSet == true) {
        txMeta.setName = data.name;
        func(bigchainManger.signTx(data, txMeta, publicKey, privateKey));
    }
    else {
        console.log(data);
        txMeta.schemaId = data.schemaId;
        pimaasManger.getSchema(data.schemaId, function(pimSet) {
            console.log(ajv.validate(pimSet.schema,data.metadata))
            txMeta.setName = pimSet.name
            if (ajv.validate(pimSet.schema,data.metadata))
                func(bigchainManger.signTx(data, txMeta, publicKey, privateKey));
            else
                throw new Error("Doesn't validate");
        })
    }
}

PIMaasManger.prototype.getSet = function(txId, func) {
    this.getTx(txId, function(tx) {func(tx.asset.data)})
}

PIMaasManger.prototype.getSchema = function(schemaId, func) {
    this.getTx(schemaId, function(tx) {func(tx.asset.data)})
}

PIMaasManger.prototype.validate = function(schemaId, metadata, func) {
    bigchainManger.getTx(schemaId, function(tx) {
        func(ajv.validate(tx.asset.data.schema, metadata))
    })
}

PIMaasManger.prototype.getTx = function(tx, func) {
    bigchainManger.getTx(tx, func);
}

PIMaasManger.prototype.postTx = function(tx, func) {
    bigchainManger.postTx(tx, func);
}

module.exports = exports = new PIMaasManger();<|endoftext|>


<commit_before>// ==========================================================================
// Project:   xTuple Postbooks - Business Management System Framework
// Copyright: ©2011 OpenMFG LLC, d/b/a xTuple
// ==========================================================================
/*globals XM */

/** @class

  Provides special number handling capabilities for documents.

  @extends XM.Record
*/

XM.Document = XM.Record.extend(
/** @scope XM.Document.prototype */ {

  /**
    The unique property for the document, typically a number, code or name.
    This property will be checked when a user edits it to ensure it has not already
    been used by another record of the same type.

    @default number
  */
  documentKey: 'number',

  /**
    If set, the number Policy property will be set based on the number
    generation policy on this setting.
  */
  numberPolicySetting: null,

  // ..........................................................
  // CALCULATED PROPERTIES
  //

  /**
    Number generation method for the document key that can be one of three constants:
      XM.MANUAL_NUMBER
      XM.AUTO_NUMBER
      XM.AUTO_OVERRIDE_NUMBER

    Can be inferred from the setting that controls this for a given record type
    if it is set.

    @seealso numberPolicySetting
    @default XM.MANUAL_NUMBER
  */
  numberPolicy: function(key, value) {
    var setting =  this.get('numberPolicySetting');
    if(value === undefined && setting) {
      value = XM.session.get('settings').get(setting);
    }
    this._numberPolicy = value ? value : XM.MANUAL_NUMBER;
    return this._numberPolicy;
  }.property().cacheable(),

  // ..........................................................
  // METHODS
  //

  init: function() {
    arguments.callee.base.apply(this, arguments);
    var docKey = this.get('documentKey');
    dv = function() {
      var record = arguments[0],
          docKey = record.get('documentKey'),
          status = record.get('status'),
          numberPolicy = record.get('numberPolicy');
      if((numberPolicy === XM.AUTO_NUMBER ||
          numberPolicy === XM.AUTO_OVERRIDE_NUMBER) &&
          status === SC.Record.READY_NEW) {
        XM.Record.fetchNumber.call(record, docKey);
      } else return '';
    }
    this[docKey].defaultValue = dv;
    this[docKey].set('isRequired', true);
    this.addObserver(docKey, this.keyDidChange);
  },

  /**
    Called whenever the document key property changes. Does the following:
      * Locks editing when number has been set and number policy is XM.AUTO_NUMBER
      * Releases a generated number if user has over-ridden an auto generated number
      * Checks for duplicate key violitions by calling findExisting().

    @seealso XM.Document.findExisting()
  */
  keyDidChange: function() {
    var record = this;
        status = record.get('status'),
        docKey = record.get('documentKey'),
        number = record.get(docKey),
        policy = record.get('numberPolicy');
console.log('key changed')
    // if generated and automatic, lock it down
    if(record._xm_numberGen && policy === 'A') this.number.set('isEditable', false);

    // release the fetched number if applicable
    if(record._xm_numberGen && record._xm_numberGen != number) {
      XM.Record.releaseNumber.call(record, record._xm_numberGen);
      record._xm_numberGen = null;
    }

    // For manually edited numbers, check for conflicts with existing
    if(number && (status == SC.Record.READY_NEW || status == SC.Record.READY_DIRTY))  {
      if(this._xm_numberGen && this._xm_numberGen == number) return;
console.log('eh?')
      // callback
      callback = function(err, result) {
        if(!err) {
          var err = XM.errors.findProperty('code', 'xt1007'),
              id = record.get('id'),
              isConflict = result ? result !== id  : false;
          record.updateErrors(err, isConflict);
        }
      }

      // function call
      XM.Record.findExisting.call(record, docKey, number, callback);
    }
  },

  destroy: function() {
    var record = this,
        status = this.get('status');

    /* release the number if applicable */
    if(status === SC.Record.READY_NEW && record._xm_numberGen) {
      XM.Record.releaseNumber.call(record, record._xm_numberGen);
      record._xm_numberGen = null;
    }
    arguments.callee.base.apply(this, arguments);
  },

  // ..........................................................
  // OBSERVERS
  //

  /** @private */
  _xm_numberPolicyDidChange: function() {
    var policy = this.get('numberPolicy');
    this.number.set('isEditable', policy !== 'A');
  }.observes('numberPolicy'),

});

<commit_msg>Fix property reference to use dockey instead of hard coded number.<commit_after>// ==========================================================================
// Project:   xTuple Postbooks - Business Management System Framework
// Copyright: ©2011 OpenMFG LLC, d/b/a xTuple
// ==========================================================================
/*globals XM */

/** @class

  Provides special number handling capabilities for documents.

  @extends XM.Record
*/

XM.Document = XM.Record.extend(
/** @scope XM.Document.prototype */ {

  /**
    The unique property for the document, typically a number, code or name.
    This property will be checked when a user edits it to ensure it has not already
    been used by another record of the same type.

    @default number
  */
  documentKey: 'number',

  /**
    If set, the number Policy property will be set based on the number
    generation policy on this setting.
  */
  numberPolicySetting: null,

  // ..........................................................
  // CALCULATED PROPERTIES
  //

  /**
    Number generation method for the document key that can be one of three constants:
      XM.MANUAL_NUMBER
      XM.AUTO_NUMBER
      XM.AUTO_OVERRIDE_NUMBER

    Can be inferred from the setting that controls this for a given record type
    if it is set.

    @seealso numberPolicySetting
    @default XM.MANUAL_NUMBER
  */
  numberPolicy: function(key, value) {
    var setting =  this.get('numberPolicySetting');
    if(value === undefined && setting) {
      value = XM.session.get('settings').get(setting);
    }
    this._numberPolicy = value ? value : XM.MANUAL_NUMBER;
    return this._numberPolicy;
  }.property().cacheable(),

  // ..........................................................
  // METHODS
  //

  init: function() {
    arguments.callee.base.apply(this, arguments);
    var docKey = this.get('documentKey');
    dv = function() {
      var record = arguments[0],
          docKey = record.get('documentKey'),
          status = record.get('status'),
          numberPolicy = record.get('numberPolicy');
      if((numberPolicy === XM.AUTO_NUMBER ||
          numberPolicy === XM.AUTO_OVERRIDE_NUMBER) &&
          status === SC.Record.READY_NEW) {
        XM.Record.fetchNumber.call(record, docKey);
      } else return '';
    }
    this[docKey].defaultValue = dv;
    this[docKey].set('isRequired', true);
    this.addObserver(docKey, this.keyDidChange);
  },

  /**
    Called whenever the document key property changes. Does the following:
      * Locks editing when number has been set and number policy is XM.AUTO_NUMBER
      * Releases a generated number if user has over-ridden an auto generated number
      * Checks for duplicate key violitions by calling findExisting().

    @seealso XM.Document.findExisting()
  */
  keyDidChange: function() {
    var record = this;
        status = record.get('status'),
        docKey = record.get('documentKey'),
        number = record.get(docKey),
        policy = record.get('numberPolicy');

    // if generated and automatic, lock it down
    if(record._xm_numberGen && policy === 'A') this[docKey].set('isEditable', false);

    // release the fetched number if applicable
    if(record._xm_numberGen && record._xm_numberGen != number) {
      XM.Record.releaseNumber.call(record, record._xm_numberGen);
      record._xm_numberGen = null;
    }

    // For manually edited numbers, check for conflicts with existing
    if(number && (status == SC.Record.READY_NEW || status == SC.Record.READY_DIRTY))  {
      if(this._xm_numberGen && this._xm_numberGen == number) return;

      // callback
      callback = function(err, result) {
        if(!err) {
          var err = XM.errors.findProperty('code', 'xt1007'),
              id = record.get('id'),
              isConflict = result ? result !== id  : false;
          record.updateErrors(err, isConflict);
        }
      }

      // function call
      XM.Record.findExisting.call(record, docKey, number, callback);
    }
  },

  destroy: function() {
    var record = this,
        status = this.get('status');

    /* release the number if applicable */
    if(status === SC.Record.READY_NEW && record._xm_numberGen) {
      XM.Record.releaseNumber.call(record, record._xm_numberGen);
      record._xm_numberGen = null;
    }
    arguments.callee.base.apply(this, arguments);
  },

  // ..........................................................
  // OBSERVERS
  //

  /** @private */
  _xm_numberPolicyDidChange: function() {
    var policy = this.get('numberPolicy'),
        docKey = this.get('documentKey');
    this[docKey].set('isEditable', policy !== 'A');
  }.observes('numberPolicy')

});

<|endoftext|>


<commit_before>//Make sure to load uuid.js and uuidhelpers.js into mongo before running this!

mapFunction = function() {
    var level1 = level2 = level3 = level4 = 0;
    switch(parseInt(this.body.performanceLevel))
    {
        case 1: level1++; break;
        case 2: level2++; break;
        case 3: level3++; break;
        case 4: level4++; break;
        default: break;
    }

    var values = {level1:level1,level2:level2,level3:level3,level4:level4};
    var studentId = this.body.studentId;
    var ssaArray = db.studentschoolassociation.find({"body.studentId":studentId}).toArray();
    var districts = new Array();

    for( var i=0; i<ssaArray.length; i++) {
        var schoolId = ssaArray[i].body.schoolId;
        emit({"schoolId":schoolId,"assessmentType":aggregation_name}, values);

        var eosaArray = db.educationOrganizationschoolassociation.find({"body.schoolId":schoolId}).toArray();

        for( var j=0; j<eosaArray.length; j++) {
            districts[eosaArray[j].body.educationOrganizationId] = eosaArray[j].body.educationOrganizationId;
        }
    }

    for( districtId in districts) {
        emit({"districtId":districtId,"assessmentType":aggregation_name}, values);
    }
};

reduceFunction = function(key,values) {
    var level1total = level2total = level3total = level4total = 0;

    for( var i=0; i<values.length; i++) {
        level1total+=values[i].level1;
        level2total+=values[i].level2;
        level3total+=values[i].level3;
        level4total+=values[i].level4;
    }

    return {level1:level1total,level2:level2total,level3:level3total,level4:level4total};

};

finalizeFunction = function(key,value) {

    var total = value.level1 + value.level2 + value.level3 + value.level4;

    var level1percentage = value.level1*100.0/total;
    var level2percentage = value.level2*100.0/total;
    var level3percentage = value.level3*100.0/total;
    var level4percentage = value.level4*100.0/total;

    return {
        ts: new Date(),
        level1:value.level1,
        level2:value.level2,
        level3:value.level3,
        level4:value.level4,
        level1percentage:Math.round(level1percentage*10)/10,
        level2percentage:Math.round(level2percentage*10)/10,
        level3percentage:Math.round(level3percentage*10)/10,
        level4percentage:Math.round(level4percentage*10)/10,
        groupBy: key,
        raw:"true"
    };

};

var cleanUp = function() {
	db.myoutput.find({"value.raw":"true"}).forEach(function (data) {
		var old_id = data._id;
		var doc = data;

		doc._id = JUUID(UUID.generate());
		doc.type = "aggregate";
		doc.body = doc.value;

		delete doc.value;
		delete doc.body.raw;

		db.myoutput.insert(doc);
		db.myoutput.remove({ _id: old_id});
	});
}

db.myoutput.drop()

db.runCommand( { mapreduce:"studentassessmentassociation",
                                                      map:mapFunction,
                                                      reduce:reduceFunction,
                                                      finalize:finalizeFunction,
                                                      query: {"body.assessmentId":{$in: ["67ce204b-9999-4a11-bfea-000000004682","67ce204b-9999-4a11-bfea-000000004683","67ce204b-9999-4a11-bfea-000000004684"]}},
                                                      scope: { aggregation_name : "8th Grade EOG" },
                                                      out: { reduce: "myoutput" }
                                                    });
cleanUp();
db.myoutput.find()

<commit_msg>put aggregations into aggregation collection / change typed from aggregate => aggregation<commit_after>//Make sure to load uuid.js and uuidhelpers.js into mongo before running this!

mapFunction = function() {
    var level1 = level2 = level3 = level4 = 0;
    switch(parseInt(this.body.performanceLevel))
    {
        case 1: level1++; break;
        case 2: level2++; break;
        case 3: level3++; break;
        case 4: level4++; break;
        default: break;
    }

    var values = {level1:level1,level2:level2,level3:level3,level4:level4};
    var studentId = this.body.studentId;
    var ssaArray = db.studentschoolassociation.find({"body.studentId":studentId}).toArray();
    var districts = new Array();

    for( var i=0; i<ssaArray.length; i++) {
        var schoolId = ssaArray[i].body.schoolId;
        emit({"schoolId":schoolId,"assessmentType":aggregation_name}, values);

        var eosaArray = db.educationOrganizationschoolassociation.find({"body.schoolId":schoolId}).toArray();

        for( var j=0; j<eosaArray.length; j++) {
            districts[eosaArray[j].body.educationOrganizationId] = eosaArray[j].body.educationOrganizationId;
        }
    }

    for( districtId in districts) {
        emit({"districtId":districtId,"assessmentType":aggregation_name}, values);
    }
};

reduceFunction = function(key,values) {
    var level1total = level2total = level3total = level4total = 0;

    for( var i=0; i<values.length; i++) {
        level1total+=values[i].level1;
        level2total+=values[i].level2;
        level3total+=values[i].level3;
        level4total+=values[i].level4;
    }

    return {level1:level1total,level2:level2total,level3:level3total,level4:level4total};

};

finalizeFunction = function(key,value) {

    var total = value.level1 + value.level2 + value.level3 + value.level4;

    var level1percentage = value.level1*100.0/total;
    var level2percentage = value.level2*100.0/total;
    var level3percentage = value.level3*100.0/total;
    var level4percentage = value.level4*100.0/total;

    return {
        ts: new Date(),
        level1:value.level1,
        level2:value.level2,
        level3:value.level3,
        level4:value.level4,
        level1percentage:Math.round(level1percentage*10)/10,
        level2percentage:Math.round(level2percentage*10)/10,
        level3percentage:Math.round(level3percentage*10)/10,
        level4percentage:Math.round(level4percentage*10)/10,
        groupBy: key,
        raw:"true"
    };

};

var cleanUp = function() {
	db.aggregation.find({"value.raw":"true"}).forEach(function (data) {
		var old_id = data._id;
		var doc = data;

		doc._id = JUUID(UUID.generate());
		doc.type = "aggregation";
		doc.body = doc.value;

		delete doc.value;
		delete doc.body.raw;

		db.aggregation.insert(doc);
		db.aggregation.remove({ _id: old_id});
	});
}

db.aggregation.drop()

db.runCommand( { mapreduce:"studentassessmentassociation",
                                                      map:mapFunction,
                                                      reduce:reduceFunction,
                                                      finalize:finalizeFunction,
                                                      query: {"body.assessmentId":{$in: ["67ce204b-9999-4a11-bfea-000000004682","67ce204b-9999-4a11-bfea-000000004683","67ce204b-9999-4a11-bfea-000000004684"]}},
                                                      scope: { aggregation_name : "8th Grade EOG" },
                                                      out: { reduce: "aggregation" }
                                                    });
cleanUp();
db.aggregation.find()

<|endoftext|>


<commit_before>/* This is code which will be run when application is started */
var Path        = require('path'),
    ChatManager = require('./model/shared/chatmanager'),
    User        = require('./model/local/user');

module.exports = {
  setApplicationState : function (options) {
        options.sharedState = {
            chats : new ChatManager()
        }

        options.localState = function () {
            this.user = new User();
        }
  }
}
<commit_msg>Renaming setApplicationState to initialize<commit_after>/* This is code which will be run when application is started */
var Path        = require('path'),
    ChatManager = require('./model/shared/chatmanager'),
    User        = require('./model/local/user');

module.exports = {
  initialize : function (options) {
        options.sharedState = {
            chats : new ChatManager()
        }

        options.localState = function () {
            this.user = new User();
        }
  }
}
<|endoftext|>


<commit_before>/**
 * 计算器
 * Created by suliang on 2016/10/28.
 * v2.0
 * v2.0 modified on 2016.12.29
 */
var calculator = (function(){

    var num = 0, result = 0, numshow = "0";
    var operate = 0; //判断输入状态的标志
    var calcul = 0; //判断计算状态的标志
    var flag = 0; //判断此时的输入状态是数字还是运算符

    // 数字keycode
    var keyCode = {
        "48":0,"96":0,"49":1,"97":1,"50":2,"98":2,"51":3,"99":3,"52":4,"100":4,"53":5,"101":5,"54":6,"102":6,"55":7,"103":7,"56":8,"104":8,"57":9,"105":9
    };

    // 操作keycode
    var excuteCode = {
        "107":"plus",
        "187":"plus",
        "109":"minus",
        "106":"times",
        "110":"dot",
        "111":"divide",
        "108":"equal",
        "13":"equal",
        "46":"delAll",
        "8":"del",
        "27":"clearscreen",
    }

    //初始化
    var init = function(){

        //初始化计算器显示屏
        $(".numScreen").val(0);
        $(".numScreenSave").html("");

        //绑定数字输入点击事件
        $("#useCalculatorBody").find(".number-btn").unbind("click").click(function(){

            var num = $(this).val();
            command(num);

            //防止焦点停留导致键盘输入错误
            $(this).blur();
        });

        //绑定运算符输入点击事件
        $("#useCalculatorBody").find(".tool").unbind("click").click(function(){

            var _excute = $(this).attr("data-excute");
            excuteCalcu[_excute]();

            //防止焦点停留导致键盘输入错误
            $(this).blur();
        });

        if(calculator.index == 0){
            //实现数字键盘
            $(document).on("keydown",function(e){
                if($(e.target).prop("tagName") === "BODY" || $(e.target).hasClass("numScreen")){

                    //执行数字输入
                    if(e.which in keyCode){
                        command(keyCode[e.which]);
                    }

                    //执行运算符输入
                    else if(e.which in excuteCode){

                        //阻止微端回退页面
                        if(e.which == 8){
                            e.preventDefault();
                        }
                        excuteCalcu[excuteCode[e.which]]();
                    }
                }
            });

            //修改计算器状态
            calculator.index = 1;
        }
    };

    //计算操作集合
    var excuteCalcu = {};

    //处理当前输入值
    var command = function(num) {

        //获得当前显示数据
        var str = String($(".numScreen").val());

        //如果当前值不是"0"，且状态为0，则返回当前值，否则返回空值;
        if(str !== "0"){
            if(operate !== 0){
                str = "";
            }
        }else{
            str = "";
        }

        //给当前值追加字符
        str = str + String(num);

        //最多输入13位
        if(str.length === 13){
            return false;
        }

        //刷新显示并重置输入状态
        $(".numScreen").val(str);
        operate = 0;
        flag = 0;

    };

    //处理每一步的计算结果
    var commandSave = function(){

        var _numScreen = String($(".numScreen").val());
        var _numScreenSave = $(".numScreenSave").html();

        var str = _numScreenSave + _numScreen;

        //拼接运算符
        switch (calcul) {
            case 1:
                str = str + "+";
                break;
            case 2:
                str = str + "-";
                break;
            case 3:
                str = str + "*";
                break;
            case 4:
                str = str + "/";
                break;
        }

        //处理等于的情况
        if(calcul === 0){

            //只在输入框显示最后结果
            $(".numScreenSave").html("");

            //有小数的情况
            if(String(num).indexOf(".") !== -1){
                if(String(num).indexOf("e") !== -1){
                    num = String(num);
                }else{
                    num = String(num).substr(0,14);
                }
            }

            //没有小数的情况
            else{
                String(num).substr(0,12)
            }
            $(".numScreen").val(num);
        }else{
            $(".numScreenSave").html(str); //刷新显示
            $(".numScreen").val(num);
            flag = 1;
        }

    };

    // 处理两个0情况
    excuteCalcu.dzero = function() {

        var str = String($(".numScreen").val());

        //如果当前值不是"0"，且状态为0，则返回当str+"00"，否则返回"0";
        if(str !== "0"){
            if(operate === 0){
                str = str + "00";
            }else{
                str = "0";
            }
        }else{
            str = "0";
        }
        //最多输入13位
        if(str.length >= 13){
            return false;
        }
        $(".numScreen").val(str);
        operate = 0;
    };

    // 处理小数点情况
    excuteCalcu.dot = function() {

        var str = String($(".numScreen").val());

        //如果当前值不是"0"，且状态为0，则返回当前值，否则返回"0";
        if(str !== "0"){
            if(operate !== 0){
                str = "0";
            }
        }else{
            str = "0";
        }

        //判断是否已经有一个点号,如果有则不再插入
        for (i = 0; i <= str.length; i++) {
            if (str.substr(i, 1) == ".") {
                return false;
            }
        }

        str = str + ".";
        $(".numScreen").val(str);
        operate = 0;
    };

    // 退格
    excuteCalcu.del = function() {

        var str = String($(".numScreen").val());
        str = (str != "0") ? str : "";
        str = str.substr(0, str.length - 1);
        str = (str != "") ? str : "0";
        $(".numScreen").val(str);
    };

    // 全删
    excuteCalcu.delAll = function() {
        $(".numScreen").val(0);
    };

    // 清除数据
    excuteCalcu.clearscreen = function() {
        num = 0;
        result = 0;
        numshow = "0";
        calcul = 0;
        $(".numScreen").val("0");
        $(".numScreenSave").html("");
    };

    // 加法
    excuteCalcu.plus = function() {

        //处理重写运算符
        if(flag){
            //只修改运算符状态，不进行运算
            $(".numScreenSave").html($(".numScreenSave").html().substr(0,$(".numScreenSave").html().length-1) + "+");
            operate = 1;
            calcul = 1;
            return;
        }
        calculate(); //调用计算函数
        operate = 1; //更改输入状态
        calcul = 1; //更改计算状态为加
        commandSave();
    };

    // 减法
    excuteCalcu.minus = function() {

        if(flag){
            //只修改运算符状态，不进行运算
            $(".numScreenSave").html($(".numScreenSave").html().substr(0,$(".numScreenSave").html().length-1) + "-");
            operate = 1;
            calcul = 2;
            return;
        }
        calculate();
        operate = 1;
        calcul = 2;
        commandSave();
    };

    // 乘法
    excuteCalcu.times = function() {

        if(flag){
            //只修改运算符状态，不进行运算
            $(".numScreenSave").html($(".numScreenSave").html().substr(0,$(".numScreenSave").html().length-1) + "*");
            operate = 1;
            calcul = 3;
            return;
        }
        calculate();
        operate = 1;
        calcul = 3;
        commandSave();

    };

    // 除法
    excuteCalcu.divide = function() {

        if(flag){
            //只修改运算符状态，不进行运算
            $(".numScreenSave").html($(".numScreenSave").html().substr(0,$(".numScreenSave").html().length-1) + "/");
            operate = 1;
            calcul = 4;
            return;
        }
        calculate();
        operate = 1;
        calcul = 4;
        commandSave();
    };

    //等于
    excuteCalcu.equal = function() {

        //处理不规范按键问题
        var _saveText = $(".numScreenSave").html();
        if(_saveText.substring(_saveText.length - 1) === "="){
            return false;
        }

        if(_saveText.indexOf("+") ==-1 && _saveText.indexOf("-") ==-1 &&  _saveText.indexOf("*") ==-1 && _saveText.indexOf("/") ==-1 && _saveText.indexOf("%") ==-1){
            return false;
        }

        calculate();
        operate = 1;
        result = 0;
        numshow = "0";
        calcul = 0;
        commandSave();
        num = 0;

        $(".numScreen").focus();
        $(".numScreen").select();
    };

    // 清理小数点后的0
    var removeZeroForCal = function (numberStr) {
        var idx = numberStr.indexOf('.');
        if (idx !== -1) {

            var afterNumber = numberStr.substring(idx + 1);
            var size = afterNumber.length;
            for (var i = 0; i < size; i++) {
                if (afterNumber.lastIndexOf('0') === afterNumber.length - 1) {
                    afterNumber = afterNumber.substring(0, afterNumber.length - 1);
                }
                else {
                    break;
                }
            }

            var newNumber = numberStr.substring(0, idx) + '.' + afterNumber;
            if (newNumber.indexOf('.') === newNumber.length - 1) {
                return newNumber.substring(0, newNumber.length - 1);
            }
            return newNumber;
        }
        return numberStr;
    };

    // 执行计算
    var calculate = function() {

        numshow = new Number($(".numScreen").val());

        //处理第一个数为0的计算状态
        if(num !== 0){
            switch (calcul) { //判断要输入状态
                case 1:
                    var a = new BigDecimal(String(num));
                    var b = new BigDecimal(String(numshow));
                    result = a.add(b) + "";
                    break; //计算"+"
                case 2:
                    var a = new BigDecimal(String(num));
                    var b = new BigDecimal(String(numshow));
                    result = a.subtract(b) + "";
                    break; //计算"-"
                case 3:
                    var a = new BigDecimal(String(num));
                    var b = new BigDecimal(String(numshow));
                    result = a.multiply(b) + "";
                    break; //计算"*"
                case 4:
                    if (numshow != 0 && !isNaN(numshow)) {
                        var a = new BigDecimal(String(num));
                        var b = new BigDecimal(String(numshow));
                        result = parseFloat(a.divide(b,12,BigDecimal.ROUND_HALF_EVEN) + "");
                    } else {
                        result = "除数不能为零";
                    }
                    break; //计算"/"

            }

        }else{
            if(calcul == 2){
                var a = new BigDecimal(String(num));
                var b = new BigDecimal(String(numshow));
                result = a.subtract(b) + "";
            }else if(calcul == 3){
                var a = new BigDecimal(String(num));
                var b = new BigDecimal(String(numshow));
                result = a.multiply(b) + "";

            }else if(calcul == 4){
                if (numshow != 0 && !isNaN(numshow)) {
                    var a = new BigDecimal(String(num));
                    var b = new BigDecimal(String(numshow));
                    result = parseFloat(a.divide(b,12,BigDecimal.ROUND_HALF_EVEN) + "");
                } else {
                    result = "除数不能为零";
                }
            }else{
                result = parseFloat(num) + numshow;
            }

        }

        if(calcul == 0){
            numshow = String(result);
            $(".numScreen").val(result);
        }else{
            $(".numScreen").val(numshow);
        }
        num = result; //存储当前值

    };

    return {
        init:init
    }

})();<commit_msg>删除冗余代码<commit_after>/**
 * 计算器
 * Created by suliang on 2016/10/28.
 * v2.0
 * v2.0 modified on 2016.12.29
 */
var calculator = (function(){

    var num = 0, result = 0, numshow = "0";
    var operate = 0; //判断输入状态的标志
    var calcul = 0; //判断计算状态的标志
    var flag = 0; //判断此时的输入状态是数字还是运算符

    // 数字keycode
    var keyCode = {
        "48":0,"96":0,"49":1,"97":1,"50":2,"98":2,"51":3,"99":3,"52":4,"100":4,"53":5,"101":5,"54":6,"102":6,"55":7,"103":7,"56":8,"104":8,"57":9,"105":9
    };

    // 操作keycode
    var excuteCode = {
        "107":"plus",
        "187":"plus",
        "109":"minus",
        "106":"times",
        "110":"dot",
        "111":"divide",
        "108":"equal",
        "13":"equal",
        "46":"delAll",
        "8":"del",
        "27":"clearscreen",
    }

    //初始化
    var init = function(){

        //初始化计算器显示屏
        $(".numScreen").val(0);
        $(".numScreenSave").html("");

        //绑定数字输入点击事件
        $("#useCalculatorBody").find(".number-btn").unbind("click").click(function(){

            var num = $(this).val();
            command(num);

            //防止焦点停留导致键盘输入错误
            $(this).blur();
        });

        //绑定运算符输入点击事件
        $("#useCalculatorBody").find(".tool").unbind("click").click(function(){

            var _excute = $(this).attr("data-excute");
            excuteCalcu[_excute]();

            //防止焦点停留导致键盘输入错误
            $(this).blur();
        });

        if(calculator.index == 0){
            //实现数字键盘
            $(document).on("keydown",function(e){
                if($(e.target).prop("tagName") === "BODY" || $(e.target).hasClass("numScreen")){

                    //执行数字输入
                    if(e.which in keyCode){
                        command(keyCode[e.which]);
                    }

                    //执行运算符输入
                    else if(e.which in excuteCode){
                        excuteCalcu[excuteCode[e.which]]();
                    }
                }
            });

            //修改计算器状态
            calculator.index = 1;
        }
    };

    //计算操作集合
    var excuteCalcu = {};

    //处理当前输入值
    var command = function(num) {

        //获得当前显示数据
        var str = String($(".numScreen").val());

        //如果当前值不是"0"，且状态为0，则返回当前值，否则返回空值;
        if(str !== "0"){
            if(operate !== 0){
                str = "";
            }
        }else{
            str = "";
        }

        //给当前值追加字符
        str = str + String(num);

        //最多输入13位
        if(str.length === 13){
            return false;
        }

        //刷新显示并重置输入状态
        $(".numScreen").val(str);
        operate = 0;
        flag = 0;

    };

    //处理每一步的计算结果
    var commandSave = function(){

        var _numScreen = String($(".numScreen").val());
        var _numScreenSave = $(".numScreenSave").html();

        var str = _numScreenSave + _numScreen;

        //拼接运算符
        switch (calcul) {
            case 1:
                str = str + "+";
                break;
            case 2:
                str = str + "-";
                break;
            case 3:
                str = str + "*";
                break;
            case 4:
                str = str + "/";
                break;
        }

        //处理等于的情况
        if(calcul === 0){

            //只在输入框显示最后结果
            $(".numScreenSave").html("");

            //有小数的情况
            if(String(num).indexOf(".") !== -1){
                if(String(num).indexOf("e") !== -1){
                    num = String(num);
                }else{
                    num = String(num).substr(0,14);
                }
            }

            //没有小数的情况
            else{
                String(num).substr(0,12)
            }
            $(".numScreen").val(num);
        }else{
            $(".numScreenSave").html(str); //刷新显示
            $(".numScreen").val(num);
            flag = 1;
        }

    };

    // 处理两个0情况
    excuteCalcu.dzero = function() {

        var str = String($(".numScreen").val());

        //如果当前值不是"0"，且状态为0，则返回当str+"00"，否则返回"0";
        if(str !== "0"){
            if(operate === 0){
                str = str + "00";
            }else{
                str = "0";
            }
        }else{
            str = "0";
        }
        //最多输入13位
        if(str.length >= 13){
            return false;
        }
        $(".numScreen").val(str);
        operate = 0;
    };

    // 处理小数点情况
    excuteCalcu.dot = function() {

        var str = String($(".numScreen").val());

        //如果当前值不是"0"，且状态为0，则返回当前值，否则返回"0";
        if(str !== "0"){
            if(operate !== 0){
                str = "0";
            }
        }else{
            str = "0";
        }

        //判断是否已经有一个点号,如果有则不再插入
        for (i = 0; i <= str.length; i++) {
            if (str.substr(i, 1) == ".") {
                return false;
            }
        }

        str = str + ".";
        $(".numScreen").val(str);
        operate = 0;
    };

    // 退格
    excuteCalcu.del = function() {

        var str = String($(".numScreen").val());
        str = (str != "0") ? str : "";
        str = str.substr(0, str.length - 1);
        str = (str != "") ? str : "0";
        $(".numScreen").val(str);
    };

    // 全删
    excuteCalcu.delAll = function() {
        $(".numScreen").val(0);
    };

    // 清除数据
    excuteCalcu.clearscreen = function() {
        num = 0;
        result = 0;
        numshow = "0";
        calcul = 0;
        $(".numScreen").val("0");
        $(".numScreenSave").html("");
    };

    // 加法
    excuteCalcu.plus = function() {

        //处理重写运算符
        if(flag){
            //只修改运算符状态，不进行运算
            $(".numScreenSave").html($(".numScreenSave").html().substr(0,$(".numScreenSave").html().length-1) + "+");
            operate = 1;
            calcul = 1;
            return;
        }
        calculate(); //调用计算函数
        operate = 1; //更改输入状态
        calcul = 1; //更改计算状态为加
        commandSave();
    };

    // 减法
    excuteCalcu.minus = function() {

        if(flag){
            //只修改运算符状态，不进行运算
            $(".numScreenSave").html($(".numScreenSave").html().substr(0,$(".numScreenSave").html().length-1) + "-");
            operate = 1;
            calcul = 2;
            return;
        }
        calculate();
        operate = 1;
        calcul = 2;
        commandSave();
    };

    // 乘法
    excuteCalcu.times = function() {

        if(flag){
            //只修改运算符状态，不进行运算
            $(".numScreenSave").html($(".numScreenSave").html().substr(0,$(".numScreenSave").html().length-1) + "*");
            operate = 1;
            calcul = 3;
            return;
        }
        calculate();
        operate = 1;
        calcul = 3;
        commandSave();

    };

    // 除法
    excuteCalcu.divide = function() {

        if(flag){
            //只修改运算符状态，不进行运算
            $(".numScreenSave").html($(".numScreenSave").html().substr(0,$(".numScreenSave").html().length-1) + "/");
            operate = 1;
            calcul = 4;
            return;
        }
        calculate();
        operate = 1;
        calcul = 4;
        commandSave();
    };

    //等于
    excuteCalcu.equal = function() {

        //处理不规范按键问题
        var _saveText = $(".numScreenSave").html();
        if(_saveText.substring(_saveText.length - 1) === "="){
            return false;
        }

        if(_saveText.indexOf("+") ==-1 && _saveText.indexOf("-") ==-1 &&  _saveText.indexOf("*") ==-1 && _saveText.indexOf("/") ==-1 && _saveText.indexOf("%") ==-1){
            return false;
        }

        calculate();
        operate = 1;
        result = 0;
        numshow = "0";
        calcul = 0;
        commandSave();
        num = 0;

        $(".numScreen").focus();
        $(".numScreen").select();
    };

    // 清理小数点后的0
    var removeZeroForCal = function (numberStr) {
        var idx = numberStr.indexOf('.');
        if (idx !== -1) {

            var afterNumber = numberStr.substring(idx + 1);
            var size = afterNumber.length;
            for (var i = 0; i < size; i++) {
                if (afterNumber.lastIndexOf('0') === afterNumber.length - 1) {
                    afterNumber = afterNumber.substring(0, afterNumber.length - 1);
                }
                else {
                    break;
                }
            }

            var newNumber = numberStr.substring(0, idx) + '.' + afterNumber;
            if (newNumber.indexOf('.') === newNumber.length - 1) {
                return newNumber.substring(0, newNumber.length - 1);
            }
            return newNumber;
        }
        return numberStr;
    };

    // 执行计算
    var calculate = function() {

        numshow = new Number($(".numScreen").val());

        //处理第一个数为0的计算状态
        if(num !== 0){
            switch (calcul) { //判断要输入状态
                case 1:
                    var a = new BigDecimal(String(num));
                    var b = new BigDecimal(String(numshow));
                    result = a.add(b) + "";
                    break; //计算"+"
                case 2:
                    var a = new BigDecimal(String(num));
                    var b = new BigDecimal(String(numshow));
                    result = a.subtract(b) + "";
                    break; //计算"-"
                case 3:
                    var a = new BigDecimal(String(num));
                    var b = new BigDecimal(String(numshow));
                    result = a.multiply(b) + "";
                    break; //计算"*"
                case 4:
                    if (numshow != 0 && !isNaN(numshow)) {
                        var a = new BigDecimal(String(num));
                        var b = new BigDecimal(String(numshow));
                        result = parseFloat(a.divide(b,12,BigDecimal.ROUND_HALF_EVEN) + "");
                    } else {
                        result = "除数不能为零";
                    }
                    break; //计算"/"

            }

        }else{
            if(calcul == 2){
                var a = new BigDecimal(String(num));
                var b = new BigDecimal(String(numshow));
                result = a.subtract(b) + "";
            }else if(calcul == 3){
                var a = new BigDecimal(String(num));
                var b = new BigDecimal(String(numshow));
                result = a.multiply(b) + "";

            }else if(calcul == 4){
                if (numshow != 0 && !isNaN(numshow)) {
                    var a = new BigDecimal(String(num));
                    var b = new BigDecimal(String(numshow));
                    result = parseFloat(a.divide(b,12,BigDecimal.ROUND_HALF_EVEN) + "");
                } else {
                    result = "除数不能为零";
                }
            }else{
                result = parseFloat(num) + numshow;
            }

        }

        if(calcul == 0){
            numshow = String(result);
            $(".numScreen").val(result);
        }else{
            $(".numScreen").val(numshow);
        }
        num = result; //存储当前值

    };

    return {
        init:init
    }

})();<|endoftext|>