<commit_before>
VVVV = {}
VVVV.Types = {}

VVVV.Types.Color = function(r, g, b, a) {
  this.rgba = [r, g, b, a];

  this.toString = function() {
    return "r="+(r*100)+"% "+"g="+(g*100)+"% "+"b="+(b*100)+"% "+"a="+(a*100)+"%";
  }
}

VVVV.Core = {

  Pin: function(pinname, values, node) {
    this.pinname = pinname;
    this.links = [];
    this.values = values;
    this.node = node;
    this.changed = true;
    this.active = false;

    this.getValue = function(i) {
      //if (this.values.length===0)
      //  return "not calculated";
      return this.values[i%this.values.length];
    }

    this.setValue = function(i, v) {
      this.values[i] = v;
      this.changed = true;
      _(this.links).each(function(l) {
        l.toPin.values[i] = v;
        l.toPin.changed = true;
      });
    }

    this.pinIsChanged = function() {
      var ret = this.changed;
      this.changed = false;
      return ret;
    }

    this.getSliceCount = function() {
      return this.values.length;
    }
  },

  Node: function(id, nodename, graph) {

    this.nodename = nodename;
    this.id = id;
    this.x = 0;
    this.y = 0;
    this.width = 0;
    this.height = 0;
    this.isIOBox = false;
    this.isShader = false;

    this.inputPins = {};
    this.outputPins = {};
    this.invisiblePins = [];

    this.graph = graph;
    if (graph)
      this.graph.nodeMap[id] = this;

    this.addInputPin = function(pinname, value) {
      pin = new VVVV.Core.Pin(pinname, value, this);
      this.inputPins[pinname] = pin;
      this.graph.pinMap[this.id+'_'+pinname] = pin;
      return pin;
    }

    this.addOutputPin = function(pinname, value) {
      pin = new VVVV.Core.Pin(pinname, value, this);
      this.outputPins[pinname] = pin;
      this.graph.pinMap[this.id+'_'+pinname] = pin;
      return pin;
    }

    this.addInvisiblePin = function(pinname, value) {
      pin = new VVVV.Core.Pin(pinname, value, this);
      this.invisiblePins.push(pin);
      this.graph.pinMap[this.id+'_'+pinname] = pin;
      return pin;
    }

    this.IOBoxType = function() {
      match = /^IOBox \((.*)\)/.exec(this.nodename);
      if (match && match.length>1)
        return match[1];
      return "";
    }

    this.IOBoxInputPin = function() {
      switch (this.IOBoxType()) {
        case "Value Advanced":
          return this.inputPins["Y Input Value"];
        case "String":
          return this.inputPins["Input String"];
      }
      return undefined;
    }

    this.IOBoxOutputPin = function() {
      switch (this.IOBoxType()) {
        case "Value Advanced":
          return this.outputPins["Y Output Value"];
        case "String":
          return this.outputPins["Output String"];
      }
      return undefined;
    }

    this.IOBoxRows = function() {
      if (this.graph.pinMap[this.id+"_Rows"])
        return this.graph.pinMap[this.id+"_Rows"].getValue(0);
      else
        return 1;
    }

    this.isComment = function() {
      return this.isIOBox && _(this.outputPins).size()==0 && this.invisiblePins.length==1
    }

    this.label = function() {
      if (this.isIOBox) {
        return this.IOBoxInputPin().getValue(0);
      }

      label = this.nodename.replace(/\s\(.+\)/, '');
      switch (label) {
        case "Add": return "+";
        case "Subtract": return "-";
        case "Multiply": return "*";
        case "Divide": return "/";
        case "EQ": return "=";
        default: return label;
      }

    }

    this.getWidth = function() {
      var ret;
      if (this.width==100 || this.width==0)
        ret = Math.max(18, (this.label().length+2)*6);
      else
        ret = this.width/15;
      ret = Math.max(ret, (_(this.inputPins).size()-1)*12+4);
      return ret;
    }

    this.getHeight = function() {
      if (this.height==100)
        return 18;
      else
        return Math.max(18, this.height/15);
    }

    this.getUpstreamNodes = function() {
      var ret = [];
      _(this.inputPins).each(function(p) {
        for (var j=0; j<p.links.length; j++) {
          ret.push(p.links[j].fromPin.node);
        }
      });
      return ret;
    }

    this.getDownstreamNodes = function() {
      var ret = [];
      _(this.outputPins).each(function(p) {
        for (var j=0; j<p.links.length; j++) {
          ret.push(p.links[j].toPin.node);
        }
      });
      return ret;
    }

    this.getMaxInputSliceCount = function() {
      var ret = 0;
      _(this.inputPins).each(function(p) {
        if (p.values.length>ret)
          ret = p.values.length;
      });
      return ret;
    }

    this.initialize = function() {

    }

    this.evaluate = function() {
      var that = this;
      _(this.outputPins).each(function(p) {
        p.setValue(0, "not calculated");
      });
    }

  },

  Link: function(fromPin, toPin) {
    this.fromPin = fromPin;
    this.toPin = toPin;

    this.fromPin.links.push(this);
    this.toPin.links.push(this);
  },

  Graph: function(xml) {
    this.pinMap = {};
    this.nodeMap = {};
    this.nodeList = [];
    this.linkList = [];
    this.nodeLibrary = {};

    function splitValues(v) {
      if (v==undefined)
        return [];
      if (/\|/.test(v))
        separator = "|";
      else
        separator = ",";
      return v.split(separator).filter(function(d,i) { return d!=""});
    }

    var thisGraph = this;

    _(VVVV.Nodes).each(function(n) {
      var x = new n(0, thisGraph);
      console.log("Registering "+x.nodename);
      thisGraph.nodeLibrary[x.nodename] = n;
    });

    $windowBounds = $(xml).find('patch > bounds[type="Window"]').first();
    if ($windowBounds.length>0) {
      this.width = $windowBounds.attr('width')/15;
      this.height = $windowBounds.attr('height')/15;
    }
    else {
      this.width = 500;
      this.height = 500;
    }

    $(xml).find('node').each(function() {
      if ($(this).attr('componentmode')=="InABox")
        $bounds = $(this).find('bounds[type="Box"]').first();
      else
        $bounds = $(this).find('bounds[type="Node"]').first();

      nodename = $(this).attr('systemname')!="" ? $(this).attr('systemname') : $(this).attr('nodename');
      if (nodename==undefined)
        return;
      thisGraph.width = Math.max(thisGraph.width, $bounds.attr('left')/15+100);
      thisGraph.height = Math.max(thisGraph.height, $bounds.attr('top')/15+25);

      if (thisGraph.nodeLibrary[nodename]!=undefined)
        var n = new thisGraph.nodeLibrary[nodename]($(this).attr('id'), thisGraph);
      else
        var n = new VVVV.Core.Node($(this).attr('id'), nodename, thisGraph);
      n.x = $bounds.attr('left')/15;
      n.y = $bounds.attr('top')/15;
      n.width = $bounds.attr('width');
      n.height = $bounds.attr('height');

      if (/^IOBox/.test(nodename))
        n.isIOBox = true;
      if (/\.fx$/.test($(this).attr('nodename')))
        n.isShader = true;

      var that = this;
      $(this).find('pin').each(function() {
        pinname = $(this).attr('pinname');
        values = splitValues($(this).attr('values'));
        if (n.outputPins[pinname]!=undefined)
          return;
        if (n.inputPins[pinname]!=undefined) {
          if (values!=undefined)
            n.inputPins[pinname].values = values;
        }
        if ($(this).attr('visible')==1 || $(this).attr('slicecount')!=undefined)
        {
          if ($(xml).find('link[srcnodeid='+n.id+']').filter('link[srcpinname='+pinname.replace(/[\[\]]/,'')+']').length > 0)
            n.addOutputPin(pinname, values);
          else
            n.addInputPin(pinname, values);
        }
        else
          n.addInvisiblePin(pinname, values);
      });

      n.initialize();
      thisGraph.nodeList.push(n);
    });

    $(xml).find('link').each(function() {
      srcPin = thisGraph.pinMap[$(this).attr('srcnodeid')+'_'+$(this).attr('srcpinname')];
      dstPin = thisGraph.pinMap[$(this).attr('dstnodeid')+'_'+$(this).attr('dstpinname')];

      if (srcPin==undefined)
        srcPin = thisGraph.nodeMap[$(this).attr('srcnodeid')].addOutputPin($(this).attr('srcpinname'), undefined);
      if (dstPin==undefined)
        dstPin = thisGraph.nodeMap[$(this).attr('dstnodeid')].addInputPin($(this).attr('dstpinname'), undefined);

      thisGraph.linkList.push(new VVVV.Core.Link(srcPin, dstPin));
    });

    this.afterEvaluate = function() {

    }

    this.evaluate = function() {
      var todoNodes = {};
      for (var i=0; i<this.nodeList.length; i++) {
        todoNodes[this.nodeList[i].id] = this.nodeList[i];
      }

      function evaluateSubGraph(node) {

        //console.log("starting with "+node.nodename);
        var upstreamNodesInvalid = false;
        upstreamNodes = node.getUpstreamNodes();
        _(upstreamNodes).each(function(upnode) {
          //console.log('testing '+upnode.nodename);
          if (todoNodes[upnode.id]!=undefined) {
            upstreamNodesInvalid = true;
            //console.log(upnode.nodename+' is still invalid ..');
          }
        });
        if (upstreamNodesInvalid) {
          //console.log('upstream nodes still invalid');
          return false;
        }
        //console.log('upstream nodes valid, calculating and deleting '+node.nodename);

        node.evaluate();

        /**
         *_(node.getDownstreamNodes()).each(function(downnode) {
         *  evaluateSubGraph(downnode);
         *});
         */

        delete todoNodes[node.id];
        return true;
      }

      while (_(todoNodes).size() > 0) {
        _(todoNodes).each(function(n, id, index) {
          evaluateSubGraph(n);
        });
      }

      this.afterEvaluate();

    }
  }
}<commit_msg>fixed bug where pins where created two times (one because of xml and one because of node construction<commit_after>
VVVV = {}
VVVV.Types = {}

VVVV.Types.Color = function(r, g, b, a) {
  this.rgba = [r, g, b, a];

  this.toString = function() {
    return "r="+(r*100)+"% "+"g="+(g*100)+"% "+"b="+(b*100)+"% "+"a="+(a*100)+"%";
  }
}

VVVV.Core = {

  Pin: function(pinname, values, node) {
    this.pinname = pinname;
    this.links = [];
    this.values = values;
    this.node = node;
    this.changed = true;
    this.active = false;

    this.getValue = function(i) {
      //if (this.values.length===0)
      //  return "not calculated";
      return this.values[i%this.values.length];
    }

    this.setValue = function(i, v) {
      this.values[i] = v;
      this.changed = true;
      _(this.links).each(function(l) {
        l.toPin.values[i] = v;
        l.toPin.changed = true;
      });
    }

    this.pinIsChanged = function() {
      var ret = this.changed;
      //if (this.node.nodename=='LinearFilter (Animation)') {
      //  console.log("querying pinchanged for "+this.pinname+' of node '+this.node.id+' to changed...');
      //  if (ret)
      //    console.log("it changed! resetting it, though...");
      //}
      this.changed = false;
      return ret;
    }

    this.getSliceCount = function() {
      return this.values.length;
    }
  },

  Node: function(id, nodename, graph) {

    this.nodename = nodename;
    this.id = id;
    this.x = 0;
    this.y = 0;
    this.width = 0;
    this.height = 0;
    this.isIOBox = false;
    this.isShader = false;

    this.inputPins = {};
    this.outputPins = {};
    this.invisiblePins = [];

    this.graph = graph;
    if (graph)
      this.graph.nodeMap[id] = this;

    this.addInputPin = function(pinname, value) {
      pin = new VVVV.Core.Pin(pinname, value, this);
      this.inputPins[pinname] = pin;
      this.graph.pinMap[this.id+'_'+pinname] = pin;
      return pin;
    }

    this.addOutputPin = function(pinname, value) {
      pin = new VVVV.Core.Pin(pinname, value, this);
      this.outputPins[pinname] = pin;
      this.graph.pinMap[this.id+'_'+pinname] = pin;
      return pin;
    }

    this.addInvisiblePin = function(pinname, value) {
      pin = new VVVV.Core.Pin(pinname, value, this);
      this.invisiblePins.push(pin);
      this.graph.pinMap[this.id+'_'+pinname] = pin;
      return pin;
    }

    this.IOBoxType = function() {
      match = /^IOBox \((.*)\)/.exec(this.nodename);
      if (match && match.length>1)
        return match[1];
      return "";
    }

    this.IOBoxInputPin = function() {
      switch (this.IOBoxType()) {
        case "Value Advanced":
          return this.inputPins["Y Input Value"];
        case "String":
          return this.inputPins["Input String"];
      }
      return undefined;
    }

    this.IOBoxOutputPin = function() {
      switch (this.IOBoxType()) {
        case "Value Advanced":
          return this.outputPins["Y Output Value"];
        case "String":
          return this.outputPins["Output String"];
      }
      return undefined;
    }

    this.IOBoxRows = function() {
      if (this.graph.pinMap[this.id+"_Rows"])
        return this.graph.pinMap[this.id+"_Rows"].getValue(0);
      else
        return 1;
    }

    this.isComment = function() {
      return this.isIOBox && _(this.outputPins).size()==0 && this.invisiblePins.length==1
    }

    this.label = function() {
      if (this.isIOBox) {
        return this.IOBoxInputPin().getValue(0);
      }

      label = this.nodename.replace(/\s\(.+\)/, '');
      switch (label) {
        case "Add": return "+";
        case "Subtract": return "-";
        case "Multiply": return "*";
        case "Divide": return "/";
        case "EQ": return "=";
        default: return label;
      }

    }

    this.getWidth = function() {
      var ret;
      if (this.width==100 || this.width==0)
        ret = Math.max(18, (this.label().length+2)*6);
      else
        ret = this.width/15;
      ret = Math.max(ret, (_(this.inputPins).size()-1)*12+4);
      return ret;
    }

    this.getHeight = function() {
      if (this.height==100)
        return 18;
      else
        return Math.max(18, this.height/15);
    }

    this.getUpstreamNodes = function() {
      var ret = [];
      _(this.inputPins).each(function(p) {
        for (var j=0; j<p.links.length; j++) {
          ret.push(p.links[j].fromPin.node);
        }
      });
      return ret;
    }

    this.getDownstreamNodes = function() {
      var ret = [];
      _(this.outputPins).each(function(p) {
        for (var j=0; j<p.links.length; j++) {
          ret.push(p.links[j].toPin.node);
        }
      });
      return ret;
    }

    this.getMaxInputSliceCount = function() {
      var ret = 0;
      _(this.inputPins).each(function(p) {
        if (p.values.length>ret)
          ret = p.values.length;
      });
      return ret;
    }

    this.initialize = function() {

    }

    this.evaluate = function() {
      var that = this;
      _(this.outputPins).each(function(p) {
        p.setValue(0, "not calculated");
      });
    }

  },

  Link: function(fromPin, toPin) {
    this.fromPin = fromPin;
    this.toPin = toPin;

    this.fromPin.links.push(this);
    this.toPin.links.push(this);
  },

  Graph: function(xml) {
    this.pinMap = {};
    this.nodeMap = {};
    this.nodeList = [];
    this.linkList = [];
    this.nodeLibrary = {};

    function splitValues(v) {
      if (v==undefined)
        return [];
      if (/\|/.test(v))
        separator = "|";
      else
        separator = ",";
      return v.split(separator).filter(function(d,i) { return d!=""});
    }

    var thisGraph = this;

    _(VVVV.Nodes).each(function(n) {
      var x = new n(0, thisGraph);
      console.log("Registering "+x.nodename);
      thisGraph.nodeLibrary[x.nodename] = n;
    });

    $windowBounds = $(xml).find('patch > bounds[type="Window"]').first();
    if ($windowBounds.length>0) {
      this.width = $windowBounds.attr('width')/15;
      this.height = $windowBounds.attr('height')/15;
    }
    else {
      this.width = 500;
      this.height = 500;
    }

    $(xml).find('node').each(function() {
      if ($(this).attr('componentmode')=="InABox")
        $bounds = $(this).find('bounds[type="Box"]').first();
      else
        $bounds = $(this).find('bounds[type="Node"]').first();

      nodename = $(this).attr('systemname')!="" ? $(this).attr('systemname') : $(this).attr('nodename');
      if (nodename==undefined)
        return;
      thisGraph.width = Math.max(thisGraph.width, $bounds.attr('left')/15+100);
      thisGraph.height = Math.max(thisGraph.height, $bounds.attr('top')/15+25);

      if (thisGraph.nodeLibrary[nodename]!=undefined)
        var n = new thisGraph.nodeLibrary[nodename]($(this).attr('id'), thisGraph);
      else
        var n = new VVVV.Core.Node($(this).attr('id'), nodename, thisGraph);
      n.x = $bounds.attr('left')/15;
      n.y = $bounds.attr('top')/15;
      n.width = $bounds.attr('width');
      n.height = $bounds.attr('height');

      if (/^IOBox/.test(nodename))
        n.isIOBox = true;
      if (/\.fx$/.test($(this).attr('nodename')))
        n.isShader = true;

      var that = this;
      $(this).find('pin').each(function() {
        pinname = $(this).attr('pinname');
        values = splitValues($(this).attr('values'));
        if (n.outputPins[pinname]!=undefined)
          return;
        if (n.inputPins[pinname]!=undefined) {
          if (values!=undefined)
            n.inputPins[pinname].values = values;
          return;
        }
        if ($(this).attr('visible')==1 || $(this).attr('slicecount')!=undefined)
        {
          if ($(xml).find('link[srcnodeid='+n.id+']').filter('link[srcpinname='+pinname.replace(/[\[\]]/,'')+']').length > 0) // if it's an input pin
            n.addOutputPin(pinname, values);
          else
            n.addInputPin(pinname, values);
        }
        else
          n.addInvisiblePin(pinname, values);
      });

      n.initialize();
      thisGraph.nodeList.push(n);
    });

    $(xml).find('link').each(function() {
      srcPin = thisGraph.pinMap[$(this).attr('srcnodeid')+'_'+$(this).attr('srcpinname')];
      dstPin = thisGraph.pinMap[$(this).attr('dstnodeid')+'_'+$(this).attr('dstpinname')];

      if (srcPin==undefined)
        srcPin = thisGraph.nodeMap[$(this).attr('srcnodeid')].addOutputPin($(this).attr('srcpinname'), undefined);
      if (dstPin==undefined)
        dstPin = thisGraph.nodeMap[$(this).attr('dstnodeid')].addInputPin($(this).attr('dstpinname'), undefined);

      thisGraph.linkList.push(new VVVV.Core.Link(srcPin, dstPin));
    });

    this.afterEvaluate = function() {

    }

    this.evaluate = function() {
      var todoNodes = {};
      for (var i=0; i<this.nodeList.length; i++) {
        todoNodes[this.nodeList[i].id] = this.nodeList[i];
      }

      function evaluateSubGraph(node) {

        //console.log("starting with "+node.nodename);
        var upstreamNodesInvalid = false;
        upstreamNodes = node.getUpstreamNodes();
        _(upstreamNodes).each(function(upnode) {
          //console.log('testing '+upnode.nodename);
          if (todoNodes[upnode.id]!=undefined) {
            upstreamNodesInvalid = true;
            //console.log(upnode.nodename+' is still invalid ..');
          }
        });
        if (upstreamNodesInvalid) {
          //console.log('upstream nodes still invalid');
          return false;
        }
        //console.log('upstream nodes valid, calculating and deleting '+node.nodename);

        node.evaluate();

        /**
         *_(node.getDownstreamNodes()).each(function(downnode) {
         *  evaluateSubGraph(downnode);
         *});
         */

        delete todoNodes[node.id];
        return true;
      }

      while (_(todoNodes).size() > 0) {
        _(todoNodes).each(function(n, id, index) {
          evaluateSubGraph(n);
        });
      }

      this.afterEvaluate();

    }
  }
}<|endoftext|>


<commit_before>const topojson = require('topojson-client'),
  toGeoJSON = require('@tmcw/togeojson'),
  gtfs2geojson = require('gtfs2geojson'),
  csv2geojson = require('csv2geojson'),
  osmtogeojson = require('osmtogeojson'),
  polytogeojson = require('polytogeojson'),
  geojsonNormalize = require('@mapbox/geojson-normalize');

module.exports.readDrop = readDrop;
module.exports.readAsText = readAsText;
module.exports.readFile = readFile;

function readDrop(callback) {
  return function () {
    const results = [];
    const errors = [];
    if (
      d3.event.dataTransfer &&
      d3.event.dataTransfer &&
      d3.event.dataTransfer.files &&
      d3.event.dataTransfer.files.length
    ) {
      d3.event.stopPropagation();
      d3.event.preventDefault();
      let remaining = d3.event.dataTransfer.files.length;
      [].forEach.call(d3.event.dataTransfer.files, (f) => {
        readAsText(f, (err, text) => {
          if (err) {
            errors.push(err);
            if (!--remaining) finish(errors, results);
          } else {
            readFile(f, text, (err, res, war) => {
              if (err) errors.push(err);
              if (res) results.push(res);
              if (war) results.push(war);
              if (!--remaining) finish(errors, results, war);
            });
          }
        });
      });
    } else {
      return callback({
        message: 'No files were dropped'
      });
    }

    function finish(errors, results, war) {
      // if no conversions suceeded, return the first error
      if (!results.length && errors.length)
        return callback(errors[0], null, war);
      // otherwise combine results
      return callback(
        null,
        {
          type: 'FeatureCollection',
          features: results.reduce((memo, r) => {
            r = geojsonNormalize(r);
            if (r) {
              memo = memo.concat(r.features);
            }
            return memo;
          }, [])
        },
        war
      );
    }
  };
}

function readAsText(f, callback) {
  try {
    const reader = new FileReader();
    reader.readAsText(f);
    reader.onload = function (e) {
      if (e.target && e.target.result) callback(null, e.target.result);
      else
        callback({
          message: 'Dropped file could not be loaded'
        });
    };
    reader.onerror = function () {
      callback({
        message: 'Dropped file was unreadable'
      });
    };
  } catch (e) {
    callback({
      message: 'Dropped file was unreadable'
    });
  }
}

function readFile(f, text, callback) {
  const fileType = detectType(f, text);

  if (!fileType) {
    return callback({
      message: 'Could not detect file type'
    });
  } else if (fileType === 'kml') {
    const kmldom = toDom(text);
    if (!kmldom) {
      return callback({
        message: 'Invalid KML file: not valid XML'
      });
    }
    let warning;
    if (kmldom.getElementsByTagName('NetworkLink').length) {
      warning = {
        message:
          'The KML file you uploaded included NetworkLinks: some content may not display. ' +
          'Please export and upload KML without NetworkLinks for optimal performance'
      };
    }
    callback(null, toGeoJSON.kml(kmldom), warning);
  } else if (fileType === 'xml') {
    const xmldom = toDom(text);
    if (!xmldom) {
      return callback({
        message: 'Invalid XML file: not valid XML'
      });
    }
    const result = osmtogeojson.toGeojson(xmldom);
    // only keep object tags as properties
    result.features.forEach((feature) => {
      feature.properties = feature.properties.tags;
    });
    callback(null, result);
  } else if (fileType === 'gpx') {
    callback(null, toGeoJSON.gpx(toDom(text)));
  } else if (fileType === 'geojson') {
    try {
      const gj = JSON.parse(text);
      if (gj && gj.type === 'Topology' && gj.objects) {
        const collection = { type: 'FeatureCollection', features: [] };
        for (const o in gj.objects) {
          const ft = topojson.feature(gj, gj.objects[o]);
          if (ft.features)
            collection.features = collection.features.concat(ft.features);
          else collection.features = collection.features.concat([ft]);
        }
        return callback(null, collection);
      } else {
        return callback(null, gj);
      }
    } catch (err) {
      alert('Invalid JSON file: ' + err);
      return;
    }
  } else if (fileType === 'dsv') {
    csv2geojson.csv2geojson(
      text,
      {
        delimiter: 'auto'
      },
      (err, result) => {
        if (err) {
          return callback({
            type: 'geocode',
            result: result,
            raw: text
          });
        } else {
          return callback(null, result);
        }
      }
    );
  } else if (fileType === 'gtfs-shapes') {
    try {
      return callback(null, gtfs2geojson.lines(text));
    } catch (e) {
      console.log(e);
      return callback({ message: 'Invalid GTFS shapes.txt file' });
    }
  } else if (fileType === 'gtfs-stops') {
    try {
      return callback(null, gtfs2geojson.stops(text));
    } catch (e) {
      return callback({ message: 'Invalid GTFS stops.txt file' });
    }
  } else if (fileType === 'poly') {
    callback(null, polytogeojson(text));
  }

  function toDom(x) {
    return new DOMParser().parseFromString(x, 'text/xml');
  }

  function detectType(f, text) {
    const filename = f.name ? f.name.toLowerCase() : '';
    function ext(_) {
      return filename.indexOf(_) !== -1;
    }
    if (f.type === 'application/vnd.google-earth.kml+xml' || ext('.kml')) {
      return 'kml';
    }
    if (ext('.gpx')) return 'gpx';
    if (ext('.geojson') || ext('.json') || ext('.topojson')) return 'geojson';
    if (f.type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) {
      return 'dsv';
    }
    if (ext('.xml') || ext('.osm')) return 'xml';
    if (ext('.poly')) return 'poly';
    if (text && text.indexOf('shape_id,shape_pt_lat,shape_pt_lon') !== -1) {
      return 'gtfs-shapes';
    }
    if (
      text &&
      text.indexOf(
        'stop_id,stop_code,stop_name,stop_desc,stop_lat,stop_lon'
      ) !== -1
    ) {
      return 'gtfs-stops';
    }
  }
}
<commit_msg>Update src/lib/readfile.js<commit_after>const topojson = require('topojson-client'),
  toGeoJSON = require('@tmcw/togeojson'),
  gtfs2geojson = require('gtfs2geojson'),
  csv2geojson = require('csv2geojson'),
  osmtogeojson = require('osmtogeojson'),
  polytogeojson = require('polytogeojson'),
  geojsonNormalize = require('@mapbox/geojson-normalize');

module.exports.readDrop = readDrop;
module.exports.readAsText = readAsText;
module.exports.readFile = readFile;

function readDrop(callback) {
  return function () {
    const results = [];
    const errors = [];
    if (
      d3.event.dataTransfer &&
      d3.event.dataTransfer &&
      d3.event.dataTransfer.files &&
      d3.event.dataTransfer.files.length
    ) {
      d3.event.stopPropagation();
      d3.event.preventDefault();
      let remaining = d3.event.dataTransfer.files.length;
      [].forEach.call(d3.event.dataTransfer.files, (f) => {
        readAsText(f, (err, text) => {
          if (err) {
            errors.push(err);
            if (!--remaining) finish(errors, results);
          } else {
            readFile(f, text, (err, res, war) => {
              if (err) errors.push(err);
              if (res) results.push(res);
              if (war) results.push(war);
              if (!--remaining) finish(errors, results, war);
            });
          }
        });
      });
    } else {
      return callback({
        message: 'No files were dropped'
      });
    }

    function finish(errors, results, war) {
      // if no conversions suceeded, return the first error
      if (!results.length && errors.length)
        return callback(errors[0], null, war);
      // otherwise combine results
      return callback(
        null,
        {
          type: 'FeatureCollection',
          features: results.reduce((memo, r) => {
            r = geojsonNormalize(r);
            if (r) {
              memo = memo.concat(r.features);
            }
            return memo;
          }, [])
        },
        war
      );
    }
  };
}

function readAsText(f, callback) {
  try {
    const reader = new FileReader();
    reader.readAsText(f);
    reader.onload = function (e) {
      if (e.target && e.target.result) callback(null, e.target.result);
      else
        callback({
          message: 'Dropped file could not be loaded'
        });
    };
    reader.onerror = function () {
      callback({
        message: 'Dropped file was unreadable'
      });
    };
  } catch (e) {
    callback({
      message: 'Dropped file was unreadable'
    });
  }
}

function readFile(f, text, callback) {
  const fileType = detectType(f, text);

  if (!fileType) {
    return callback({
      message: 'Could not detect file type'
    });
  } else if (fileType === 'kml') {
    const kmldom = toDom(text);
    if (!kmldom) {
      return callback({
        message: 'Invalid KML file: not valid XML'
      });
    }
    let warning;
    if (kmldom.getElementsByTagName('NetworkLink').length) {
      warning = {
        message:
          'The KML file you uploaded included NetworkLinks: some content may not display. ' +
          'Please export and upload KML without NetworkLinks for optimal performance'
      };
    }
    callback(null, toGeoJSON.kml(kmldom), warning);
  } else if (fileType === 'xml') {
    const xmldom = toDom(text);
    if (!xmldom) {
      return callback({
        message: 'Invalid XML file: not valid XML'
      });
    }
    const result = osmtogeojson.toGeojson(xmldom);
    // only keep object tags as properties
    result.features.forEach((feature) => {
      feature.properties = feature.properties.tags;
    });
    callback(null, result);
  } else if (fileType === 'gpx') {
    callback(null, toGeoJSON.gpx(toDom(text)));
  } else if (fileType === 'geojson') {
    try {
      const gj = JSON.parse(text);
      if (gj && gj.type === 'Topology' && gj.objects) {
        const collection = { type: 'FeatureCollection', features: [] };
        for (const o in gj.objects) {
          const ft = topojson.feature(gj, gj.objects[o]);
          if (ft.features)
            collection.features = collection.features.concat(ft.features);
          else collection.features = collection.features.concat([ft]);
        }
        return callback(null, collection);
      } else {
        return callback(null, gj);
      }
    } catch (err) {
      alert('Invalid JSON file: ' + err);
      return;
    }
  } else if (fileType === 'dsv') {
    csv2geojson.csv2geojson(
      text,
      {
        delimiter: 'auto'
      },
      (err, result) => {
        if (err) {
          return callback({
            type: 'geocode',
            result: result,
            raw: text
          });
        } else {
          return callback(null, result);
        }
      }
    );
  } else if (fileType === 'gtfs-shapes') {
    try {
      return callback(null, gtfs2geojson.lines(text));
    } catch (e) {
      return callback({ message: 'Invalid GTFS shapes.txt file' });
    }
  } else if (fileType === 'gtfs-stops') {
    try {
      return callback(null, gtfs2geojson.stops(text));
    } catch (e) {
      return callback({ message: 'Invalid GTFS stops.txt file' });
    }
  } else if (fileType === 'poly') {
    callback(null, polytogeojson(text));
  }

  function toDom(x) {
    return new DOMParser().parseFromString(x, 'text/xml');
  }

  function detectType(f, text) {
    const filename = f.name ? f.name.toLowerCase() : '';
    function ext(_) {
      return filename.indexOf(_) !== -1;
    }
    if (f.type === 'application/vnd.google-earth.kml+xml' || ext('.kml')) {
      return 'kml';
    }
    if (ext('.gpx')) return 'gpx';
    if (ext('.geojson') || ext('.json') || ext('.topojson')) return 'geojson';
    if (f.type === 'text/csv' || ext('.csv') || ext('.tsv') || ext('.dsv')) {
      return 'dsv';
    }
    if (ext('.xml') || ext('.osm')) return 'xml';
    if (ext('.poly')) return 'poly';
    if (text && text.indexOf('shape_id,shape_pt_lat,shape_pt_lon') !== -1) {
      return 'gtfs-shapes';
    }
    if (
      text &&
      text.indexOf(
        'stop_id,stop_code,stop_name,stop_desc,stop_lat,stop_lon'
      ) !== -1
    ) {
      return 'gtfs-stops';
    }
  }
}
<|endoftext|>


<commit_before>/**
 * GoogleChart component.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import { debounce } from 'lodash';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useEffect, useState, useRef, useCallback } from '@wordpress/element';

/**
 * Internal dependencies
 */
import ProgressBar from './ProgressBar';

let chartLoadPromise;

async function loadCharts() {
	if ( chartLoadPromise ) {
		return chartLoadPromise;
	}

	// Inject the script if not already loaded and resolve on load.
	if ( ! global.google || ! global.google.charts ) {
		const script = document.createElement( 'script' );
		script.type = 'text/javascript';

		chartLoadPromise = new Promise( ( resolve ) => {
			script.onload = resolve;
			// Add the script to the DOM
			global.document.head.appendChild( script );
			// Set the `src` to begin transport
			script.src = 'https://www.gstatic.com/charts/loader.js';
		} );
	} else {
		// Charts is already available - resolve immediately.
		chartLoadPromise = Promise.resolve();
	}

	return chartLoadPromise;
}

export default function GoogleChart( props ) {
	const {
		chartType,
		className,
		data,
		loadCompressed,
		loadHeight,
		loadSmall,
		loadText,
		options,
		selectedStats,
		singleStat,
	} = props;

	const chartRef = useRef( null );
	const [ chart, setChart ] = useState( null );
	const [ loading, setLoading ] = useState( true );

	const drawChart = useCallback( () => {
		let dataTable = global.google?.visualization?.arrayToDataTable?.( data );
		if ( dataTable ) {
			if ( selectedStats.length > 0 ) {
				dataTable = new global.google.visualization.DataView( dataTable );
				if ( ! singleStat ) {
					dataTable.setColumns( [
						0,
						...selectedStats.map( ( stat ) => stat + 1 ),
					] );
				}
			}

			chart.draw( dataTable, options );
		}
	}, [ chart, data, singleStat, selectedStats ] );

	useEffect( () => {
		loadCharts().then( () => {
			global.google.charts.load( 'current', {
				packages: [ 'corechart' ],
				callback: () => {
					setLoading( false );
				},
			} );
		} );

		const resize = debounce( drawChart, 100 );
		global.addEventListener( 'resize', resize );

		return () => {
			global.removeEventListener( 'resize', resize );
		};
	}, [] );

	// Create a new chart when the library is loaded.
	useEffect( () => {
		if ( ! loading && chartRef.current && global.google ) {
			const googleChart = 'pie' === chartType
				? new global.google.visualization.PieChart( chartRef.current )
				: new global.google.visualization.LineChart( chartRef.current );
			setChart( googleChart );
		}
	}, [ loading, !! chartRef.current, chartType ] );

	// Draw the chart whenever one of these properties has changed.
	useEffect( () => {
		if ( chart ) {
			drawChart();
		}
	}, [
		chart,
		selectedStats,
		options,
		singleStat,
	] );

	return (

					{ loading && (

							{ loadText && (

{ __( 'Loading chart…', 'google-site-kit' ) }

							) }

							<ProgressBar
								className={ className }
								small={ loadSmall }
								compress={ loadCompressed }
								height={ loadHeight }
							/>

					) }

	);
}

GoogleChart.propTypes = {
	chartType: PropTypes.string,
	className: PropTypes.string,
	data: PropTypes.arrayOf( PropTypes.array ),
	loadCompressed: PropTypes.bool,
	loadHeight: PropTypes.number,
	loadSmall: PropTypes.bool,
	loadText: PropTypes.bool,
	options: PropTypes.object.isRequired,
	selectedStats: PropTypes.array,
	singleStat: PropTypes.bool,
};

GoogleChart.defaultProps = {
	chartType: 'line',
	className: '',
	data: [],
	loadCompressed: false,
	loadSmall: false,
	loadHeight: null,
	loadText: true,
	selectedStats: [],
	singleStat: true,
};
<commit_msg>Update assets/js/components/GoogleChart.js<commit_after>/**
 * GoogleChart component.
 *
 * Site Kit by Google, Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import debounce from 'lodash/debounce';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
import { useEffect, useState, useRef, useCallback } from '@wordpress/element';

/**
 * Internal dependencies
 */
import ProgressBar from './ProgressBar';

let chartLoadPromise;

async function loadCharts() {
	if ( chartLoadPromise ) {
		return chartLoadPromise;
	}

	// Inject the script if not already loaded and resolve on load.
	if ( ! global.google || ! global.google.charts ) {
		const script = document.createElement( 'script' );
		script.type = 'text/javascript';

		chartLoadPromise = new Promise( ( resolve ) => {
			script.onload = resolve;
			// Add the script to the DOM
			global.document.head.appendChild( script );
			// Set the `src` to begin transport
			script.src = 'https://www.gstatic.com/charts/loader.js';
		} );
	} else {
		// Charts is already available - resolve immediately.
		chartLoadPromise = Promise.resolve();
	}

	return chartLoadPromise;
}

export default function GoogleChart( props ) {
	const {
		chartType,
		className,
		data,
		loadCompressed,
		loadHeight,
		loadSmall,
		loadText,
		options,
		selectedStats,
		singleStat,
	} = props;

	const chartRef = useRef( null );
	const [ chart, setChart ] = useState( null );
	const [ loading, setLoading ] = useState( true );

	const drawChart = useCallback( () => {
		let dataTable = global.google?.visualization?.arrayToDataTable?.( data );
		if ( dataTable ) {
			if ( selectedStats.length > 0 ) {
				dataTable = new global.google.visualization.DataView( dataTable );
				if ( ! singleStat ) {
					dataTable.setColumns( [
						0,
						...selectedStats.map( ( stat ) => stat + 1 ),
					] );
				}
			}

			chart.draw( dataTable, options );
		}
	}, [ chart, data, singleStat, selectedStats ] );

	useEffect( () => {
		loadCharts().then( () => {
			global.google.charts.load( 'current', {
				packages: [ 'corechart' ],
				callback: () => {
					setLoading( false );
				},
			} );
		} );

		const resize = debounce( drawChart, 100 );
		global.addEventListener( 'resize', resize );

		return () => {
			global.removeEventListener( 'resize', resize );
		};
	}, [] );

	// Create a new chart when the library is loaded.
	useEffect( () => {
		if ( ! loading && chartRef.current && global.google ) {
			const googleChart = 'pie' === chartType
				? new global.google.visualization.PieChart( chartRef.current )
				: new global.google.visualization.LineChart( chartRef.current );
			setChart( googleChart );
		}
	}, [ loading, !! chartRef.current, chartType ] );

	// Draw the chart whenever one of these properties has changed.
	useEffect( () => {
		if ( chart ) {
			drawChart();
		}
	}, [
		chart,
		selectedStats,
		options,
		singleStat,
	] );

	return (

					{ loading && (

							{ loadText && (

{ __( 'Loading chart…', 'google-site-kit' ) }

							) }

							<ProgressBar
								className={ className }
								small={ loadSmall }
								compress={ loadCompressed }
								height={ loadHeight }
							/>

					) }

	);
}

GoogleChart.propTypes = {
	chartType: PropTypes.string,
	className: PropTypes.string,
	data: PropTypes.arrayOf( PropTypes.array ),
	loadCompressed: PropTypes.bool,
	loadHeight: PropTypes.number,
	loadSmall: PropTypes.bool,
	loadText: PropTypes.bool,
	options: PropTypes.object.isRequired,
	selectedStats: PropTypes.array,
	singleStat: PropTypes.bool,
};

GoogleChart.defaultProps = {
	chartType: 'line',
	className: '',
	data: [],
	loadCompressed: false,
	loadSmall: false,
	loadHeight: null,
	loadText: true,
	selectedStats: [],
	singleStat: true,
};
<|endoftext|>


<commit_before>var os = require( 'os' )
var assert = require( 'assert' )

/**
 * BlockDevice Constructor
 * @param {Object} options
 */
function BlockDevice( options ) {

  if( !(this instanceof BlockDevice) )
    return new BlockDevice( options )

  options = options != null ?
    options : {}

  this.fs = options.fs || require( 'fs' )
  this.fd = options.fd
  this.path = options.path
  this.mode = options.mode || 'rs+'

  this.blockSize = options.blockSize || -1
  this.size = options.size || -1

  // Heads per Track (for CHS addressing)
  this.hpt = -1
  // Sectors per Track (for CHS addressing)
  this.spt = -1

  // Make 'this.fs' non-enumerable
  Object.defineProperty( this, 'fs', {
    enumerable: false
  })

}

/**
 * Returns physical device path from id
 * @param  {Number} id
 * @return {String} path
 */
BlockDevice.getPath = function( id ) {
  return os.platform() === 'win32' ?
    '\\\\.\\PhysicalDrive' + id :
    '/dev/device' + id
}

/**
 * BlockDevice Prototype
 * @type {Object}
 */
BlockDevice.prototype = {

  /**
   * BlockDevice constructor
   * @type {Function}
   */
  constructor: BlockDevice,

  /**
   * Opens a file descriptor for this device
   * @param {Function} callback
   * @return {BlockDevice}
   */
  open: function( callback ) {

    var self = this

    // Close a previously opened handle
    if( this.fd != null ) {
      return this.close( function( error ) {
        if( error != null )
          return callback.call( self, error )
        self.open( self.path, self.mode, callback )
      })
    }

    // Open a new fd handle
    this.fs.open( this.path, this.mode, function( error, fd ) {
      self.fd = fd
      callback.call( self, error, fd )
    })

    return this

  },

  /**
   * Closes the active file descriptor
   * @param {Function} callback
   * @return {BlockDevice}
   */
  close: function( callback ) {

    var self = this

    if( this.fd != null ) {
      this.fs.close( this.fd, function( error ) {
        self.fd = null
        callback.call( self )
      })
    }

    return this

  },

  /**
   * Primitive logical block size detection
   * @param  {Number} [size=128]
   * @param  {Number} [step=128]
   * @param  {Number} [limit=8192]
   * @param  {Function} callback
   * @return {Number}
   */
  detectBlockSize: function( size, step, limit, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    size  = size || 0x200
    step  = step || 0x80
    limit = limit || 0x2000

    var self = this

    var readBlock = function() {

      var block = new Buffer( size )

      self.fs.read( self.fd, block, 0, size, 0, function( error, bytesRead ) {
        if( error != null ) {
          // EINVAL tells us that the block size
          // ain't just right (yet); everything
          // else is probably user error
          if( error.code !== 'EINVAL' )
            return callback.call( self, error )
          // Increase the blocksize by `step`
          size += step
          // Attempt next size read
          return readBlock()
        }
        // Check if bytes read correspond
        // to current block size
        if( size !== bytesRead )
          return callback.call( self, new Error( 'Size and bytes read mismatch: ' + size + ', ' + bytesRead ) )
        // Check if the limit has been reached,
        // and terminate with error, if so
        if( size > limit )
          return callback.call( self, new Error( 'Reached limit of ' + limit + ' bytes' ))
        // We've successfully found the
        // smallest readable block size;
        // stop looking...
        self.blockSize = size
        callback.call( self, null, size )

      })

    }

    // Start reading blocks
    readBlock()

    return this

  },

  /**
   * Experimental devie size detection
   * @param  {Number} fd
   * @param  {Number} step
   * @return {Number}
   */
  detectSize: function( fd, step ) {

    console.warn( '[EXPERIMENTAL] detectSize' )

    step = step || 1024 * 1024 * 1024

    // Keep an output buffer around,
    // to avoid buffer creation on every read
    var block = new Buffer( this.blockSize )
    var bytesRead, size = 0, offset = 0

    while( true ) {
      try {
        bytesRead = this.fs.readSync( fd, block, 0, this.blockSize, offset )
        size = offset
        offset += step
      } catch( error ) {
        if( error.code !== 'EIO' ) {
          // We're only interested in I/O errors,
          // since they signal OOB reading
          throw error
        } else if( step <= this.blockSize ) {
          // If our maximum accuracy is reached,
          // break out of the loop
          break
        } else {
          // Step back
          offset -= step
          // Decrease step size
          step = Math.max( step / 1024, 1 )
        }
      }
      // console.log( 'bytes read:', bytesRead )
      // console.log( 'offset:', offset )
      console.log( 'step size:', step )
      console.log( 'size:', size / 1024 / 1024 / 1024, 'GB' )
    }

    var blocks = Math.ceil( size / this.blockSize )
    var size = blocks * this.blockSize

    // console.log( 'blocks:', blocks, 'á', this.blockSize, 'B' )
    // console.log( 'size:', size, 'B' )

    return size

  },

  /**
   * Converts a CHS address to an LBA
   * @param  {Number} cylinder
   * @param  {Number} head
   * @param  {Number} sector
   * @return {Number} lba
   */
  getLBA: function( cylinder, head, sector ) {

    if( this.hpt < 0 || this.spt < 0 )
      throw new Error( 'Missing disk geometry data' )

    return ( cylinder * this.hpt + head ) *
      this.spt + ( sector - 1 )

  },

  read: function( offset, length, buffer ) {
    buffer = buffer || new Buffer( length )
    return this.fs.readSync( this.fd, buffer, 0, length, offset )
  },

  /**
   * Reads from one LBA to another
   * @param  {Number} fromLBA
   * @param  {Number} toLBA
   * @param  {Buffer} buffer (optional)
   * @return {Buffer}
   */
  readLBA: function( fromLBA, toLBA, buffer ) {

    fromLBA = fromLBA || 0
    toLBA = toLBA || ( fromLBA + 1 )

    var from = this.blockSize * fromLBA
    var to = this.blockSize * toLBA

    return this.read( from, to - from, buffer )

  },

  write: function( offset, buffer ) {
    return this.fs.writeSync( this.fd, buffer, 0, buffer.length, offset )
  },

  writeLBA: function( fromLBA, buffer ) {
    var offset = this.blockSize * fromLBA
    return this.write( offset, buffer )
  }

}

// Exports
module.exports = BlockDevice
<commit_msg>Updated lib: Made device.detectSize() async<commit_after>var os = require( 'os' )
var assert = require( 'assert' )

/**
 * BlockDevice Constructor
 * @param {Object} options
 */
function BlockDevice( options ) {

  if( !(this instanceof BlockDevice) )
    return new BlockDevice( options )

  options = options != null ?
    options : {}

  this.fs = options.fs || require( 'fs' )
  this.fd = options.fd
  this.path = options.path
  this.mode = options.mode || 'rs+'

  this.blockSize = options.blockSize || -1
  this.size = options.size || -1

  // Heads per Track (for CHS addressing)
  this.hpt = -1
  // Sectors per Track (for CHS addressing)
  this.spt = -1

  // Make 'this.fs' non-enumerable
  Object.defineProperty( this, 'fs', {
    enumerable: false
  })

}

/**
 * Returns physical device path from id
 * @param  {Number} id
 * @return {String} path
 */
BlockDevice.getPath = function( id ) {
  return os.platform() === 'win32' ?
    '\\\\.\\PhysicalDrive' + id :
    '/dev/device' + id
}

/**
 * BlockDevice Prototype
 * @type {Object}
 */
BlockDevice.prototype = {

  /**
   * BlockDevice constructor
   * @type {Function}
   */
  constructor: BlockDevice,

  /**
   * Opens a file descriptor for this device
   * @param {Function} callback
   * @return {BlockDevice}
   */
  open: function( callback ) {

    var self = this

    // Close a previously opened handle
    if( this.fd != null ) {
      return this.close( function( error ) {
        if( error != null )
          return callback.call( self, error )
        self.open( self.path, self.mode, callback )
      })
    }

    // Open a new fd handle
    this.fs.open( this.path, this.mode, function( error, fd ) {
      self.fd = fd
      callback.call( self, error, fd )
    })

    return this

  },

  /**
   * Closes the active file descriptor
   * @param {Function} callback
   * @return {BlockDevice}
   */
  close: function( callback ) {

    var self = this

    if( this.fd != null ) {
      this.fs.close( this.fd, function( error ) {
        self.fd = null
        callback.call( self )
      })
    }

    return this

  },

  /**
   * Primitive logical block size detection
   * @param  {Number} [size=128]
   * @param  {Number} [step=128]
   * @param  {Number} [limit=8192]
   * @param  {Function} callback
   * @return {Number}
   */
  detectBlockSize: function( size, step, limit, callback ) {

    if( this.fd == null )
      return callback.call( this, new Error( 'Invalid file descriptor' ) )

    size  = size || 0x200
    step  = step || 0x80
    limit = limit || 0x2000

    var self = this

    var readBlock = function() {

      var block = new Buffer( size )

      self.fs.read( self.fd, block, 0, size, 0, function( error, bytesRead ) {
        if( error != null ) {
          // EINVAL tells us that the block size
          // ain't just right (yet); everything
          // else is probably user error
          if( error.code !== 'EINVAL' )
            return callback.call( self, error )
          // Increase the blocksize by `step`
          size += step
          // Attempt next size read
          return readBlock()
        }
        // Check if bytes read correspond
        // to current block size
        if( size !== bytesRead )
          return callback.call( self, new Error( 'Size and bytes read mismatch: ' + size + ', ' + bytesRead ) )
        // Check if the limit has been reached,
        // and terminate with error, if so
        if( size > limit )
          return callback.call( self, new Error( 'Reached limit of ' + limit + ' bytes' ))
        // We've successfully found the
        // smallest readable block size;
        // stop looking...
        self.blockSize = size
        callback.call( self, null, size )

      })

    }

    // Start reading blocks
    readBlock()

    return this

  },

  /**
   * Experimental device size detection
   * NOTE: This is extremely slow and should only be used
   * if the device's size can not be determined by reading
   * structures (like GPT/MBR/VBR/EBR/Partitions) from it
   * @param  {Number} step
   * @param  {Function} callback
   * @return {Number}
   */
  detectSize: function( step, callback ) {

    if( this.blockSize <= 0 || this.blockSize == null )
      throw new Error( 'No block size specified' )

    step = step || 1024 * 1024 * 1024

    // Keep an output buffer around,
    // to avoid buffer creation on every read
    var block = new Buffer( this.blockSize )
    var bytesRead = -1, size = -1, offset = 0
    var self = this

    var readBlock = function() {
      self.fs.read( self.fd, block, 0, self.blockSize, offset, function( error, bytesRead ) {
        // console.log( 'bytes read:', bytesRead )
        // console.log( 'offset:', offset )
        // console.log( 'step size:', step )
        // console.log( 'size:', size / 1024 / 1024 / 1024, 'GB' )
        if( error != null ) {
          // We're only interested in I/O errors,
          // since they signal OOB reading, otherwise break out of loop
          if( error.code !== 'EIO') {
            return callback.call( self, error, size )
          }
          // Step back
          offset -= step
          // Decrease step size
          step = Math.max( step / 8, 1 )
        } else {
          // Size is block size added to previous offset
          size = offset + self.blockSize
          // Advance offset on successfull read
          offset += step
        }
        // If our maximum accuracy is reached,
        // break out of the loop
        if( step < self.blockSize ) {
          var blocks = Math.ceil( size / self.blockSize )
          var total = blocks * self.blockSize
          return callback.call( self, null, total )
        }
        // Continue reading blocks
        readBlock()
      })
    }

    // Start reading blocks
    readBlock()

    return this

  },

  /**
   * Converts a CHS address to an LBA
   * @param  {Number} cylinder
   * @param  {Number} head
   * @param  {Number} sector
   * @return {Number} lba
   */
  getLBA: function( cylinder, head, sector ) {

    if( this.hpt < 0 || this.spt < 0 )
      throw new Error( 'Missing disk geometry data' )

    return ( cylinder * this.hpt + head ) *
      this.spt + ( sector - 1 )

  },

  read: function( offset, length, buffer ) {
    buffer = buffer || new Buffer( length )
    return this.fs.readSync( this.fd, buffer, 0, length, offset )
  },

  /**
   * Reads from one LBA to another
   * @param  {Number} fromLBA
   * @param  {Number} toLBA
   * @param  {Buffer} buffer (optional)
   * @return {Buffer}
   */
  readLBA: function( fromLBA, toLBA, buffer ) {

    fromLBA = fromLBA || 0
    toLBA = toLBA || ( fromLBA + 1 )

    var from = this.blockSize * fromLBA
    var to = this.blockSize * toLBA

    return this.read( from, to - from, buffer )

  },

  write: function( offset, buffer ) {
    return this.fs.writeSync( this.fd, buffer, 0, buffer.length, offset )
  },

  writeLBA: function( fromLBA, buffer ) {
    var offset = this.blockSize * fromLBA
    return this.write( offset, buffer )
  }

}

// Exports
module.exports = BlockDevice
<|endoftext|>


<commit_before>/*
 * Copyright 2018 Next Century Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* exported searchTransforms */
/* jshint camelcase:false */

var searchTransforms = (function(_) {
  function getTemplateFromSearchParameters(searchParameters, dateConfig, networkExpansionParameters) {
    var template = {
      clauses: !networkExpansionParameters ? [] : [{
        clauses: [],
        type: 'Ad',
        variable: '?ad1'
      }],
      filters: []
    };

    if(_.isEmpty(searchParameters)) {
      return template;
    }

    var andFilter = {
      clauses: [],
      operator: 'and'
    };

    var notFilter = {
      clauses: [],
      operator: 'not exists'
    };

    _.keys(searchParameters).forEach(function(type) {
      var unionClause = {
        clauses: [],
        operator: 'union'
      };

      var createVariable = true;

      _.keys(searchParameters[type]).forEach(function(term) {
        if(searchParameters[type][term].enabled) {
          // If the term is a date...
          if(dateConfig[term]) {
            // JS dates default to UTC but dates are saved otherwise in the DIG DB.  Ensure that constraint "X-Y-ZT05:00:00.000Z" will return results with date "X-Y-ZT00:00:00".
            var date = new Date(searchParameters[type][term].date.getTime());
            date.setUTCHours(0);

            andFilter.clauses.push({
              constraint: date.toISOString().split('.')[0],
              operator: term.includes('start') ? '>=' : '<=',
              variable: '?' + type + '1'
            });

            // Only create one date variable per date type.
            if(createVariable) {
              createVariable = false;

              template.clauses.push({
                isOptional: false,
                predicate: type,
                variable: '?' + type + '1'
              });

              // If network expansion is enabled for any type...
              if(networkExpansionParameters) {
                template.clauses[0].clauses.push({
                  isOptional: false,
                  predicate: type,
                  variable: '?' + type + '1'
                });
              }
            }
          } else if(searchParameters[type][term].search === 'lessthan' || searchParameters[type][term].search === 'morethan') {
            andFilter.clauses.push({
              constraint: searchParameters[type][term].key,
              operator: searchParameters[type][term].search === 'lessthan' ? '<' : '>',
              variable: '?' + type + '1'
            });

            // Only create one number variable per number type.
            if(createVariable) {
              createVariable = false;

              template.clauses.push({
                isOptional: false,
                predicate: type,
                variable: '?' + type + '1'
              });

              // If network expansion is enabled for any type...
              if(networkExpansionParameters) {
                template.clauses[0].clauses.push({
                  isOptional: false,
                  predicate: type,
                  variable: '?' + type + '1'
                });
              }
            }
          } else if(searchParameters[type][term].search === 'excluded') {
            notFilter.clauses.push({
              constraint: searchParameters[type][term].key,
              predicate: type
            });
          } else if(searchParameters[type][term].search === 'union') {
            unionClause.clauses.push({
              constraint: searchParameters[type][term].key,
              isOptional: false,
              predicate: type
            });
          } else {
            var optional = (searchParameters[type][term].search !== 'required');

            template.clauses.push({
              constraint: searchParameters[type][term].key,
              isOptional: networkExpansionParameters && networkExpansionParameters[type] ? true : optional,
              predicate: type
            });

            // If network expansion is enabled for any type...
            if(networkExpansionParameters) {
              template.clauses[0].clauses.push({
                constraint: searchParameters[type][term].key,
                isOptional: optional,
                predicate: type
              });
            }
          }
        }
      });

      if(unionClause.clauses.length === 1) {
        template.clauses.push(unionClause.clauses[0]);
        if(networkExpansionParameters) {
          template.clauses[0].clauses.push(unionClause.clauses[0]);
        }
      }

      if(unionClause.clauses.length > 1) {
        template.clauses.push(unionClause);
        if(networkExpansionParameters) {
          template.clauses[0].clauses.push({
            clauses: unionClause.clauses,
            isOptional: true,
            operator: 'union'
          });
        }
      }
    });

    var unionNetworkExpansion = {
      clauses: [],
      operator: 'union'
    };

    _.keys(networkExpansionParameters || {}).forEach(function(type) {
      if(networkExpansionParameters[type]) {
        unionNetworkExpansion.clauses.push({
          isOptional: false,
          predicate: type,
          variable: '?' + type
        });

        template.clauses[0].clauses.push({
          isOptional: false,
          predicate: type,
          variable: '?' + type
        });
      }
    });

    if(unionNetworkExpansion.clauses.length === 1) {
      template.clauses.push(unionNetworkExpansion.clauses[0]);
    }

    if(unionNetworkExpansion.clauses.length > 1) {
      template.clauses.push(unionNetworkExpansion);
    }

    if(andFilter.clauses.length) {
      template.filters.push(andFilter);
    }

    if(notFilter.clauses.length) {
      template.filters.push(notFilter);
    }

    return template;
  }

  return {
    createFacetsQuery: function(dateConfig) {
      return function(searchParameters, config) {
        var networkExpansionParameters = config ? config.custom : {};
        var isNetworkExpansion = !!(_.findKey(networkExpansionParameters, function(value) {
          return value;
        }));

        var template = getTemplateFromSearchParameters(searchParameters, dateConfig, isNetworkExpansion ? networkExpansionParameters : undefined);

        var predicate = config ? config.aggregationType : undefined;
        var groupBy = {
          limit: (config && config.pageSize ? config.pageSize : 0),
          offset: 0
        };
        var orderBy;
        var selects;

        if(predicate) {
          selects = [{
            'function': 'count',
            type: 'function',
            variable: '?' + predicate
          }];

          if(!isNetworkExpansion || !networkExpansionParameters[predicate]) {
            template.clauses.push({
              isOptional: false,
              predicate: predicate,
              variable: '?' + predicate
            });
          }

          if(isNetworkExpansion && !networkExpansionParameters[predicate]) {
            template.clauses[0].clauses.push({
              isOptional: false,
              predicate: predicate,
              variable: '?' + predicate
            });
          }

          groupBy.variables = [{
            variable: '?' + predicate
          }];

          orderBy = {
            values: [{
              'function': (config && config.sortOrder === '_term' ? undefined : 'count'),
              order: (config && config.sortOrder === '_term' ? 'asc' : 'desc'),
              variable: '?' + predicate
            }]
          };
        }

        return {
          SPARQL: {
            'group-by': groupBy,
            'order-by': orderBy,
            select: {
              variables: selects
            },
            where: {
              clauses: template.clauses,
              filters: template.filters,
              type: 'Ad',
              variable: '?ad'
            }
          },
          type: 'Aggregation'
        };
      };
    },

    createSearchQuery: function(dateConfig) {
      return function(searchParameters, config) {
        var networkExpansionParameters = config ? config.custom : {};
        var isNetworkExpansion = !!(_.findKey(networkExpansionParameters, function(value) {
          return value;
        }));

        var template = getTemplateFromSearchParameters(searchParameters, dateConfig, isNetworkExpansion ? networkExpansionParameters : undefined);

        var groupBy = (!config || !config.page || !config.pageSize) ? undefined : {
          limit: config.pageSize,
          offset: (config.page - 1) * config.pageSize
        };

        var orderBy;
        if(config.sortKey && config.sortOrder) {
          orderBy = {
            values: [{
              order: config.sortOrder,
              variable: '?' + config.sortKey + 'Sort'
            }]
          };
          template.clauses.push({
            isOptional: false,
            predicate: config.sortKey,
            variable: '?' + config.sortKey + 'Sort'
          });
        }

        return {
          SPARQL: {
            'group-by': groupBy,
            'order-by': orderBy,
            select: {
              variables: [{
                type: 'simple',
                variable: !isNetworkExpansion ? '?ad' : '?ad2'
              }]
            },
            where: {
              clauses: template.clauses,
              filters: template.filters,
              type: 'Ad',
              variable: !isNetworkExpansion ? '?ad' : '?ad2'
            }
          },
          type: 'Point Fact'
        };
      };
    },

    searchResults: function(response, config) {
      var highlights = {};
      var hits = {};

      if(response && response.length) {
        if(response[0].query && response[0].query.SPARQL && response[0].query.SPARQL.where && response[0].query.SPARQL.where.clauses && response[0].query.SPARQL.where.clauses.length) {
          var clauses = response[0].query.SPARQL.where.clauses;
          clauses.forEach(function(clause) {
            if(clause.predicate && clause.constraint && clause._id) {
              highlights._all = highlights._all || {};
              highlights._all[('' + clause.constraint).toLowerCase()] = clause._id;
              highlights[clause.predicate] = highlights[clause.predicate] || {};
              highlights[clause.predicate][('' + clause.constraint).toLowerCase()] = clause._id;
            }
            if(clause.clauses) {
              clause.clauses.forEach(function(nestedClause) {
                if(nestedClause.predicate && nestedClause.constraint && nestedClause._id) {
                  highlights._all = highlights._all || {};
                  highlights._all[('' + nestedClause.constraint).toLowerCase()] = nestedClause._id;
                  highlights[nestedClause.predicate] = highlights[nestedClause.predicate] || {};
                  highlights[nestedClause.predicate][('' + nestedClause.constraint).toLowerCase()] = nestedClause._id;
                }
              });
            }
          });
        }

        if(response[0].result) {
          if(config && config.isNetworkExpansion && response[0].result.length > 1) {
            hits = response[0].result[1].hits || {};
          } else {
            hits = response[0].result.hits || {};
          }
        }
      }

      return {
        highlights: highlights,
        hits: hits
      };
    }
  };
});

<commit_msg>Fixed a bug with dates in the search transforms.<commit_after>/*
 * Copyright 2018 Next Century Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* exported searchTransforms */
/* jshint camelcase:false */

var searchTransforms = (function(_) {
  function getTemplateFromSearchParameters(searchParameters, dateConfig, networkExpansionParameters) {
    var template = {
      clauses: !networkExpansionParameters ? [] : [{
        clauses: [],
        type: 'Ad',
        variable: '?ad1'
      }],
      filters: []
    };

    if(_.isEmpty(searchParameters)) {
      return template;
    }

    var andFilter = {
      clauses: [],
      operator: 'and'
    };

    var notFilter = {
      clauses: [],
      operator: 'not exists'
    };

    _.keys(searchParameters).forEach(function(type) {
      var unionClause = {
        clauses: [],
        operator: 'union'
      };

      var createVariable = true;

      _.keys(searchParameters[type]).forEach(function(term) {
        if(searchParameters[type][term].enabled) {
          // If the term is a date...
          if(dateConfig[term]) {
            // JS dates default to UTC but dates are saved otherwise in the DIG DB.  Ensure that constraint "X-Y-ZT05:00:00.000Z" will return results with date "X-Y-ZT00:00:00".
            var date = new Date(searchParameters[type][term].date);
            date.setUTCHours(0);

            andFilter.clauses.push({
              constraint: date.toISOString().split('.')[0],
              operator: term.includes('start') ? '>=' : '<=',
              variable: '?' + type + '1'
            });

            // Only create one date variable per date type.
            if(createVariable) {
              createVariable = false;

              template.clauses.push({
                isOptional: false,
                predicate: type,
                variable: '?' + type + '1'
              });

              // If network expansion is enabled for any type...
              if(networkExpansionParameters) {
                template.clauses[0].clauses.push({
                  isOptional: false,
                  predicate: type,
                  variable: '?' + type + '1'
                });
              }
            }
          } else if(searchParameters[type][term].search === 'lessthan' || searchParameters[type][term].search === 'morethan') {
            andFilter.clauses.push({
              constraint: searchParameters[type][term].key,
              operator: searchParameters[type][term].search === 'lessthan' ? '<' : '>',
              variable: '?' + type + '1'
            });

            // Only create one number variable per number type.
            if(createVariable) {
              createVariable = false;

              template.clauses.push({
                isOptional: false,
                predicate: type,
                variable: '?' + type + '1'
              });

              // If network expansion is enabled for any type...
              if(networkExpansionParameters) {
                template.clauses[0].clauses.push({
                  isOptional: false,
                  predicate: type,
                  variable: '?' + type + '1'
                });
              }
            }
          } else if(searchParameters[type][term].search === 'excluded') {
            notFilter.clauses.push({
              constraint: searchParameters[type][term].key,
              predicate: type
            });
          } else if(searchParameters[type][term].search === 'union') {
            unionClause.clauses.push({
              constraint: searchParameters[type][term].key,
              isOptional: false,
              predicate: type
            });
          } else {
            var optional = (searchParameters[type][term].search !== 'required');

            template.clauses.push({
              constraint: searchParameters[type][term].key,
              isOptional: networkExpansionParameters && networkExpansionParameters[type] ? true : optional,
              predicate: type
            });

            // If network expansion is enabled for any type...
            if(networkExpansionParameters) {
              template.clauses[0].clauses.push({
                constraint: searchParameters[type][term].key,
                isOptional: optional,
                predicate: type
              });
            }
          }
        }
      });

      if(unionClause.clauses.length === 1) {
        template.clauses.push(unionClause.clauses[0]);
        if(networkExpansionParameters) {
          template.clauses[0].clauses.push(unionClause.clauses[0]);
        }
      }

      if(unionClause.clauses.length > 1) {
        template.clauses.push(unionClause);
        if(networkExpansionParameters) {
          template.clauses[0].clauses.push({
            clauses: unionClause.clauses,
            isOptional: true,
            operator: 'union'
          });
        }
      }
    });

    var unionNetworkExpansion = {
      clauses: [],
      operator: 'union'
    };

    _.keys(networkExpansionParameters || {}).forEach(function(type) {
      if(networkExpansionParameters[type]) {
        unionNetworkExpansion.clauses.push({
          isOptional: false,
          predicate: type,
          variable: '?' + type
        });

        template.clauses[0].clauses.push({
          isOptional: false,
          predicate: type,
          variable: '?' + type
        });
      }
    });

    if(unionNetworkExpansion.clauses.length === 1) {
      template.clauses.push(unionNetworkExpansion.clauses[0]);
    }

    if(unionNetworkExpansion.clauses.length > 1) {
      template.clauses.push(unionNetworkExpansion);
    }

    if(andFilter.clauses.length) {
      template.filters.push(andFilter);
    }

    if(notFilter.clauses.length) {
      template.filters.push(notFilter);
    }

    return template;
  }

  return {
    createFacetsQuery: function(dateConfig) {
      return function(searchParameters, config) {
        var networkExpansionParameters = config ? config.custom : {};
        var isNetworkExpansion = !!(_.findKey(networkExpansionParameters, function(value) {
          return value;
        }));

        var template = getTemplateFromSearchParameters(searchParameters, dateConfig, isNetworkExpansion ? networkExpansionParameters : undefined);

        var predicate = config ? config.aggregationType : undefined;
        var groupBy = {
          limit: (config && config.pageSize ? config.pageSize : 0),
          offset: 0
        };
        var orderBy;
        var selects;

        if(predicate) {
          selects = [{
            'function': 'count',
            type: 'function',
            variable: '?' + predicate
          }];

          if(!isNetworkExpansion || !networkExpansionParameters[predicate]) {
            template.clauses.push({
              isOptional: false,
              predicate: predicate,
              variable: '?' + predicate
            });
          }

          if(isNetworkExpansion && !networkExpansionParameters[predicate]) {
            template.clauses[0].clauses.push({
              isOptional: false,
              predicate: predicate,
              variable: '?' + predicate
            });
          }

          groupBy.variables = [{
            variable: '?' + predicate
          }];

          orderBy = {
            values: [{
              'function': (config && config.sortOrder === '_term' ? undefined : 'count'),
              order: (config && config.sortOrder === '_term' ? 'asc' : 'desc'),
              variable: '?' + predicate
            }]
          };
        }

        return {
          SPARQL: {
            'group-by': groupBy,
            'order-by': orderBy,
            select: {
              variables: selects
            },
            where: {
              clauses: template.clauses,
              filters: template.filters,
              type: 'Ad',
              variable: '?ad'
            }
          },
          type: 'Aggregation'
        };
      };
    },

    createSearchQuery: function(dateConfig) {
      return function(searchParameters, config) {
        var networkExpansionParameters = config ? config.custom : {};
        var isNetworkExpansion = !!(_.findKey(networkExpansionParameters, function(value) {
          return value;
        }));

        var template = getTemplateFromSearchParameters(searchParameters, dateConfig, isNetworkExpansion ? networkExpansionParameters : undefined);

        var groupBy = (!config || !config.page || !config.pageSize) ? undefined : {
          limit: config.pageSize,
          offset: (config.page - 1) * config.pageSize
        };

        var orderBy;
        if(config.sortKey && config.sortOrder) {
          orderBy = {
            values: [{
              order: config.sortOrder,
              variable: '?' + config.sortKey + 'Sort'
            }]
          };
          template.clauses.push({
            isOptional: false,
            predicate: config.sortKey,
            variable: '?' + config.sortKey + 'Sort'
          });
        }

        return {
          SPARQL: {
            'group-by': groupBy,
            'order-by': orderBy,
            select: {
              variables: [{
                type: 'simple',
                variable: !isNetworkExpansion ? '?ad' : '?ad2'
              }]
            },
            where: {
              clauses: template.clauses,
              filters: template.filters,
              type: 'Ad',
              variable: !isNetworkExpansion ? '?ad' : '?ad2'
            }
          },
          type: 'Point Fact'
        };
      };
    },

    searchResults: function(response, config) {
      var highlights = {};
      var hits = {};

      if(response && response.length) {
        if(response[0].query && response[0].query.SPARQL && response[0].query.SPARQL.where && response[0].query.SPARQL.where.clauses && response[0].query.SPARQL.where.clauses.length) {
          var clauses = response[0].query.SPARQL.where.clauses;
          clauses.forEach(function(clause) {
            if(clause.predicate && clause.constraint && clause._id) {
              highlights._all = highlights._all || {};
              highlights._all[('' + clause.constraint).toLowerCase()] = clause._id;
              highlights[clause.predicate] = highlights[clause.predicate] || {};
              highlights[clause.predicate][('' + clause.constraint).toLowerCase()] = clause._id;
            }
            if(clause.clauses) {
              clause.clauses.forEach(function(nestedClause) {
                if(nestedClause.predicate && nestedClause.constraint && nestedClause._id) {
                  highlights._all = highlights._all || {};
                  highlights._all[('' + nestedClause.constraint).toLowerCase()] = nestedClause._id;
                  highlights[nestedClause.predicate] = highlights[nestedClause.predicate] || {};
                  highlights[nestedClause.predicate][('' + nestedClause.constraint).toLowerCase()] = nestedClause._id;
                }
              });
            }
          });
        }

        if(response[0].result) {
          if(config && config.isNetworkExpansion && response[0].result.length > 1) {
            hits = response[0].result[1].hits || {};
          } else {
            hits = response[0].result.hits || {};
          }
        }
      }

      return {
        highlights: highlights,
        hits: hits
      };
    }
  };
});

<|endoftext|>


<commit_before>// the timer to run code every second
var Timer = window.setInterval(function(){Tick()},1000);

// the array of components
var Components = [];

// the array of malicious software
var Baddies = [];

// the object constructor for save games
function GameSave()
{
  this.bytes = 0;						// the current level of bytes
	this.bps = 1;							// the current level of bytes per second
	this.baddielvl = 1;				// the baddies' level
	this.warriors = 0;				// the current level of warriors
	this.sacrificed = 0;			// the current level of sacrificed
	this.upgradeavail = 0;	// the number of available upgrade points
	this.upgradespent = 0;		// the number of spent upgrade points
	this.defeated = 0;				// the number of defeated baddies
}

//the object model for components
function Component(name, cost, persec, level,text)
{
  this.name = name;
  this.cost = cost;
  this.persec = persec;
  this.level = level;
	this.text = text;
}

// the object model for the baddies
function Baddie(type, power, reward)
{
	this.type = type;
	this.power = power;
	this.reward = reward;
	this.slowreward = reward;
	this.ticks = 0;
}
// the function to make a new baddie
function MakeBaddie()
{
	// if there are less than 5 baddies
	if (Baddies.length < 5)
	{
		// there's a chance to spawn a baddie
		var chance = Math.random();
		if (chance > .75)
		{
			var power = game.baddielvl * 10;
			chance = Math.random();
			// if chance is more than 50% then make Malware, otherwise make virus
			if (chance > .5)
			{
				Baddies[Baddies.length] = new Baddie("M",power,power);
			} else {
				Baddies[Baddies.length] = new Baddie("V",power,power);
			}
		}
	}
}
// the function to initialize the components
function InitComponents()
{
  Components[0] = new Component("CPU",10,1,0,"CPU");
  Components[1] = new Component("MOBO",50,5,0,"MoBo");
  Components[2] = new Component("RAM",1000,10,0,"RAM");
	Components[3] = new Component("AV",10,10,0,"Anti-Virus");
	Components[4] = new Component("MW",10,10,0,"Malware Agent");
}

// the function to initialize the display
function UpdateDisplay()
{
	for (var i = 0; i < Components.length; i++)
	{
		var idname = Components[i].name.toLowerCase();
		var lvl = idname + "-level";
		var bps = idname + "-bps";
		var btn = idname + "-btn";
    document.getElementById(lvl).innerHTML = Components[i].level;
    document.getElementById(bps).innerHTML = Components[i].persec + " / " + Components[i].level * Components[i].persec;
		document.getElementById(btn).value = Components[i].text + " (" + Components[i].cost + ")";
		document.getElementById("bytes-per-sec").innerHTML = game.bps;
	}
	// clear the baddie track
	for (var i = 0; i < 5; i++)
	{
		var idtype = "malsoft" + i;
		var idstat = "malstat" + i;
		document.getElementById(idtype).innerHTML = " ";
		document.getElementById(idstat).innerHTML = " ";
	}

	// fill the baddie track
	for (var i = 0; i < Baddies.length; i++)
	{
		var idtype = "malsoft" + i;
		var idstat = "malstat" + i;
		document.getElementById(idtype).innerHTML = Baddies[i].type;
		document.getElementById(idstat).innerHTML = Baddies[i].power + " / " + Baddies[i].slowreward;
	}
	document.getElementById("total-bytes").innerHTML = game.bytes;
	document.getElementById("warrior-bytes").innerHTML = game.warriors;
	document.getElementById("sacrificed-bytes").innerHTML = game.sacrificed;
	document.getElementById("total-fixed").innerHTML = game.defeated;
	document.getElementById("available-upgrade").innerHTML = game.upgradeavail;
	document.getElementById("used-upgrade").innerHTML = game.upgradespent;
}

function Fight()
{
	if (Baddies.length > 0)
	{
		// initialize the damage variable
		var damage = 0;

		// if it's a virus
		if (Baddies[0].type == "V")
		{
			// then use the anti-virus level to combat the baddie
			damage = (game.warriors > (Components[3].level * Components[3].persec)) ? Components[3].level * Components[3].persec : game.warriors;
		} else if (Baddies[0].type == "M") {
			// or use the malware agent level to combat the baddie
			damage = (game.warriors > (Components[4].level * Components[4].persec)) ? Components[4].level * Components[4].persec : game.warriors;
		}

		// if the baddie has less power than the damage
		if (Baddies[0].power <= damage)
		{
			// decrease the warriors by the power
			game.warriors -= Baddies[0].power;
			// increase the sacrificed bytes
			game.sacrificed += Baddies[0].power;
			// decrease the damage equal to the power
			damage -= Baddies[0].power;
			// then do damage equal to the power
			Baddies[0].power -= Baddies[0].power;
			KillBaddie();
		} else {
			// decrease the warriors
			game.warriors -= damage;
			// increase the sacrificed
			game.sacrificed += damage;
			// otherwise do the damage
			Baddies[0].power -= damage;
		}
	}
}

function KillBaddie()
{
	game.defeated++;
	game.upgradeavail += Baddies[0].slowreward;
	Baddies.shift();
	UpdateDisplay();
}

// the function that runs at the interval
function Tick()
{
	// get the bytes per second
	game.bps = BytesPerSecond();
	// increase the game bytes by this much
	game.bytes += game.bps;
	// also increase the warriors by this much
	game.warriors += game.bps;
	// run the script to make a baddie
	MakeBaddie();
	// run the script to FIIIIIIIIIIIIIGHT!!
	Fight();
	// if the baddie wasn't killed in 1 fight, reduce the slow reward
	if (Baddies.length > 0)
	{
		if (Baddies[0].ticks < 5)
		{
			Baddies[0].ticks++;
			Baddies[0].slowreward = Baddies[0].reward * (1 - Baddies[0].ticks/10);
		}
	}
	// give the user some points to update
	game.upgradeavail++;
	// update the display
	UpdateDisplay();
}

function Upgrade(id)
{
  if (game.upgradeavail >= Components[id].cost) // is there enough upgrade available?
  {
    game.upgradeavail -= Components[id].cost; // decrease the available by the cost
		game.upgradespent += Components[id].cost;	// increase the spend upgrade by the cost
    Components[id].level++; //increase the component level
    Components[id].cost = Math.round(Components[id].cost * 1.25);
		game.bps = BytesPerSecond();
		UpdateDisplay();
	}
}

function BytesPerSecond()
{
	var bps = 1;
  for(var i = 0; i < 3; i++)
  {
    bps += (Components[i].level * Components[i].persec);
  }
	return bps;
}

window.onload = function()
{
  window.game = new GameSave();
  InitComponents();
	UpdateDisplay();
}<commit_msg>Baddie Level<commit_after>// the timer to run code every second
var Timer = window.setInterval(function(){Tick()},1000);

// the array of components
var Components = [];

// the array of malicious software
var Baddies = [];

// the array of floating texts
var TxtFloats = [];

// the object constructor for save games
function GameSave()
{
  this.bytes = 0;						// the current level of bytes
	this.bps = 1;							// the current level of bytes per second
	this.baddielvl = 1;				// the baddies' level
	this.warriors = 0;				// the current level of warriors
	this.sacrificed = 0;			// the current level of sacrificed
	this.upgradeavail = 0;		// the number of available upgrade points
	this.upgradespent = 0;		// the number of spent upgrade points
	this.defeated = 0;				// the number of defeated baddies
}

//the object model for components
function Component(name, cost, persec, level,text)
{
  this.name = name;
  this.cost = cost;
  this.persec = persec;
  this.level = level;
	this.text = text;
}

// the object model for the baddies
function Baddie(type, power, reward)
{
	this.type = type;
	this.power = power;
	this.reward = reward;
	this.slowreward = reward;
	this.ticks = -2;
}

// the object model for float texts
function TxtFloat (text)
{
	this.id = 0;
	this.time = FloatTimer;
	this.opacity = 100;
	this.text = text;
}

// the function to make a new baddie
function MakeBaddie()
{
	// if there are less than 5 baddies
	if (Baddies.length < 5)
	{
		// there's a chance to spawn a baddie
		var chance = Math.random();
		if (chance > .15)
		{
			var power = game.baddielvl * 10;
			chance = Math.random();
			// if chance is more than 50% then make Malware, otherwise make virus
			if (chance > .5)
			{
				Baddies[Baddies.length] = new Baddie("M",power,power/2);
			} else {
				Baddies[Baddies.length] = new Baddie("V",power,power/2);
			}
		}
	}
}
// the function to initialize the components
function InitComponents()
{
  Components[0] = new Component("CPU",10,1,0,"CPU");
  Components[1] = new Component("MOBO",50,5,0,"MoBo");
  Components[2] = new Component("RAM",1000,10,0,"RAM");
	Components[3] = new Component("AV",10,10,0,"Anti-Virus");
	Components[4] = new Component("MW",10,10,0,"Malware Agent");
}

// the function to initialize the display
function UpdateDisplay()
{
	for (var i = 0; i < Components.length; i++)
	{
		var idname = Components[i].name.toLowerCase();
		var lvl = idname + "-level";
		var bps = idname + "-bps";
		var btn = idname + "-btn";
    document.getElementById(lvl).innerHTML = Components[i].level;
    document.getElementById(bps).innerHTML = Components[i].persec + " / " + Components[i].level * Components[i].persec;
		document.getElementById(btn).value = Components[i].text + " (" + Components[i].cost + ")";
		document.getElementById("bytes-per-sec").innerHTML = game.bps;
	}
	// clear the baddie track
	for (var i = 0; i < 5; i++)
	{
		var idtype = "malsoft" + i;
		var idstat = "malstat" + i;
		document.getElementById(idtype).innerHTML = " ";
		document.getElementById(idstat).innerHTML = " ";
	}

	// fill the baddie track
	for (var i = 0; i < Baddies.length; i++)
	{
		var idtype = "malsoft" + i;
		var idstat = "malstat" + i;
		document.getElementById(idtype).innerHTML = Baddies[i].type;
		document.getElementById(idstat).innerHTML = Baddies[i].power + " / " + Baddies[i].slowreward;
	}
	document.getElementById("total-bytes").innerHTML = game.bytes;
	document.getElementById("warrior-bytes").innerHTML = game.warriors;
	document.getElementById("sacrificed-bytes").innerHTML = game.sacrificed;
	document.getElementById("total-fixed").innerHTML = game.defeated;
	document.getElementById("available-upgrade").innerHTML = game.upgradeavail;
	document.getElementById("used-upgrade").innerHTML = game.upgradespent;
}

function Fight()
{
	if (Baddies.length > 0)
	{
		// initialize the damage variable
		var damage = 0;

		// if it's a virus
		if (Baddies[0].type == "V")
		{
			// then use the anti-virus level to combat the baddie
			damage = (game.warriors > (Components[3].level * Components[3].persec)) ? Components[3].level * Components[3].persec : game.warriors;
		} else if (Baddies[0].type == "M") {
			// or use the malware agent level to combat the baddie
			damage = (game.warriors > (Components[4].level * Components[4].persec)) ? Components[4].level * Components[4].persec : game.warriors;
		}

		// if the baddie has less power than the damage
		if (Baddies[0].power <= damage)
		{
			// decrease the warriors by the power
			game.warriors -= Baddies[0].power;
			// increase the sacrificed bytes
			game.sacrificed += Baddies[0].power;
			// decrease the damage equal to the power
			damage -= Baddies[0].power;
			// then do damage equal to the power
			Baddies[0].power -= Baddies[0].power;
			KillBaddie();
		} else {
			// decrease the warriors
			game.warriors -= damage;
			// increase the sacrificed
			game.sacrificed += damage;
			// otherwise do the damage
			Baddies[0].power -= damage;
		}
	}
}

function KillBaddie()
{
	game.defeated++;
	if (game.defeated > (2 * game.baddielvl + 1) * 10)
	{
		game.baddielvl++;
	}
	game.upgradeavail += Baddies[0].slowreward;
	Baddies.shift();
	UpdateDisplay();
}

// the function that runs at the interval
function Tick()
{
	// get the bytes per second
	game.bps = BytesPerSecond();
	// increase the game bytes by this much
	game.bytes += game.bps;
	// also increase the warriors by this much
	game.warriors += game.bps;
	// run the script to make a baddie
	MakeBaddie();
	// run the script to FIIIIIIIIIIIIIGHT!!
	Fight();
	// if the baddie wasn't killed in 1 fight, reduce the slow reward
	if (Baddies.length > 0)
	{
		if (Baddies[0].ticks < 5)
		{
			Baddies[0].ticks++;
			Baddies[0].slowreward = Baddies[0].reward * (1 - Baddies[0].ticks/10);
		}
	}
	// give the user some points to update
	game.upgradeavail++;
	// update the display
	UpdateDisplay();
}

function Upgrade(id)
{
  if (game.upgradeavail >= Components[id].cost) // is there enough upgrade available?
  {
    game.upgradeavail -= Components[id].cost; // decrease the available by the cost
		game.upgradespent += Components[id].cost;	// increase the spend upgrade by the cost
    Components[id].level++; //increase the component level
    Components[id].cost = Math.round(Components[id].cost * 1.25);
		game.bps = BytesPerSecond();
		UpdateDisplay();
	}
}

function BytesPerSecond()
{
	var bps = 1;
  for(var i = 0; i < 3; i++)
  {
    bps += (Components[i].level * Components[i].persec);
  }
	return bps;
}

window.onload = function()
{
  window.game = new GameSave();
  InitComponents();
	UpdateDisplay();
}<|endoftext|>