<commit_before>var fs = require('fs')
  , $ = require('..');

describe('iterating', function() {

  describe('siblings', function() {
    var xml = fs.readFileSync(__dirname + '/data/siblings.xml', 'utf8');
    var root = $(xml);

    describe('all siblings', function() {
      var siblings = root.children();

      it('should have total of five', function() {
        expect(siblings).to.have.length(5);
      });

      it('should be identitcal to siblings', function() {
        var s = siblings.siblings();
        expect(siblings).to.have.length(5);
        expect(siblings[0].textContent).to.equal('1');
        expect(siblings[4].textContent).to.equal('5');
      });

      it('should wrap nodes when using at', function() {
        expect(siblings.at(1).text()).to.equal('2');
        expect(siblings.at(2).name()).to.equal('b');
        expect(siblings.at(5)).to.have.length(0);
      });

      it('should iterate from first to last', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next()) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(5);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('3');
        expect(vals[3]).to.equal('4');
        expect(vals[4]).to.equal('5');
      });

      it('should iterate from first to all next a elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('4');
      });

      it('should iterate from first to all next b elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1'); // first is unqualified, includes
        expect(vals[1]).to.equal('3');
        expect(vals[2]).to.equal('5');
      });

      it('should iterate from first a to last a', function() {
        var vals = [];
        for (var sib = siblings.first('a'); sib.length > 0; sib = sib.next('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('4');
      });

      it('should iterate from first b to last b', function() {
        var vals = [];
        for (var sib = siblings.first('b'); sib.length > 0; sib = sib.next('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('3');
        expect(vals[1]).to.equal('5');
      });

      it('should iterate from last to first', function() {
        var vals = [];
        for (var sib = siblings.last(); sib.length > 0; sib = sib.prev()) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(5);
        expect(vals[0]).to.equal('5');
        expect(vals[1]).to.equal('4');
        expect(vals[2]).to.equal('3');
        expect(vals[3]).to.equal('2');
        expect(vals[4]).to.equal('1');
      });

      it('should iterate from last to all previous a elements', function() {
        var vals = [];
        for (var sib = siblings.last(); sib.length > 0; sib = sib.prev('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(4);
        expect(vals[0]).to.equal('5'); // first is unqualified, includes
        expect(vals[1]).to.equal('4');
        expect(vals[2]).to.equal('2');
        expect(vals[3]).to.equal('1');
      });

      it('should iterate from last to all previous b elements', function() {
        var vals = [];
        for (var sib = siblings.last(); sib.length > 0; sib = sib.prev('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('5');
        expect(vals[1]).to.equal('3');
      });

      it('should iterate from last a to first a', function() {
        var vals = [];
        for (var sib = siblings.last('a'); sib.length > 0; sib = sib.prev('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('4');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('1');
      });

      it('should iterate from last b to first b', function() {
        var vals = [];
        for (var sib = siblings.last('b'); sib.length > 0; sib = sib.prev('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('5');
        expect(vals[1]).to.equal('3');
      });
    });

    describe('only a siblings', function() {
      var siblings = root.children('a');

      it('should have total of three', function() {
        expect(siblings).to.have.length(3);
      });

      it('should iterate from first to last', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next()) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(5);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('3');
        expect(vals[3]).to.equal('4');
        expect(vals[4]).to.equal('5');
      });

      it('should iterate from first to all next a elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('4');
      });

      it('should iterate from first to all next b elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1'); // first is unqualified, includes
        expect(vals[1]).to.equal('3');
        expect(vals[2]).to.equal('5');
      });
    });

    describe('only b siblings', function() {
      var siblings = root.children('b');

      it('should have total of two', function() {
        expect(siblings).to.have.length(2);
      });

      it('should iterate from first to last', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next()) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('3');
        expect(vals[1]).to.equal('4');
        expect(vals[2]).to.equal('5');
      });

      it('should iterate from first to all next a elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('3'); // first is unqualified, includes
        expect(vals[1]).to.equal('4');
      });

      it('should iterate from first to all next b elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('3');
        expect(vals[1]).to.equal('5');
      });
    });

    describe('siblings of', function() {
      var children = root.children();

      describe('first child', function() {
        var first = children.at(0);

        it('should iterate from first to all next b elements', function() {
          var siblings = first.siblings();

          expect(siblings).to.have.length(4);
          expect(siblings[0].textContent).to.equal('2');
          expect(siblings[1].textContent).to.equal('3');
          expect(siblings[2].textContent).to.equal('4');
          expect(siblings[3].textContent).to.equal('5');
        });
      });

      describe('third child', function() {
        var third = children.at(2);

        it('should iterate from first to all next b elements', function() {
          var siblings = third.siblings();

          expect(siblings).to.have.length(4);
          expect(siblings[0].textContent).to.equal('1');
          expect(siblings[1].textContent).to.equal('2');
          expect(siblings[2].textContent).to.equal('4');
          expect(siblings[3].textContent).to.equal('5');
        });
      });

      describe('fifth child', function() {
        var fifth = children.at(4);

        it('should iterate from first to all next b elements', function() {
          var siblings = fifth.siblings();

          expect(siblings).to.have.length(4);
          expect(siblings[0].textContent).to.equal('1');
          expect(siblings[1].textContent).to.equal('2');
          expect(siblings[2].textContent).to.equal('3');
          expect(siblings[3].textContent).to.equal('4');
        });
      });
    });
  });

});
<commit_msg>Add test case for name qualifier.<commit_after>var fs = require('fs')
  , $ = require('..');

describe('iterating', function() {

  describe('siblings', function() {
    var xml = fs.readFileSync(__dirname + '/data/siblings.xml', 'utf8');
    var root = $(xml);

    describe('all siblings', function() {
      var siblings = root.children();

      it('should have total of five', function() {
        expect(siblings).to.have.length(5);
      });

      it('should be identitcal to siblings', function() {
        var s = siblings.siblings();
        expect(siblings).to.have.length(5);
        expect(siblings[0].textContent).to.equal('1');
        expect(siblings[4].textContent).to.equal('5');
      });

      it('should wrap nodes when using at', function() {
        expect(siblings.at(1).text()).to.equal('2');
        expect(siblings.at(2).name()).to.equal('b');
        expect(siblings.at(5)).to.have.length(0);
      });

      it('should iterate from first to last', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next()) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(5);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('3');
        expect(vals[3]).to.equal('4');
        expect(vals[4]).to.equal('5');
      });

      it('should iterate from first to all next a elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('4');
      });

      it('should iterate from first to all next b elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1'); // first is unqualified, includes
        expect(vals[1]).to.equal('3');
        expect(vals[2]).to.equal('5');
      });

      it('should iterate from first a to last a', function() {
        var vals = [];
        for (var sib = siblings.first('a'); sib.length > 0; sib = sib.next('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('4');
      });

      it('should iterate from first b to last b', function() {
        var vals = [];
        for (var sib = siblings.first('b'); sib.length > 0; sib = sib.next('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('3');
        expect(vals[1]).to.equal('5');
      });

      it('should iterate from last to first', function() {
        var vals = [];
        for (var sib = siblings.last(); sib.length > 0; sib = sib.prev()) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(5);
        expect(vals[0]).to.equal('5');
        expect(vals[1]).to.equal('4');
        expect(vals[2]).to.equal('3');
        expect(vals[3]).to.equal('2');
        expect(vals[4]).to.equal('1');
      });

      it('should iterate from last to all previous a elements', function() {
        var vals = [];
        for (var sib = siblings.last(); sib.length > 0; sib = sib.prev('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(4);
        expect(vals[0]).to.equal('5'); // first is unqualified, includes
        expect(vals[1]).to.equal('4');
        expect(vals[2]).to.equal('2');
        expect(vals[3]).to.equal('1');
      });

      it('should iterate from last to all previous b elements', function() {
        var vals = [];
        for (var sib = siblings.last(); sib.length > 0; sib = sib.prev('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('5');
        expect(vals[1]).to.equal('3');
      });

      it('should iterate from last a to first a', function() {
        var vals = [];
        for (var sib = siblings.last('a'); sib.length > 0; sib = sib.prev('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('4');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('1');
      });

      it('should iterate from last b to first b', function() {
        var vals = [];
        for (var sib = siblings.last('b'); sib.length > 0; sib = sib.prev('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('5');
        expect(vals[1]).to.equal('3');
      });
    });

    describe('only a siblings', function() {
      var siblings = root.children('a');

      it('should have total of three', function() {
        expect(siblings).to.have.length(3);
      });

      it('should iterate from first to last', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next()) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(5);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('3');
        expect(vals[3]).to.equal('4');
        expect(vals[4]).to.equal('5');
      });

      it('should iterate from first to all next a elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1');
        expect(vals[1]).to.equal('2');
        expect(vals[2]).to.equal('4');
      });

      it('should iterate from first to all next b elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('1'); // first is unqualified, includes
        expect(vals[1]).to.equal('3');
        expect(vals[2]).to.equal('5');
      });
    });

    describe('only b siblings', function() {
      var siblings = root.children('b');

      it('should have total of two', function() {
        expect(siblings).to.have.length(2);
      });

      it('should iterate from first to last', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next()) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(3);
        expect(vals[0]).to.equal('3');
        expect(vals[1]).to.equal('4');
        expect(vals[2]).to.equal('5');
      });

      it('should iterate from first to all next a elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('a')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('3'); // first is unqualified, includes
        expect(vals[1]).to.equal('4');
      });

      it('should iterate from first to all next b elements', function() {
        var vals = [];
        for (var sib = siblings.first(); sib.length > 0; sib = sib.next('b')) {
          vals.push(sib.text());
        }
        expect(vals).to.have.length(2);
        expect(vals[0]).to.equal('3');
        expect(vals[1]).to.equal('5');
      });
    });

    describe('siblings of', function() {
      var children = root.children();

      describe('first child', function() {
        var first = children.at(0);

        it('should get all siblings', function() {
          var siblings = first.siblings();

          expect(siblings).to.have.length(4);
          expect(siblings[0].textContent).to.equal('2');
          expect(siblings[1].textContent).to.equal('3');
          expect(siblings[2].textContent).to.equal('4');
          expect(siblings[3].textContent).to.equal('5');
        });

        it('should get qualified siblings with a name', function() {
          var siblings = first.siblings('a');

          expect(siblings).to.have.length(2);
          expect(siblings[0].textContent).to.equal('2');
          expect(siblings[1].textContent).to.equal('4');
        });

        it('should get qualified siblings with b name', function() {
          var siblings = first.siblings('b');

          expect(siblings).to.have.length(2);
          expect(siblings[0].textContent).to.equal('3');
          expect(siblings[1].textContent).to.equal('5');
        });
      });

      describe('third child', function() {
        var third = children.at(2);

        it('should get all siblings', function() {
          var siblings = third.siblings();

          expect(siblings).to.have.length(4);
          expect(siblings[0].textContent).to.equal('1');
          expect(siblings[1].textContent).to.equal('2');
          expect(siblings[2].textContent).to.equal('4');
          expect(siblings[3].textContent).to.equal('5');
        });
      });

      describe('fifth child', function() {
        var fifth = children.at(4);

        it('should get all siblings', function() {
          var siblings = fifth.siblings();

          expect(siblings).to.have.length(4);
          expect(siblings[0].textContent).to.equal('1');
          expect(siblings[1].textContent).to.equal('2');
          expect(siblings[2].textContent).to.equal('3');
          expect(siblings[3].textContent).to.equal('4');
        });
      });
    });
  });

});
<|endoftext|>


<commit_before>'use strict';

module.exports = Until;
var PassThrough = require('stream').PassThrough;
var inherits = require("util").inherits;
var Buffers = require('buffers');

if (!PassThrough) {
  PassThrough = require('readable-stream/passthrough');
}

inherits(Until, PassThrough);

//todo only emit end when buffer is empty
function Until(opts) {
  this._buf = Buffers();
  this._found = false;

  if (typeof opts.pattern === "string") {
    opts.pattern = new Buffer(opts.pattern);
  } else if (!opts.pattern instanceof Buffer) {
    throw new Error('Invalid pattern type')
  }

  this._opts = opts;
  this.unpiping = false;

  //todo allow and handle normal PassThrough opts
  PassThrough.call(this);
}

Until.prototype.read = function (size) {
  if (this.unpiping) {
    //either return null from read() until everything is unpiped
    //    or override readable-stream.pipe() flow()
    return null;
  }

  if (size && size <= this._buf.length) {
    var data = this._buf.slice(0, size);
    this._buf = Buffers(this._buf.slice(size, this._buf.length));
    return data;
  }

  if (size) {
    size = size - this._buf.length;
  }

  //todo override pipe instead of this hack
  if (size !== null && size !== undefined && !this._readableState.pipeChunkSize) {
    //todo other states that just use PassThrough's read?
    //todo start from buf
    return PassThrough.prototype.read.call(this, size);
  }

  var data = size ? PassThrough.prototype.read.call(this, size) : PassThrough.prototype.read.call(this);
  if (data) {
    var output = this._buf;
    output.push(data);
    var index = output.indexOf(this._opts.pattern);
    if (index === -1 || (this._found && index === 0)) {
      this._found = false;
      //slice off pattern.length - 1 from the end in case the pattern straddles chunks
      var offset = this._readableState.length ? output.length - this._opts.pattern.length + 1 : -1;
      if (offset > 0) {
        this._buf = Buffers([output.slice(offset, output.length)]);
        output = output.slice(0, offset);
      } else {
        output = output.toBuffer();
      }

      return output;
    }

    //lop off everything starting with pattern & put it in buffer for next time
    this._found = true;
    this._buf = Buffers([output.slice(index, output.length)]);
    var result = output.slice(0, index);
    var self = this;
    if (this._readableState.pipesCount) {
      this.unpiping = true;
      process.nextTick(endPipes.bind(this));
    }

    return result;
  } else {
    data = this._buf.toBuffer();
    this._buf = Buffers();
    var output = data.length ? data : null;
    return output;
  }

  function endPipes() {
    var pipes = this._readableState.pipes;
    var pipesCount = this._readableState.pipesCount;
    self.unpipe();
    self.unpiping = false;

    switch (pipesCount) {
    case 1:
      pipes.end();
      break;
    default:
      //todo
      break;
    }
  }
};
<commit_msg>Don't prematurely return entire stream contents in read()<commit_after>'use strict';

module.exports = Until;
var PassThrough = require('stream').PassThrough;
var inherits = require("util").inherits;
var Buffers = require('buffers');

if (!PassThrough) {
  PassThrough = require('readable-stream/passthrough');
}

inherits(Until, PassThrough);

//todo only emit end when buffer is empty
function Until(opts) {
  this._buf = Buffers();
  this._found = false;

  if (typeof opts.pattern === "string") {
    opts.pattern = new Buffer(opts.pattern);
  } else if (!opts.pattern instanceof Buffer) {
    throw new Error('Invalid pattern type')
  }

  this._opts = opts;
  this.unpiping = false;

  //todo allow and handle normal PassThrough opts
  PassThrough.call(this);
}

Until.prototype.read = function (size) {
  if (this.unpiping) {
    //either return null from read() until everything is unpiped
    //    or override readable-stream.pipe() flow()
    return null;
  }

  if (size && size <= this._buf.length) {
    var data = this._buf.slice(0, size);
    this._buf = Buffers(this._buf.slice(size, this._buf.length));
    return data;
  }

  if (size) {
    size = size - this._buf.length;
  }

  //todo override pipe instead of this hack
  if (size !== null && size !== undefined && !this._readableState.pipeChunkSize) {
    //todo other states that just use PassThrough's read?
    //todo start from buf
    return PassThrough.prototype.read.call(this, size);
  }

  var data = size ? PassThrough.prototype.read.call(this, size) : PassThrough.prototype.read.call(this);
  if (data) {
    var output = this._buf;
    output.push(data);
    var index = output.indexOf(this._opts.pattern);
    if (index === -1 || (this._found && index === 0)) {
      this._found = false;
      //slice off pattern.length - 1 from the end in case the pattern straddles chunks
      var offset = this._readableState.ended ? -1 : output.length - this._opts.pattern.length + 1;
      if (offset > 0) {
        this._buf = Buffers([output.slice(offset, output.length)]);
        output = output.slice(0, offset);
      } else {
        this._buf = Buffers();
        output = output.toBuffer();
      }

      return output;
    }

    //lop off everything starting with pattern & put it in buffer for next time
    this._found = true;
    this._buf = Buffers([output.slice(index, output.length)]);
    var result = output.slice(0, index);
    var self = this;
    if (this._readableState.pipesCount) {
      this.unpiping = true;
      process.nextTick(endPipes.bind(this));
    }

    return result;
  } else {
    data = this._buf.toBuffer();
    this._buf = Buffers();
    var output = data.length ? data : null;
    return output;
  }

  function endPipes() {
    var pipes = this._readableState.pipes;
    var pipesCount = this._readableState.pipesCount;
    self.unpipe();
    self.unpiping = false;

    switch (pipesCount) {
    case 1:
      pipes.end();
      break;
    default:
      //todo
      break;
    }
  }
};
<|endoftext|>


<commit_before>var spritesInfo = {
    baseStructure: {
        name: "baseStructure",
        path: "../img/structures/base.png"
    },
    neutralStructure: {
        name: "neutralStructure",
        path: "../img/structures/neutral.png"
    },
    pathMarker: {
        name: "pathMarker",
        path: "../img/missing.png"
    },
    redArmy: {
        name: "redArmy",
        path: "../img/red-flag.png"
    },
    blueArmy: {
        name: "blueArmy",
        path: "../img/blue-flag.png"
    },
};

define({
    mapSize: [32, 32],
    tileSize: 64,

    /**
     * {Object}
     * Available tile types in the application
     */
    mapTileTypes: [{
        typeId: 0,
        typeName: "Network Node",
        fillColor: 0x0000FF,
        strokeColor: 0x000000,
        strokeSize: 2

    }, {
        typeId: 1,
        typeName: "Firewall",
        fillColor: 0xFF0000,
        strokeColor: 0x000000,
        strokeSize: 2
    }, {
        typeId: 2,
        typeName: "Terminal",
        fillColor: 0x00FF00,
        strokeColor: 0x000000,
        strokeSize: 2
    }],

    // by how much (in world coordinates) the camera move everytime a key is
    // pressed.
    mapSpeed: 8,

    spritesInfo: _.cloneDeep(spritesInfo),

    // I miss python:
    // Names = [name for name, _ in spritesInfo if name.endswith('Army')]
    playersName: _.map(
        // get only army sprite
        _.filter(spritesInfo, function(sprite) {
            return sprite.name.match(/Army$/) !== null;
        }),
        // get their name
        function(sprite) {
            return sprite.name;
        }),

    pathPrefix: 'path_',

    baseMovePoint: 6,

    resourcesMap: {
        "gold": {
            index: 0,
            icon: "../img/coins.png"
        },
        "gems": {
            index: 1,
            icon: "../img/diamonds.png"
        },
    },

    armySize: 6,

    factions: {
        badGuys: {
            name: "Bad Guys",
            icon: "../img/missing.png",
            bonus: {},
            initialArmy: {
                bg_base: 5,
            },
        },
        goodGuys: {
            name: "Good Guys",
            icon: "../img/missing.png",
            bonus: {},
            initialArmy: {
                gg_base: 5,
                gg_healer: 2,
            },
        },
    },

    numberOfNeutralStructures: 12

});<commit_msg>simpler map function<commit_after>var spritesInfo = {
    baseStructure: {
        name: "baseStructure",
        path: "../img/structures/base.png"
    },
    neutralStructure: {
        name: "neutralStructure",
        path: "../img/structures/neutral.png"
    },
    pathMarker: {
        name: "pathMarker",
        path: "../img/missing.png"
    },
    redArmy: {
        name: "redArmy",
        path: "../img/red-flag.png"
    },
    blueArmy: {
        name: "blueArmy",
        path: "../img/blue-flag.png"
    },
};

define({
    mapSize: [32, 32],
    tileSize: 64,

    /**
     * {Object}
     * Available tile types in the application
     */
    mapTileTypes: [{
        typeId: 0,
        typeName: "Network Node",
        fillColor: 0x0000FF,
        strokeColor: 0x000000,
        strokeSize: 2

    }, {
        typeId: 1,
        typeName: "Firewall",
        fillColor: 0xFF0000,
        strokeColor: 0x000000,
        strokeSize: 2
    }, {
        typeId: 2,
        typeName: "Terminal",
        fillColor: 0x00FF00,
        strokeColor: 0x000000,
        strokeSize: 2
    }],

    // by how much (in world coordinates) the camera move everytime a key is
    // pressed.
    mapSpeed: 8,

    spritesInfo: _.cloneDeep(spritesInfo),

    // I miss python:
    // Names = [name for name, _ in spritesInfo if name.endswith('Army')]
    playersName: _.pluck(
        // get only army sprite
        _.filter(spritesInfo, function isArmy(sprite) {
            return sprite.name.match(/Army$/) !== null;
        }),
        // get their name
        "name"),

    pathPrefix: 'path_',

    baseMovePoint: 6,

    resourcesMap: {
        "gold": {
            index: 0,
            icon: "../img/coins.png"
        },
        "gems": {
            index: 1,
            icon: "../img/diamonds.png"
        },
    },

    armySize: 6,

    factions: {
        badGuys: {
            name: "Bad Guys",
            icon: "../img/missing.png",
            bonus: {},
            initialArmy: {
                bg_base: 5,
            },
        },
        goodGuys: {
            name: "Good Guys",
            icon: "../img/missing.png",
            bonus: {},
            initialArmy: {
                gg_base: 5,
                gg_healer: 2,
            },
        },
    },

    numberOfNeutralStructures: 12

});<|endoftext|>


<commit_before>/*
 * Copyright 2014 Amadeus s.a.s.
 * 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.
 */

Aria.tplScriptDefinition({
    $classpath : "test.aria.popups.focus.FocusTestTplScript",
    $dependencies : ['aria.utils.validators.Mandatory'],
    $prototype : {
        $dataReady : function () {
            aria.utils.Data.setValidator(this.data, "firstName", new aria.utils.validators.Mandatory("MANDATORY."));
            aria.utils.Data.setValidator(this.data, "lastName", new aria.utils.validators.Mandatory("MANDATORY."));
        },
        $viewReady : function () {
            this.myMethod();
        },
        myMethod : function () {
            aria.utils.Data.validateModel(this.data, {});
        },
        submit : function () {
            this.myMethod();
        },
        anchorClick : function () {
            this.data.error = true;
        }

    }
});
<commit_msg>fix - missing the disposal of an object in a test<commit_after>/*
 * Copyright 2014 Amadeus s.a.s.
 * 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.
 */

Aria.tplScriptDefinition({
    $classpath : "test.aria.popups.focus.FocusTestTplScript",
    $dependencies : ['aria.utils.validators.Mandatory'],
    $destructor : function () {
        this.validator.$dispose();
        this.validator = null;
    },
    $prototype : {
        $dataReady : function () {
            this.validator = new aria.utils.validators.Mandatory("MANDATORY");
            aria.utils.Data.setValidator(this.data, "firstName", this.validator);
            aria.utils.Data.setValidator(this.data, "lastName", this.validator);
        },
        $viewReady : function () {
            this.myMethod();
        },
        myMethod : function () {
            aria.utils.Data.validateModel(this.data, {});
        },
        submit : function () {
            this.myMethod();
        },
        anchorClick : function () {
            this.data.error = true;
        }

    }
});
<|endoftext|>


<commit_before>var config = require('../config');
var utils = require('../utils');
var rp = require('request-promise');
var body_parser = require('body-parser');
var express = require('express');
var co = require('co');

var root = express.Router();
root.use(body_parser.json());
root.use(body_parser.urlencoded({extended: true}));

root.post('/s/', function(req, res) {
  req.session.lastSearch = req.body.keyword;
  var apiRequest = {
    uri: 'https://maps.googleapis.com/maps/api/place/textsearch/json',
    qs: {
      key: config.apiKey,
      query: 'bars near ' + req.body.keyword
    },
    json: true
  };
  rp(apiRequest).then(function (data) {
    res.writeHead(200, {'Content-type': 'text/json; charset=UTF-8'});
    res.end(JSON.stringify(data.results.map(function(item) {
      var ret = {
        id: item.place_id,
        name: item.name,
        address: item.formatted_address
      };
      if (item.hasOwnProperty('photos'))
        ret.photo = '/api/p/?ref=' + item.photos[0].photo_reference;
      return ret;
    })));
  }).catch(utils.onError);
});

root.get('/p/', function(req, res) {
  var apiRequest = {
    uri: 'https://maps.googleapis.com/maps/api/place/photo',
    qs: {
      key: config.apiKey,
      photoreference: req.query.ref,
      maxheight: 100
    },
    resolveWithFullResponse: true
  };
  rp(apiRequest).then(function(data) {
    res.redirect(data.request.uri.href);
  }).catch(utils.onError);
});

module.exports = root;
<commit_msg>Thought searching again after the page being refreshed is kinda annoying, so it happens only once.<commit_after>var config = require('../config');
var utils = require('../utils');
var rp = require('request-promise');
var body_parser = require('body-parser');
var express = require('express');
var co = require('co');

var root = express.Router();
root.use(body_parser.json());
root.use(body_parser.urlencoded({extended: true}));

root.post('/s/', function(req, res) {
  if (!req.session.lastSearch)
    req.session.lastSearch = req.body.keyword;
  else
    req.session.lastSearch = null;
  var apiRequest = {
    uri: 'https://maps.googleapis.com/maps/api/place/textsearch/json',
    qs: {
      key: config.apiKey,
      query: 'bars near ' + req.body.keyword
    },
    json: true
  };
  rp(apiRequest).then(function (data) {
    res.writeHead(200, {'Content-type': 'text/json; charset=UTF-8'});
    res.end(JSON.stringify(data.results.map(function(item) {
      var ret = {
        id: item.place_id,
        name: item.name,
        address: item.formatted_address
      };
      if (item.hasOwnProperty('photos'))
        ret.photo = '/api/p/?ref=' + item.photos[0].photo_reference;
      return ret;
    })));
  }).catch(utils.onError);
});

root.get('/p/', function(req, res) {
  var apiRequest = {
    uri: 'https://maps.googleapis.com/maps/api/place/photo',
    qs: {
      key: config.apiKey,
      photoreference: req.query.ref,
      maxheight: 100
    },
    resolveWithFullResponse: true
  };
  rp(apiRequest).then(function(data) {
    res.redirect(data.request.uri.href);
  }).catch(utils.onError);
});

module.exports = root;
<|endoftext|>


<commit_before>describe("a realm", function() {

	var global = Function('return this')();
	var globalRealm = global.realm || require('..');
	var Realm = globalRealm.constructor;

	var testRealm;

	beforeEach(function() {
		testRealm = new Realm();
	});

	it("does not call definition functions on define.", function() {
		var definitionHasBeenCalled = false;
		testRealm.define('MyClass', function(require, exports, module) {
			definitionHasBeenCalled = true;
			module.exports = function MyClass() {};
		});
		expect(definitionHasBeenCalled).toBe(false);
	});

	it("allows one definition to require a definition defined later.", function() {
		var CLASSA = function() {};
		testRealm.define("ClassB", function(require, exports, module) {
			exports.parent = require("ClassA");
		});
		testRealm.define("ClassA", function(require, exports, module) {
			module.exports = CLASSA;
		});

		var classB = testRealm.require('ClassB');
		expect(classB.parent).toBe(CLASSA);
	});

	it("allows one definition to require another in a relative way.", function() {
		var CLASSA = function() {};
		testRealm.define("my/classes/derived/ClassB", function(require, exports, module) {
			exports.parent = require("../original/ClassA");
		});
		testRealm.define("my/classes/original/ClassA", function(require, exports, module) {
			module.exports = CLASSA;
		});

		var classB = testRealm.require('my/classes/derived/ClassB');
		expect(classB.parent).toBe(CLASSA);
	});

	it("throws an error if there is a circular reference", function() {
		var CLASSA = function() {};
		testRealm.define("ClassA", function(require, exports, module) {
			require("ClassB");
			module.exports = CLASSA;
		});
		var CLASSB = function() {};
		testRealm.define("ClassB", function(require, exports, module) {
			require("ClassA");
			module.exports = CLASSB;
		});

		expect(function() {
			testRealm.require('ClassA');
		}).toThrow(Error("Circular dependency detected: the module 'ClassA' (requested by module 'ClassB') is still in the process of exporting."));
	});

	it("we consider it to be a circular reference even if a module has partially exported", function() {
		var CLASSA = function() {};
		testRealm.define("ClassA", function(require, exports, module) {
			require("ClassB");
			module.exports = CLASSA;
		});
		testRealm.define("ClassB", function(require, exports, module) {
			exports.X = 'X';
			require("ClassA");
			exports.Y = 'Y';
		});

		expect(function() {
			testRealm.require('ClassA');
		}).toThrow(Error("Circular dependency detected: the module 'ClassA' (requested by module 'ClassB') is still in the process of exporting."));
	});

	it("we don't consider it to be a circular reference if the module has already exported at the point the circle is formed", function() {
		var CLASSA = function() {};
		testRealm.define("ClassA", function(require, exports, module) {
			module.exports = CLASSA;
			require("ClassB");
		});
		var CLASSB = function() {};
		testRealm.define("ClassB", function(require, exports, module) {
			require("ClassA");
			module.exports = CLASSB;
		});

		testRealm.require('ClassA');
	});

	it("allows the redefinition of a class in a subrealm.", function() {
		var CLASSA = function() {};
		testRealm.define("my/classes/derived/ClassB", function(require, exports, module) {
			exports.parent = require("../original/ClassA");
		});
		testRealm.define("my/classes/original/ClassA", function(require, exports, module) {
			module.exports = CLASSA;
		});

		var classB = testRealm.require('my/classes/derived/ClassB');
		expect(classB.parent).toBe(CLASSA);

		var REPLACEMENT_CLASSA = function() {};
		expect(CLASSA).not.toBe(REPLACEMENT_CLASSA);
		var subrealm = testRealm.subrealm();

		subrealm.define("my/classes/original/ClassA", function(require, exports, module) {
			module.exports = REPLACEMENT_CLASSA;
		});

		var subrealmClassB = subrealm.require('my/classes/derived/ClassB');
		expect(subrealmClassB).not.toBe(classB);
		expect(subrealmClassB.parent).toBe(REPLACEMENT_CLASSA);
	});
});
<commit_msg>Improved the success-case circular depenendency test so that it verifies that what gets returened when a circular dependency has been detected is actually valid.<commit_after>describe("a realm", function() {

	var global = Function('return this')();
	var globalRealm = global.realm || require('..');
	var Realm = globalRealm.constructor;

	var testRealm;

	beforeEach(function() {
		testRealm = new Realm();
	});

	it("does not call definition functions on define.", function() {
		var definitionHasBeenCalled = false;
		testRealm.define('MyClass', function(require, exports, module) {
			definitionHasBeenCalled = true;
			module.exports = function MyClass() {};
		});
		expect(definitionHasBeenCalled).toBe(false);
	});

	it("allows one definition to require a definition defined later.", function() {
		var CLASSA = function() {};
		testRealm.define("ClassB", function(require, exports, module) {
			exports.parent = require("ClassA");
		});
		testRealm.define("ClassA", function(require, exports, module) {
			module.exports = CLASSA;
		});

		var classB = testRealm.require('ClassB');
		expect(classB.parent).toBe(CLASSA);
	});

	it("allows one definition to require another in a relative way.", function() {
		var CLASSA = function() {};
		testRealm.define("my/classes/derived/ClassB", function(require, exports, module) {
			exports.parent = require("../original/ClassA");
		});
		testRealm.define("my/classes/original/ClassA", function(require, exports, module) {
			module.exports = CLASSA;
		});

		var classB = testRealm.require('my/classes/derived/ClassB');
		expect(classB.parent).toBe(CLASSA);
	});

	it("throws an error if there is a circular reference", function() {
		var CLASSA = function() {};
		testRealm.define("ClassA", function(require, exports, module) {
			require("ClassB");
			module.exports = CLASSA;
		});
		var CLASSB = function() {};
		testRealm.define("ClassB", function(require, exports, module) {
			require("ClassA");
			module.exports = CLASSB;
		});

		expect(function() {
			testRealm.require('ClassA');
		}).toThrow(Error("Circular dependency detected: the module 'ClassA' (requested by module 'ClassB') is still in the process of exporting."));
	});

	it("we consider it to be a circular reference even if a module has partially exported", function() {
		var CLASSA = function() {};
		testRealm.define("ClassA", function(require, exports, module) {
			require("ClassB");
			module.exports = CLASSA;
		});
		testRealm.define("ClassB", function(require, exports, module) {
			exports.X = 'X';
			require("ClassA");
			exports.Y = 'Y';
		});

		expect(function() {
			testRealm.require('ClassA');
		}).toThrow(Error("Circular dependency detected: the module 'ClassA' (requested by module 'ClassB') is still in the process of exporting."));
	});

	it("we don't consider it to be a circular reference if the module has already exported at the point the circle is formed", function() {
		testRealm.define("ClassA", function(require, exports, module) {
			function LocalClass() {
			};
			module.exports = LocalClass;
			require("ClassB");
		});
		testRealm.define("ClassB", function(require, exports, module) {
			var SuperClass = require("ClassA");
			function LocalClass() {
			};
			LocalClass.prototype = new SuperClass();
			module.exports = LocalClass;
		});

		var ClassA = testRealm.require('ClassA');
		var ClassB = testRealm.require('ClassB');
		expect((new ClassB()) instanceof ClassA).toBeTruthy();
	});

	it("allows the redefinition of a class in a subrealm.", function() {
		var CLASSA = function() {};
		testRealm.define("my/classes/derived/ClassB", function(require, exports, module) {
			exports.parent = require("../original/ClassA");
		});
		testRealm.define("my/classes/original/ClassA", function(require, exports, module) {
			module.exports = CLASSA;
		});

		var classB = testRealm.require('my/classes/derived/ClassB');
		expect(classB.parent).toBe(CLASSA);

		var REPLACEMENT_CLASSA = function() {};
		expect(CLASSA).not.toBe(REPLACEMENT_CLASSA);
		var subrealm = testRealm.subrealm();

		subrealm.define("my/classes/original/ClassA", function(require, exports, module) {
			module.exports = REPLACEMENT_CLASSA;
		});

		var subrealmClassB = subrealm.require('my/classes/derived/ClassB');
		expect(subrealmClassB).not.toBe(classB);
		expect(subrealmClassB.parent).toBe(REPLACEMENT_CLASSA);
	});
});
<|endoftext|>


<commit_before>import window from '../window';
import * as util from '../util';
import Collection from '../collection';
import * as is from '../is';
import Promise from '../promise';
import define from '../define';

import addRemove from './add-remove';
import animation from './animation';
import events from './events';
import exportFormat from './export';
import layout from './layout';
import notification from './notification';
import renderer from './renderer';
import search from './search';
import style from './style';
import viewport from './viewport';

let Core = function( opts ){
  let cy = this;

  opts = util.extend( {}, opts );

  let container = opts.container;

  // allow for passing a wrapped jquery object
  // e.g. cytoscape({ container: $('#cy') })
  if( container && !is.htmlElement( container ) && is.htmlElement( container[0] ) ){
    container = container[0];
  }

  let reg = container ? container._cyreg : null; // e.g. already registered some info (e.g. readies) via jquery
  reg = reg || {};

  if( reg && reg.cy ){
    reg.cy.destroy();

    reg = {}; // old instance => replace reg completely
  }

  let readies = reg.readies = reg.readies || [];

  if( container ){ container._cyreg = reg; } // make sure container assoc'd reg points to this cy
  reg.cy = cy;

  let head = window !== undefined && container !== undefined && !opts.headless;
  let options = opts;
  options.layout = util.extend( { name: head ? 'grid' : 'null' }, options.layout );
  options.renderer = util.extend( { name: head ? 'canvas' : 'null' }, options.renderer );

  let defVal = function( def, val, altVal ){
    if( val !== undefined ){
      return val;
    } else if( altVal !== undefined ){
      return altVal;
    } else {
      return def;
    }
  };

  let _p = this._private = {
    container: container, // html dom ele container
    ready: false, // whether ready has been triggered
    options: options, // cached options
    elements: new Collection( this ), // elements in the graph
    listeners: [], // list of listeners
    aniEles: new Collection( this ), // elements being animated
    scratch: {}, // scratch object for core
    layout: null,
    renderer: null,
    destroyed: false, // whether destroy was called
    notificationsEnabled: true, // whether notifications are sent to the renderer
    minZoom: 1e-50,
    maxZoom: 1e50,
    zoomingEnabled: defVal( true, options.zoomingEnabled ),
    userZoomingEnabled: defVal( true, options.userZoomingEnabled ),
    panningEnabled: defVal( true, options.panningEnabled ),
    userPanningEnabled: defVal( true, options.userPanningEnabled ),
    boxSelectionEnabled: defVal( true, options.boxSelectionEnabled ),
    autolock: defVal( false, options.autolock, options.autolockNodes ),
    autoungrabify: defVal( false, options.autoungrabify, options.autoungrabifyNodes ),
    autounselectify: defVal( false, options.autounselectify ),
    styleEnabled: options.styleEnabled === undefined ? head : options.styleEnabled,
    zoom: is.number( options.zoom ) ? options.zoom : 1,
    pan: {
      x: is.plainObject( options.pan ) && is.number( options.pan.x ) ? options.pan.x : 0,
      y: is.plainObject( options.pan ) && is.number( options.pan.y ) ? options.pan.y : 0
    },
    animation: { // object for currently-running animations
      current: [],
      queue: []
    },
    hasCompoundNodes: false
  };

  this.createEmitter();

  // set selection type
  this.selectionType( options.selectionType );

  // init zoom bounds
  this.zoomRange({ min: options.minZoom, max: options.maxZoom });

  let loadExtData = function( extData, next ){
    let anyIsPromise = extData.some( is.promise );

    if( anyIsPromise ){
      return Promise.all( extData ).then( next ); // load all data asynchronously, then exec rest of init
    } else {
      next( extData ); // exec synchronously for convenience
    }
  };

  // start with the default stylesheet so we have something before loading an external stylesheet
  if( _p.styleEnabled ){
    cy.setStyle([]);
  }

  // create the renderer
  cy.initRenderer( options.renderer );

  let setElesAndLayout = function( elements, onload, ondone ){
    cy.notifications( false );

    // remove old elements
    let oldEles = cy.mutableElements();
    if( oldEles.length > 0 ){
      oldEles.remove();
    }

    if( elements != null ){
      if( is.plainObject( elements ) || is.array( elements ) ){
        cy.add( elements );
      }
    }

    cy.one( 'layoutready', function( e ){
      cy.notifications( true );
      cy.emit( e ); // we missed this event by turning notifications off, so pass it on

      cy.one( 'load', onload );
      cy.emitAndNotify( 'load' );
    } ).one( 'layoutstop', function(){
      cy.one( 'done', ondone );
      cy.emit( 'done' );
    } );

    let layoutOpts = util.extend( {}, cy._private.options.layout );
    layoutOpts.eles = cy.elements();

    cy.layout( layoutOpts ).run();
  };

  loadExtData([ options.style, options.elements ], function( thens ){
    let initStyle = thens[0];
    let initEles = thens[1];

    // init style
    if( _p.styleEnabled ){
      cy.style().append( initStyle );
    }

    // initial load
    setElesAndLayout( initEles, function(){ // onready
      cy.startAnimationLoop();
      _p.ready = true;

      // if a ready callback is specified as an option, the bind it
      if( is.fn( options.ready ) ){
        cy.on( 'ready', options.ready );
      }

      // bind all the ready handlers registered before creating this instance
      for( let i = 0; i < readies.length; i++ ){
        let fn = readies[ i ];
        cy.on( 'ready', fn );
      }
      if( reg ){ reg.readies = []; } // clear b/c we've bound them all and don't want to keep it around in case a new core uses the same div etc

      cy.emit( 'ready' );
    }, options.done );

  } );
};

let corefn = Core.prototype; // short alias

util.extend( corefn, {
  instanceString: function(){
    return 'core';
  },

  isReady: function(){
    return this._private.ready;
  },

  isDestroyed: function(){
    return this._private.destroyed;
  },

  ready: function( fn ){
    if( this.isReady() ){
      this.emitter().emit( 'ready', [], fn ); // just calls fn as though triggered via ready event
    } else {
      this.on( 'ready', fn );
    }

    return this;
  },

  destroy: function(){
    let cy = this;
    if( cy.isDestroyed() ) return;

    cy.stopAnimationLoop();

    cy.destroyRenderer();

    this.emit( 'destroy' );

    cy._private.destroyed = true;

    return cy;
  },

  hasElementWithId: function( id ){
    return this._private.elements.hasElementWithId( id );
  },

  getElementById: function( id ){
    return this._private.elements.getElementById( id );
  },

  hasCompoundNodes: function(){
    return this._private.hasCompoundNodes;
  },

  headless: function(){
    return this._private.renderer.isHeadless();
  },

  styleEnabled: function(){
    return this._private.styleEnabled;
  },

  addToPool: function( eles ){
    this._private.elements.merge( eles );

    return this; // chaining
  },

  removeFromPool: function( eles ){
    this._private.elements.unmerge( eles );

    return this;
  },

  container: function(){
    return this._private.container || null;
  },

  mount: function( container, rendererOptions ){
    if( container == null ){ return; }

    let cy = this;
    let _p = cy._private;
    let options = _p.options;

    let rOpts = rendererOptions ? rendererOptions : { name: 'canvas' };
    options.renderer = rOpts;

    if( !is.htmlElement( container ) && is.htmlElement( container[0] ) ){
      container = container[0];
    }

    cy.stopAnimationLoop();

    cy.destroyRenderer();

    _p.container = container;
    _p.styleEnabled = true;

    cy.initRenderer( rOpts );

    cy.startAnimationLoop();

    cy.style( options.style );

    cy.emit( 'mount' );

    return cy;
  },

  unmount: function(){
    let cy = this;

    cy.stopAnimationLoop();

    cy.destroyRenderer();

    cy.initRenderer( { name: 'null' } );

    cy.emit( 'unmount' );

    return cy;
  },

  options: function(){
    return util.copy( this._private.options );
  },

  json: function( obj ){
    let cy = this;
    let _p = cy._private;
    let eles = cy.mutableElements();

    if( is.plainObject( obj ) ){ // set

      cy.startBatch();

      if( obj.elements ){
        let idInJson = {};

        let updateEles = function( jsons, gr ){
          let toAdd = [];
          let toMod = [];

          for( let i = 0; i < jsons.length; i++ ){
            let json = jsons[ i ];
            let id = json.data.id;
            let ele = cy.getElementById( id );

            idInJson[ id ] = true;

            if( ele.length !== 0 ){ // existing element should be updated
              toMod.push({ ele, json });
            } else { // otherwise should be added
              if( gr ){
                json.group = gr;

                toAdd.push( json );
              } else {
                toAdd.push( json );
              }
            }
          }

          cy.add( toAdd );

          for( let i = 0; i < toMod.length; i++ ){
            let { ele, json } = toMod[i];

            ele.json(json);
          }
        };

        if( is.array( obj.elements ) ){ // elements: []
          updateEles( obj.elements );

        } else { // elements: { nodes: [], edges: [] }
          let grs = [ 'nodes', 'edges' ];
          for( let i = 0; i < grs.length; i++ ){
            let gr = grs[ i ];
            let elements = obj.elements[ gr ];

            if( is.array( elements ) ){
              updateEles( elements, gr );
            }
          }
        }

        let parentsToRemove = cy.collection();

        (eles
          .filter(ele => !idInJson[ ele.id() ])
          .forEach(ele => {
            if( idInJson[ ele.id() ] ){ return true; }

            if ( ele.isParent() ) {
              parentsToRemove.merge(ele);
            } else {
              ele.remove();
            }
          })
        );

        parentsToRemove.forEach( function ( ele ) {
          ele.children().move({ parent: null }); // so that children are not removed w/
          ele.remove();
        } );

      }

      if( obj.style ){
        cy.style( obj.style );
      }

      if( obj.zoom != null && obj.zoom !== _p.zoom ){
        cy.zoom( obj.zoom );
      }

      if( obj.pan ){
        if( obj.pan.x !== _p.pan.x || obj.pan.y !== _p.pan.y ){
          cy.pan( obj.pan );
        }
      }

      let fields = [
        'minZoom', 'maxZoom', 'zoomingEnabled', 'userZoomingEnabled',
        'panningEnabled', 'userPanningEnabled',
        'boxSelectionEnabled',
        'autolock', 'autoungrabify', 'autounselectify'
      ];

      for( let i = 0; i < fields.length; i++ ){
        let f = fields[ i ];

        if( obj[ f ] != null ){
          cy[ f ]( obj[ f ] );
        }
      }

      cy.endBatch();

      return this; // chaining
    } else { // get
      let flat = !!obj;
      let json = {};

      if( flat ){
        json.elements = this.elements().map( ele => ele.json() );
      } else {
        json.elements = {};

        eles.forEach( function( ele ){
          let group = ele.group();

          if( !json.elements[ group ] ){
            json.elements[ group ] = [];
          }

          json.elements[ group ].push( ele.json() );
        } );
      }

      if( this._private.styleEnabled ){
        json.style = cy.style().json();
      }

      let options = _p.options;

      json.zoomingEnabled = _p.zoomingEnabled;
      json.userZoomingEnabled = _p.userZoomingEnabled;
      json.zoom = _p.zoom;
      json.minZoom = _p.minZoom;
      json.maxZoom = _p.maxZoom;
      json.panningEnabled = _p.panningEnabled;
      json.userPanningEnabled = _p.userPanningEnabled;
      json.pan = util.copy( _p.pan );
      json.boxSelectionEnabled = _p.boxSelectionEnabled;
      json.renderer = util.copy( options.renderer );
      json.hideEdgesOnViewport = options.hideEdgesOnViewport;
      json.textureOnViewport = options.textureOnViewport;
      json.wheelSensitivity = options.wheelSensitivity;
      json.motionBlur = options.motionBlur;

      return json;
    }
  },

  scratch: define.data( {
    field: 'scratch',
    bindingEvent: 'scratch',
    allowBinding: true,
    allowSetting: true,
    settingEvent: 'scratch',
    settingTriggersEvent: true,
    triggerFnName: 'trigger',
    allowGetting: true
  } ),

  removeScratch: define.removeData( {
    field: 'scratch',
    event: 'scratch',
    triggerFnName: 'trigger',
    triggerEvent: true
  } )

} );

corefn.$id = corefn.getElementById;

[
  addRemove,
  animation,
  events,
  exportFormat,
  layout,
  notification,
  renderer,
  search,
  style,
  viewport,
].forEach( function( props ){
  util.extend( corefn, props );
} );

export default Core;
<commit_msg>Do move and remove re. `parentsToRemove` in two steps with fresh refs<commit_after>import window from '../window';
import * as util from '../util';
import Collection from '../collection';
import * as is from '../is';
import Promise from '../promise';
import define from '../define';

import addRemove from './add-remove';
import animation from './animation';
import events from './events';
import exportFormat from './export';
import layout from './layout';
import notification from './notification';
import renderer from './renderer';
import search from './search';
import style from './style';
import viewport from './viewport';

let Core = function( opts ){
  let cy = this;

  opts = util.extend( {}, opts );

  let container = opts.container;

  // allow for passing a wrapped jquery object
  // e.g. cytoscape({ container: $('#cy') })
  if( container && !is.htmlElement( container ) && is.htmlElement( container[0] ) ){
    container = container[0];
  }

  let reg = container ? container._cyreg : null; // e.g. already registered some info (e.g. readies) via jquery
  reg = reg || {};

  if( reg && reg.cy ){
    reg.cy.destroy();

    reg = {}; // old instance => replace reg completely
  }

  let readies = reg.readies = reg.readies || [];

  if( container ){ container._cyreg = reg; } // make sure container assoc'd reg points to this cy
  reg.cy = cy;

  let head = window !== undefined && container !== undefined && !opts.headless;
  let options = opts;
  options.layout = util.extend( { name: head ? 'grid' : 'null' }, options.layout );
  options.renderer = util.extend( { name: head ? 'canvas' : 'null' }, options.renderer );

  let defVal = function( def, val, altVal ){
    if( val !== undefined ){
      return val;
    } else if( altVal !== undefined ){
      return altVal;
    } else {
      return def;
    }
  };

  let _p = this._private = {
    container: container, // html dom ele container
    ready: false, // whether ready has been triggered
    options: options, // cached options
    elements: new Collection( this ), // elements in the graph
    listeners: [], // list of listeners
    aniEles: new Collection( this ), // elements being animated
    scratch: {}, // scratch object for core
    layout: null,
    renderer: null,
    destroyed: false, // whether destroy was called
    notificationsEnabled: true, // whether notifications are sent to the renderer
    minZoom: 1e-50,
    maxZoom: 1e50,
    zoomingEnabled: defVal( true, options.zoomingEnabled ),
    userZoomingEnabled: defVal( true, options.userZoomingEnabled ),
    panningEnabled: defVal( true, options.panningEnabled ),
    userPanningEnabled: defVal( true, options.userPanningEnabled ),
    boxSelectionEnabled: defVal( true, options.boxSelectionEnabled ),
    autolock: defVal( false, options.autolock, options.autolockNodes ),
    autoungrabify: defVal( false, options.autoungrabify, options.autoungrabifyNodes ),
    autounselectify: defVal( false, options.autounselectify ),
    styleEnabled: options.styleEnabled === undefined ? head : options.styleEnabled,
    zoom: is.number( options.zoom ) ? options.zoom : 1,
    pan: {
      x: is.plainObject( options.pan ) && is.number( options.pan.x ) ? options.pan.x : 0,
      y: is.plainObject( options.pan ) && is.number( options.pan.y ) ? options.pan.y : 0
    },
    animation: { // object for currently-running animations
      current: [],
      queue: []
    },
    hasCompoundNodes: false
  };

  this.createEmitter();

  // set selection type
  this.selectionType( options.selectionType );

  // init zoom bounds
  this.zoomRange({ min: options.minZoom, max: options.maxZoom });

  let loadExtData = function( extData, next ){
    let anyIsPromise = extData.some( is.promise );

    if( anyIsPromise ){
      return Promise.all( extData ).then( next ); // load all data asynchronously, then exec rest of init
    } else {
      next( extData ); // exec synchronously for convenience
    }
  };

  // start with the default stylesheet so we have something before loading an external stylesheet
  if( _p.styleEnabled ){
    cy.setStyle([]);
  }

  // create the renderer
  cy.initRenderer( options.renderer );

  let setElesAndLayout = function( elements, onload, ondone ){
    cy.notifications( false );

    // remove old elements
    let oldEles = cy.mutableElements();
    if( oldEles.length > 0 ){
      oldEles.remove();
    }

    if( elements != null ){
      if( is.plainObject( elements ) || is.array( elements ) ){
        cy.add( elements );
      }
    }

    cy.one( 'layoutready', function( e ){
      cy.notifications( true );
      cy.emit( e ); // we missed this event by turning notifications off, so pass it on

      cy.one( 'load', onload );
      cy.emitAndNotify( 'load' );
    } ).one( 'layoutstop', function(){
      cy.one( 'done', ondone );
      cy.emit( 'done' );
    } );

    let layoutOpts = util.extend( {}, cy._private.options.layout );
    layoutOpts.eles = cy.elements();

    cy.layout( layoutOpts ).run();
  };

  loadExtData([ options.style, options.elements ], function( thens ){
    let initStyle = thens[0];
    let initEles = thens[1];

    // init style
    if( _p.styleEnabled ){
      cy.style().append( initStyle );
    }

    // initial load
    setElesAndLayout( initEles, function(){ // onready
      cy.startAnimationLoop();
      _p.ready = true;

      // if a ready callback is specified as an option, the bind it
      if( is.fn( options.ready ) ){
        cy.on( 'ready', options.ready );
      }

      // bind all the ready handlers registered before creating this instance
      for( let i = 0; i < readies.length; i++ ){
        let fn = readies[ i ];
        cy.on( 'ready', fn );
      }
      if( reg ){ reg.readies = []; } // clear b/c we've bound them all and don't want to keep it around in case a new core uses the same div etc

      cy.emit( 'ready' );
    }, options.done );

  } );
};

let corefn = Core.prototype; // short alias

util.extend( corefn, {
  instanceString: function(){
    return 'core';
  },

  isReady: function(){
    return this._private.ready;
  },

  isDestroyed: function(){
    return this._private.destroyed;
  },

  ready: function( fn ){
    if( this.isReady() ){
      this.emitter().emit( 'ready', [], fn ); // just calls fn as though triggered via ready event
    } else {
      this.on( 'ready', fn );
    }

    return this;
  },

  destroy: function(){
    let cy = this;
    if( cy.isDestroyed() ) return;

    cy.stopAnimationLoop();

    cy.destroyRenderer();

    this.emit( 'destroy' );

    cy._private.destroyed = true;

    return cy;
  },

  hasElementWithId: function( id ){
    return this._private.elements.hasElementWithId( id );
  },

  getElementById: function( id ){
    return this._private.elements.getElementById( id );
  },

  hasCompoundNodes: function(){
    return this._private.hasCompoundNodes;
  },

  headless: function(){
    return this._private.renderer.isHeadless();
  },

  styleEnabled: function(){
    return this._private.styleEnabled;
  },

  addToPool: function( eles ){
    this._private.elements.merge( eles );

    return this; // chaining
  },

  removeFromPool: function( eles ){
    this._private.elements.unmerge( eles );

    return this;
  },

  container: function(){
    return this._private.container || null;
  },

  mount: function( container, rendererOptions ){
    if( container == null ){ return; }

    let cy = this;
    let _p = cy._private;
    let options = _p.options;

    let rOpts = rendererOptions ? rendererOptions : { name: 'canvas' };
    options.renderer = rOpts;

    if( !is.htmlElement( container ) && is.htmlElement( container[0] ) ){
      container = container[0];
    }

    cy.stopAnimationLoop();

    cy.destroyRenderer();

    _p.container = container;
    _p.styleEnabled = true;

    cy.initRenderer( rOpts );

    cy.startAnimationLoop();

    cy.style( options.style );

    cy.emit( 'mount' );

    return cy;
  },

  unmount: function(){
    let cy = this;

    cy.stopAnimationLoop();

    cy.destroyRenderer();

    cy.initRenderer( { name: 'null' } );

    cy.emit( 'unmount' );

    return cy;
  },

  options: function(){
    return util.copy( this._private.options );
  },

  json: function( obj ){
    let cy = this;
    let _p = cy._private;
    let eles = cy.mutableElements();
    let getFreshRef = ele => cy.getElementById(ele.id());

    if( is.plainObject( obj ) ){ // set

      cy.startBatch();

      if( obj.elements ){
        let idInJson = {};

        let updateEles = function( jsons, gr ){
          let toAdd = [];
          let toMod = [];

          for( let i = 0; i < jsons.length; i++ ){
            let json = jsons[ i ];
            let id = json.data.id;
            let ele = cy.getElementById( id );

            idInJson[ id ] = true;

            if( ele.length !== 0 ){ // existing element should be updated
              toMod.push({ ele, json });
            } else { // otherwise should be added
              if( gr ){
                json.group = gr;

                toAdd.push( json );
              } else {
                toAdd.push( json );
              }
            }
          }

          cy.add( toAdd );

          for( let i = 0; i < toMod.length; i++ ){
            let { ele, json } = toMod[i];

            ele.json(json);
          }
        };

        if( is.array( obj.elements ) ){ // elements: []
          updateEles( obj.elements );

        } else { // elements: { nodes: [], edges: [] }
          let grs = [ 'nodes', 'edges' ];
          for( let i = 0; i < grs.length; i++ ){
            let gr = grs[ i ];
            let elements = obj.elements[ gr ];

            if( is.array( elements ) ){
              updateEles( elements, gr );
            }
          }
        }

        let parentsToRemove = cy.collection();

        (eles
          .filter(ele => !idInJson[ ele.id() ])
          .forEach(ele => {
            if( idInJson[ ele.id() ] ){ return true; }

            if ( ele.isParent() ) {
              parentsToRemove.merge(ele);
            } else {
              ele.remove();
            }
          })
        );

        // so that children are not removed w/parent
        parentsToRemove.forEach(ele => ele.children().move({ parent: null }));

        // intermediate parents may be moved by prior line, so make sure we remove by fresh refs
        parentsToRemove.forEach(ele => getFreshRef(ele).remove());
      }

      if( obj.style ){
        cy.style( obj.style );
      }

      if( obj.zoom != null && obj.zoom !== _p.zoom ){
        cy.zoom( obj.zoom );
      }

      if( obj.pan ){
        if( obj.pan.x !== _p.pan.x || obj.pan.y !== _p.pan.y ){
          cy.pan( obj.pan );
        }
      }

      let fields = [
        'minZoom', 'maxZoom', 'zoomingEnabled', 'userZoomingEnabled',
        'panningEnabled', 'userPanningEnabled',
        'boxSelectionEnabled',
        'autolock', 'autoungrabify', 'autounselectify'
      ];

      for( let i = 0; i < fields.length; i++ ){
        let f = fields[ i ];

        if( obj[ f ] != null ){
          cy[ f ]( obj[ f ] );
        }
      }

      cy.endBatch();

      return this; // chaining
    } else { // get
      let flat = !!obj;
      let json = {};

      if( flat ){
        json.elements = this.elements().map( ele => ele.json() );
      } else {
        json.elements = {};

        eles.forEach( function( ele ){
          let group = ele.group();

          if( !json.elements[ group ] ){
            json.elements[ group ] = [];
          }

          json.elements[ group ].push( ele.json() );
        } );
      }

      if( this._private.styleEnabled ){
        json.style = cy.style().json();
      }

      let options = _p.options;

      json.zoomingEnabled = _p.zoomingEnabled;
      json.userZoomingEnabled = _p.userZoomingEnabled;
      json.zoom = _p.zoom;
      json.minZoom = _p.minZoom;
      json.maxZoom = _p.maxZoom;
      json.panningEnabled = _p.panningEnabled;
      json.userPanningEnabled = _p.userPanningEnabled;
      json.pan = util.copy( _p.pan );
      json.boxSelectionEnabled = _p.boxSelectionEnabled;
      json.renderer = util.copy( options.renderer );
      json.hideEdgesOnViewport = options.hideEdgesOnViewport;
      json.textureOnViewport = options.textureOnViewport;
      json.wheelSensitivity = options.wheelSensitivity;
      json.motionBlur = options.motionBlur;

      return json;
    }
  },

  scratch: define.data( {
    field: 'scratch',
    bindingEvent: 'scratch',
    allowBinding: true,
    allowSetting: true,
    settingEvent: 'scratch',
    settingTriggersEvent: true,
    triggerFnName: 'trigger',
    allowGetting: true
  } ),

  removeScratch: define.removeData( {
    field: 'scratch',
    event: 'scratch',
    triggerFnName: 'trigger',
    triggerEvent: true
  } )

} );

corefn.$id = corefn.getElementById;

[
  addRemove,
  animation,
  events,
  exportFormat,
  layout,
  notification,
  renderer,
  search,
  style,
  viewport,
].forEach( function( props ){
  util.extend( corefn, props );
} );

export default Core;
<|endoftext|>