<commit_before>'use strict';

const Component = require('./component.js');

const _visible_tiles = Symbol('_visible_tiles');

// This is used for seeing and hearing text. Relevant to
class Hearer extends Component {
	constructor(atom, template) {
		super(atom, template);
		this[_visible_tiles] = new Set();
		this.update_visible_tiles();
		this.is_updating_visible_tiles = false;
		this.a.on("moved", this.enqueue_update_visible_tiles.bind(this));
	}

	update_visible_tiles() {
		var new_visible = this.a.server.compute_visible_tiles(this.atom, 8, false);
		var old_visible = this[_visible_tiles];
		var added = [...new_visible].filter((item) => {return !old_visible.has(item);});
		var removed = [...old_visible].filter((item) => {return !new_visible.has(item);});
		this[_visible_tiles] = new_visible;
		for(let tile of added) {
			tile.hearers.push(this.atom);
		}
		for(let tile of removed) {
			tile.hearers.splice(tile.viewers.indexOf(this.atom), 1);
		}
		this.is_updating_visible_tiles = false;
	}

	enqueue_update_visible_tiles() {
		if(this.is_updating_visible_tiles)
			return;
		process.nextTick(this.update_visible_tiles.bind(this));
		this.is_updating_visible_tiles = true;
	}

	get visible_tiles() {
		return this[_visible_tiles][Symbol.iterator].bind(this);
	}

	can_hear_sound() {
		return this.can_hear();
	}

	can_hear() {
		return true;
	}

	can_see(atom) {
		return atom && atom.loc && atom.loc == atom.base_loc;
	}

	in_view(atom) {
		for(var tile of atom.partial_locs())
			if(tile.hearers.includes(this))
				return true;
		return false;
	}

	show_message(message) {
		var can_hear = this.a.c.Hearer.can_hear(message.emitter);
		var can_see = this.a.c.Hearer.can_see(message.emitter);
		if(!can_see && !can_hear)
			return;
		if(message.type == "see" && !can_see)
			return message.blind_message;
		if(message.type == "hear" && !can_hear)
			return message.deaf_message;
		if(message.self_message && message.emitter == this.a)
			return message.self_message;
		return message.message;
	}
}

module.exports.components = {Hearer};
<commit_msg>Fixes copy-paste error<commit_after>'use strict';

const Component = require('./component.js');

const _visible_tiles = Symbol('_visible_tiles');

// This is used for seeing and hearing text. Relevant to
class Hearer extends Component {
	constructor(atom, template) {
		super(atom, template);
		this[_visible_tiles] = new Set();
		this.update_visible_tiles();
		this.is_updating_visible_tiles = false;
		this.a.on("moved", this.enqueue_update_visible_tiles.bind(this));
	}

	update_visible_tiles() {
		var new_visible = this.a.server.compute_visible_tiles(this.atom, 8, false);
		var old_visible = this[_visible_tiles];
		var added = [...new_visible].filter((item) => {return !old_visible.has(item);});
		var removed = [...old_visible].filter((item) => {return !new_visible.has(item);});
		this[_visible_tiles] = new_visible;
		for(let tile of added) {
			tile.hearers.push(this.atom);
		}
		for(let tile of removed) {
			tile.hearers.splice(tile.hearers.indexOf(this.atom), 1);
		}
		this.is_updating_visible_tiles = false;
	}

	enqueue_update_visible_tiles() {
		if(this.is_updating_visible_tiles)
			return;
		process.nextTick(this.update_visible_tiles.bind(this));
		this.is_updating_visible_tiles = true;
	}

	get visible_tiles() {
		return this[_visible_tiles][Symbol.iterator].bind(this);
	}

	can_hear_sound() {
		return this.can_hear();
	}

	can_hear() {
		return true;
	}

	can_see(atom) {
		return atom && atom.loc && atom.loc == atom.base_loc;
	}

	in_view(atom) {
		for(var tile of atom.partial_locs())
			if(tile.hearers.includes(this))
				return true;
		return false;
	}

	show_message(message) {
		var can_hear = this.a.c.Hearer.can_hear(message.emitter);
		var can_see = this.a.c.Hearer.can_see(message.emitter);
		if(!can_see && !can_hear)
			return;
		if(message.type == "see" && !can_see)
			return message.blind_message;
		if(message.type == "hear" && !can_hear)
			return message.deaf_message;
		if(message.self_message && message.emitter == this.a)
			return message.self_message;
		return message.message;
	}
}

module.exports.components = {Hearer};
<|endoftext|>


<commit_before>/*eslint es6:true */
describe('Errors', function () {
  var o_o = require('yield-yield');
  var expect = require('chai').expect;

  it('breaks before first yield', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });

  });

  it('breaks after first yield before second yield', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after second yield in async', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      setTimeout(cb, 50);
      var result = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after second yield in sync', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      cb();
      var result = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after third yield', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      cb();
      var result = yield;
      var cb1 = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after fourth yield', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      cb();
      var result = yield;
      var cb1 = yield;
      cb1();
      result = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after fourth yield in async', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      cb();
      var result = yield;
      var cb1 = yield;
      setTimeout(cb1, 50);
      result = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('should show error if cb is called twice after second yield sync', function (done) {
    var counter = 0;
    var finished = false;

    o_o(function *() {

      var cb = yield;
      cb();
      var ret = yield;

      expect(function () {
        cb();
      }).to.throw('Callback is called twice');
      finished = true;

    })(function (err) {

      counter++;
      expect(counter).to.equal(1);
      expect(finished).to.be.true;

      return done();
    });
  });

  it('should show error if cb is called twice after second yield async', function (done) {
    var counter = 0;
    o_o(function *() {

      var cb = yield;
      cb();
      var ret = yield;

      setTimeout(function () {
        expect(function () {
          cb();
        }).to.throw('Callback is called twice');
        throw new Error('Should not trigger second time call into the callback');
      }, 50);

    })(function (err) {
      counter++;
      expect(counter).to.equal(1);
      expect(err).to.be.not.ok;

      return done();
    });
  });

  it('should show error if cb is called twice before yield in sync', function (done) {
    var finished = false;

    o_o(function *() {

      var cb = yield;
      cb();
      expect(function () {
        cb();
      }).to.throw('Callback is called twice');

      yield;

      finished = true;

    })(function (err) {

      expect(finished).to.be.true;
      return done();
    });
  });

  it('should show error when generator returns before in sync', function (done) {

      var fnc = o_o(function *() {
        var cb = yield;
        cb(null, 'result one');
        return;
      });

      fnc(function (err) {
        expect(err.message).to.include('Generator has no second yield statement');
        return done();
      });

  });

  it('should show error when generator returns before in async', function (done) {

      var fnc = o_o(function *() {
        var cb = yield;

        setTimeout(function () {
          cb(null, 'result one');
        }, 50);

        return;
      });

      fnc(function (err) {
        expect(err.message).to.include('Generator has no second yield statement');
        return done();
      });

  });

  it('should give error that function is not a generator', function () {
    expect(function () {
      o_o(function () {});
    }).to.throw('Function is not a Generator');

  });

//  it('should detach from the main thread when calling cb', function (done) {
//
//    var counter = 0;
//
//    o_o(function *() {
//      yield (yield)();
//    })(function (err) {
//      counter++;
//      expect(counter).to.be.equal(1);
//      done();
//      throw new Error();
//    });
//
//  });

});
<commit_msg>Fixing tests<commit_after>/*eslint es6:true */
describe('Errors', function () {
  var o_o = require('yield-yield');
  var expect = require('chai').expect;

  it('breaks before first yield', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });

  });

  it('breaks after first yield before second yield', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after second yield in async', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      setTimeout(cb, 50);
      var result = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after second yield in sync', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      cb();
      var result = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after third yield', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      cb();
      var result = yield;
      var cb1 = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after fourth yield', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      cb();
      var result = yield;
      var cb1 = yield;
      cb1();
      result = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('breaks after fourth yield in async', function (done) {
    var msg = 'error #' + ~~(Math.random() * 1000);
    var fnc = o_o(function *() {
      var cb = yield;
      cb();
      var result = yield;
      var cb1 = yield;
      setTimeout(cb1, 50);
      result = yield;
      throw new Error(msg);
    });

    fnc(function (err) {
      expect(err.message).to.be.equal(msg);
      return done();
    });
  });

  it('should show error if cb is called twice after second yield sync', function (done) {
    var counter = 0;
    var finished = false;

    o_o(function *() {

      var cb = yield;
      cb();
      var ret = yield;

      expect(function () {
        cb();
      }).to.throw('Callback is called twice');
      finished = true;

    })(function (err) {

      counter++;
      expect(counter).to.equal(1);
      expect(finished).to.be.true;

      return done();
    });
  });

  it('should show error if cb is called twice after second yield async', function (done) {
    var counter = 0;
    o_o(function *() {

      var cb = yield;
      cb();
      var ret = yield;

      setTimeout(function () {
        expect(function () {
          cb();
        }).to.throw('Callback is called twice');
      }, 50);

    })(function (err) {
      expect(err).to.be.not.ok;
      counter++;
      expect(counter).to.equal(1);

      return done();
    });
  });

  it('should show error if cb is called twice before yield in sync', function (done) {
    var finished = false;

    o_o(function *() {

      var cb = yield;
      cb();
      expect(function () {
        cb();
      }).to.throw('Callback is called twice');

      yield;

      finished = true;

    })(function (err) {

      expect(finished).to.be.true;
      return done();
    });
  });

  it('should show error when generator returns before in sync', function (done) {

      var fnc = o_o(function *() {
        var cb = yield;
        cb(null, 'result one');
        return;
      });

      fnc(function (err) {
        expect(err.message).to.include('Generator has no second yield statement');
        return done();
      });

  });

  it('should show error when generator returns before in async', function (done) {

      var fnc = o_o(function *() {
        var cb = yield;

        setTimeout(function () {
          cb(null, 'result one');
        }, 50);

        return;
      });

      fnc(function (err) {
        expect(err.message).to.include('Generator has no second yield statement');
        return done();
      });

  });

  it('should give error that function is not a generator', function () {
    expect(function () {
      o_o(function () {});
    }).to.throw('Function is not a Generator');

  });

//  it('should detach from the main thread when calling cb', function (done) {
//
//    var counter = 0;
//
//    o_o(function *() {
//      yield (yield)();
//    })(function (err) {
//      counter++;
//      expect(counter).to.be.equal(1);
//      done();
//      throw new Error();
//    });
//
//  });

});
<|endoftext|>


<commit_before>var Processing = {};
var Processing = function(aCanvas, aCode, aFunctions){};

Processing.name;
Processing.use3DContext;
Processing.focused;
Processing.breakShape;
Processing.glyphTable;
Processing.pmouseX;
Processing.pmouseY;
Processing.mouseX;
Processing.mouseY;
Processing.mouseButton;
Processing.mouseScroll;

// Undefined event handlers to be replaced by user when needed
Processing.mouseClicked;
Processing.mouseDragged;
Processing.mouseMoved;
Processing.mousePressed;
Processing.mouseReleased;
Processing.mouseScrolled;
Processing.mouseOver;
Processing.mouseOut;
Processing.touchStart;
Processing.touchEnd;
Processing.touchMove;
Processing.touchCancel;
Processing.key;
Processing.keyCode;
Processing.keyPressed;
Processing.keyReleased;
Processing.keyTyped;
Processing.draw;
Processing.setup;

// Remapped vars
Processing.__mousePressed;
Processing.__keyPressed;
Processing.__frameRate;

// The current animation frame
Processing.frameCount;

// The height/width of the canvas
Processing.width;
Processing.height;

Processing.prototype.size = function(x, y){};
Processing.prototype.size = function(x, y, z){};

// 2D Primitives
Processing.prototype.arc = function(x, y, width, height, start, stop){};
Processing.prototype.ellipse = function(x, y, width, height){};
Processing.prototype.line = function(x1, y1, x2, y2){};
Processing.prototype.line = function(x1, y1, z1, x2, y2, z2){};
Processing.prototype.point = function(x, y){};
Processing.prototype.point = function(x, y, z){};
Processing.prototype.quad = function(x1, y1, x2, y2, x3, y3, x4, y4){};
Processing.prototype.rect = function(x, y, width, height){};
Processing.prototype.rect = function(x, y, width, height, radius){};
Processing.prototype.rect = function(x, y, width, height, tlradius, trradius, brradius, blradius){};
Processing.prototype.triangle = function(x1, y1, x2, y2, x3, y3){};

// Color Setting
Processing.prototype.background = function(gray){};
Processing.prototype.background = function(gray, alpha){};
Processing.prototype.background = function(value1, value2, value3){};
Processing.prototype.background = function(value1, value2, value3, alpha){};
Processing.prototype.colorMode = function(mode){};
Processing.prototype.colorMode = function(mode, range1){};
Processing.prototype.colorMode = function(mode, range1, range2, range3){};
Processing.prototype.colorMode = function(mode, range1, range2, range3, range4){};
Processing.prototype.fill = function(arg1){};
Processing.prototype.fill = function(arg1, arg2){};
Processing.prototype.fill = function(arg1, arg2, arg3){};
Processing.prototype.fill = function(arg1, arg2, arg3, alpha){};
Processing.prototype.noFill = function(){};
Processing.prototype.noStroke = function(){};
Processing.prototype.stroke = function(arg1){};
Processing.prototype.stroke = function(arg1, arg2){};
Processing.prototype.stroke = function(arg1, arg2, arg3){};
Processing.prototype.stroke = function(arg1, arg2, arg3, alpha){};

// Color Creating & Reading
Processing.prototype.alpha = function(color){};
Processing.prototype.blendColor = function(c1, c2, mode){};
Processing.prototype.blue = function(color){};
Processing.prototype.brightness = function(color){};
Processing.prototype.color = function(arg1){};
Processing.prototype.color = function(arg1, arg2){};
Processing.prototype.color = function(arg1, arg2, arg3){};
Processing.prototype.color = function(arg1, arg2, arg3, alpha){};
Processing.prototype.green = function(color){};
Processing.prototype.hue = function(color){};
Processing.prototype.lerpColor = function(c1, c2, amt){};
Processing.prototype.red = function(color){};
Processing.prototype.saturation = function(color){};

// PImage
var PImage = {};
var PImage = function(){};
var PImage = function(width, height){};
var PImage = function(width, height, format){};
var PImage = function(img){};

PImage.prototype.blend = function(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE){};
PImage.prototype.blend = function(x, y, width, height, dx, dy, dwidth, dheight, MODE){};
PImage.prototype.updatePixels = function(){};
PImage.prototype.get = function(x, y, w, h){};
PImage.prototype.set = function(x, y, c){};
PImage.prototype.copy = function(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight){};
PImage.prototype.copy = function(sx, sy, swidth, sheight, dx, dy, dwidth, dheight){};
PImage.prototype.filter = function(mode, param){};
PImage.prototype.filter = function(mode){};
PImage.prototype.save = function(file){};
PImage.prototype.resize = function(w, h){};
PImage.prototype.mask = function(mask){};

Processing.prototype.createImage = function(w, h, mode){};

// PImage Loading & Displaying
Processing.prototype.image = function(img, x, y){};
Processing.prototype.image = function(img, x, y, width, height){};
Processing.prototype.imageMode = function(MODE){};
Processing.prototype.loadImage = function(filename){};
Processing.prototype.noTint = function(){};
Processing.prototype.requestImage = function(filename){};
Processing.prototype.requestImage = function(filename, extension){};
Processing.prototype.tint = function(arg1){};
Processing.prototype.tint = function(arg1, arg2){};
Processing.prototype.tint = function(arg1, arg2, arg3){};
Processing.prototype.tint = function(arg1, arg2, arg3, alpha){};

// PImage Pixels is a part of PImage class

// Rendering
var PGraphics = {};
var PGraphics = function(){};
var PGraphics = function(width, height){};
var PGraphics = function(width, height, applet){};

PGraphics.prototype.beginDraw = function(){};
PGraphics.prototype.endDraw = function(){};

Processing.prototype.createGraphics = function(width, height, renderer){};
Processing.prototype.createGraphics = function(width, height, renderer, filename){};

PGraphics.prototype.hint = function(item){};<commit_msg>Add some binds for Processing.js.<commit_after>var Processing = {};
var Processing = function(aCanvas, aCode, aFunctions){};

Processing.name;
Processing.use3DContext;
Processing.focused;
Processing.breakShape;
Processing.glyphTable;
Processing.pmouseX;
Processing.pmouseY;
Processing.mouseX;
Processing.mouseY;
Processing.mouseButton;
Processing.mouseScroll;

// Undefined event handlers to be replaced by user when needed
Processing.mouseClicked;
Processing.mouseDragged;
Processing.mouseMoved;
Processing.mousePressed;
Processing.mouseReleased;
Processing.mouseScrolled;
Processing.mouseOver;
Processing.mouseOut;
Processing.touchStart;
Processing.touchEnd;
Processing.touchMove;
Processing.touchCancel;
Processing.key;
Processing.keyCode;
Processing.keyPressed;
Processing.keyReleased;
Processing.keyTyped;
Processing.draw;
Processing.setup;

// Remapped vars
Processing.__mousePressed;
Processing.__keyPressed;
Processing.__frameRate;

// The current animation frame
Processing.frameCount;

// The height/width of the canvas
Processing.width;
Processing.height;

Processing.prototype.size = function(x, y){};
Processing.prototype.size = function(x, y, z){};

// 2D Primitives
Processing.prototype.arc = function(x, y, width, height, start, stop){};
Processing.prototype.ellipse = function(x, y, width, height){};
Processing.prototype.line = function(x1, y1, x2, y2){};
Processing.prototype.line = function(x1, y1, z1, x2, y2, z2){};
Processing.prototype.point = function(x, y){};
Processing.prototype.point = function(x, y, z){};
Processing.prototype.quad = function(x1, y1, x2, y2, x3, y3, x4, y4){};
Processing.prototype.rect = function(x, y, width, height){};
Processing.prototype.rect = function(x, y, width, height, radius){};
Processing.prototype.rect = function(x, y, width, height, tlradius, trradius, brradius, blradius){};
Processing.prototype.triangle = function(x1, y1, x2, y2, x3, y3){};

// Color Setting
Processing.prototype.background = function(gray){};
Processing.prototype.background = function(gray, alpha){};
Processing.prototype.background = function(value1, value2, value3){};
Processing.prototype.background = function(value1, value2, value3, alpha){};
Processing.prototype.colorMode = function(mode){};
Processing.prototype.colorMode = function(mode, range1){};
Processing.prototype.colorMode = function(mode, range1, range2, range3){};
Processing.prototype.colorMode = function(mode, range1, range2, range3, range4){};
Processing.prototype.fill = function(arg1){};
Processing.prototype.fill = function(arg1, arg2){};
Processing.prototype.fill = function(arg1, arg2, arg3){};
Processing.prototype.fill = function(arg1, arg2, arg3, alpha){};
Processing.prototype.noFill = function(){};
Processing.prototype.noStroke = function(){};
Processing.prototype.stroke = function(arg1){};
Processing.prototype.stroke = function(arg1, arg2){};
Processing.prototype.stroke = function(arg1, arg2, arg3){};
Processing.prototype.stroke = function(arg1, arg2, arg3, alpha){};

// Color Creating & Reading
Processing.prototype.alpha = function(color){};
Processing.prototype.blendColor = function(c1, c2, mode){};
Processing.prototype.blue = function(color){};
Processing.prototype.brightness = function(color){};
Processing.prototype.color = function(arg1){};
Processing.prototype.color = function(arg1, arg2){};
Processing.prototype.color = function(arg1, arg2, arg3){};
Processing.prototype.color = function(arg1, arg2, arg3, alpha){};
Processing.prototype.green = function(color){};
Processing.prototype.hue = function(color){};
Processing.prototype.lerpColor = function(c1, c2, amt){};
Processing.prototype.red = function(color){};
Processing.prototype.saturation = function(color){};

// PImage
var PImage = {};
var PImage = function(){};
var PImage = function(width, height){};
var PImage = function(width, height, format){};
var PImage = function(img){};

PImage.prototype.blend = function(srcImg, x, y, width, height, dx, dy, dwidth, dheight, MODE){};
PImage.prototype.blend = function(x, y, width, height, dx, dy, dwidth, dheight, MODE){};
PImage.prototype.updatePixels = function(){};
PImage.prototype.get = function(x, y, w, h){};
PImage.prototype.set = function(x, y, c){};
PImage.prototype.copy = function(srcImg, sx, sy, swidth, sheight, dx, dy, dwidth, dheight){};
PImage.prototype.copy = function(sx, sy, swidth, sheight, dx, dy, dwidth, dheight){};
PImage.prototype.filter = function(mode, param){};
PImage.prototype.filter = function(mode){};
PImage.prototype.save = function(file){};
PImage.prototype.resize = function(w, h){};
PImage.prototype.mask = function(mask){};

Processing.prototype.createImage = function(w, h, mode){};

// PImage Loading & Displaying
Processing.prototype.image = function(img, x, y){};
Processing.prototype.image = function(img, x, y, width, height){};
Processing.prototype.imageMode = function(MODE){};
Processing.prototype.loadImage = function(filename){};
Processing.prototype.noTint = function(){};
Processing.prototype.requestImage = function(filename){};
Processing.prototype.requestImage = function(filename, extension){};
Processing.prototype.tint = function(arg1){};
Processing.prototype.tint = function(arg1, arg2){};
Processing.prototype.tint = function(arg1, arg2, arg3){};
Processing.prototype.tint = function(arg1, arg2, arg3, alpha){};

// PImage Pixels is a part of PImage class

// Rendering
var PGraphics = {};
var PGraphics = function(){};
var PGraphics = function(width, height){};
var PGraphics = function(width, height, applet){};

PGraphics.prototype.beginDraw = function(){};
PGraphics.prototype.endDraw = function(){};

Processing.prototype.createGraphics = function(width, height, renderer){};
Processing.prototype.createGraphics = function(width, height, renderer, filename){};

PGraphics.prototype.hint = function(item){};

// Typography Creating & Displaying

Processing.prototype.createFont = function(name, size){};
Processing.prototype.loadFont = function(fontname){};

Processing.prototype.text = function(data, x, y){};
Processing.prototype.text = function(data, x, y, z){};
Processing.prototype.text = function(data, x, y, width, height){};
Processing.prototype.text = function(data, x, y, width, height, z){};

Processing.prototype.textFont = function(pfont, size){};
Processing.prototype.textFont = function(pfont){};

// Typography Attributes
Processing.prototype.textAlign = function(align){};
Processing.prototype.textAlign = function(align, yalign){};
Processing.prototype.textLeading = function(dist){};
Processing.prototype.textMode = function(mode){};
Processing.prototype.textSize = function(size){};
Processing.prototype.textWidth = function(data){};

// Typography Mertics
Processing.prototype.textAscent = function(){};
Processing.prototype.textDescent = function(){};

// Math Calculation
Processing.prototype.abs = function(arg){};
Processing.prototype.ceil = function(arg){};
Processing.prototype.constrain = function(value, max, min){};
Processing.prototype.dist = function(x1, y1, x2,y2){};
Processing.prototype.dist = function(x1, y1, z1, x2, y2, z2){};
Processing.prototype.exp = function(arg){};
Processing.prototype.floor = function(arg){};
Processing.prototype.lerp = function(value1, value2, amt){};
Processing.prototype.log = function(arg){};
Processing.prototype.mag = function(a, b){};
Processing.prototype.mag = function(a, b, c){};
Processing.prototype.map = function(value, low1, high1, low2, high2){};		// ???

Processing.prototype.max = function(value1, value2){};
Processing.prototype.max = function(value1, value2, value3){};
Processing.prototype.max = function(array){};

Processing.prototype.min = function(value1, value2){};
Processing.prototype.min = function(value1, value2, value3){};
Processing.prototype.min = function(array){};

Processing.prototype.norm = function(value, low, high){};
Processing.prototype.pow = function(num, exponent){};
Processing.prototype.round = function(value){};
Processing.prototype.sq = function(value){};
Processing.prototype.sqrt = function(value){};

// Math Trigonometry
Processing.prototype.acos = function(value){};
Processing.prototype.asin = function(value){};
Processing.prototype.atan = function(value){};
Processing.prototype.atan2 = function(x, y){};
Processing.prototype.cos = function(angle){};
Processing.prototype.degrees = function(angle){};
Processing.prototype.radians = function(angle){};
Processing.prototype.sin = function(rad){};
Processing.prototype.tan = function(angle){};

// Math Random
Processing.prototype.noise = function(x){};
Processing.prototype.noise = function(x, y){};
Processing.prototype.noise = function(x, y, z){};

Processing.prototype.noiseDetail = function(octaves, fallout){};
Processing.prototype.noiseDetail = function(octaves){};
Processing.prototype.noiseSeed = function(seed){};

Processing.prototype.random = function(high){};
Processing.prototype.random = function(high, low){};
Processing.prototype.randomSeed = function(seed){};<|endoftext|>


<commit_before>/* @flow */

import { _Vue } from '../install'
import type Router from '../index'
import { inBrowser } from '../util/dom'
import { runQueue } from '../util/async'
import { warn, isError, isRouterError } from '../util/warn'
import { START, isSameRoute } from '../util/route'
import {
  flatten,
  flatMapComponents,
  resolveAsyncComponents
} from '../util/resolve-components'
import {
  createNavigationDuplicatedError,
  createNavigationCancelledError,
  createNavigationRedirectedError,
  createNavigationAbortedError,
  NavigationFailureType
} from './errors'

export class History {
  router: Router
  base: string
  current: Route
  pending: ?Route
  cb: (r: Route) => void
  ready: boolean
  readyCbs: Array<Function>
  readyErrorCbs: Array<Function>
  errorCbs: Array<Function>
  listeners: Array<Function>
  cleanupListeners: Function

  // implemented by sub-classes
  +go: (n: number) => void
  +push: (loc: RawLocation) => void
  +replace: (loc: RawLocation) => void
  +ensureURL: (push?: boolean) => void
  +getCurrentLocation: () => string
  +setupListeners: Function

  constructor (router: Router, base: ?string) {
    this.router = router
    this.base = normalizeBase(base)
    // start with a route object that stands for "nowhere"
    this.current = START
    this.pending = null
    this.ready = false
    this.readyCbs = []
    this.readyErrorCbs = []
    this.errorCbs = []
    this.listeners = []
  }

  listen (cb: Function) {
    this.cb = cb
  }

  onReady (cb: Function, errorCb: ?Function) {
    if (this.ready) {
      cb()
    } else {
      this.readyCbs.push(cb)
      if (errorCb) {
        this.readyErrorCbs.push(errorCb)
      }
    }
  }

  onError (errorCb: Function) {
    this.errorCbs.push(errorCb)
  }

  transitionTo (
    location: RawLocation,
    onComplete?: Function,
    onAbort?: Function
  ) {
    const route = this.router.match(location, this.current)
    this.confirmTransition(
      route,
      () => {
        const prev = this.current
        this.updateRoute(route)
        onComplete && onComplete(route)
        this.ensureURL()
        this.router.afterHooks.forEach(hook => {
          hook && hook(route, prev)
        })

        // fire ready cbs once
        if (!this.ready) {
          this.ready = true
          this.readyCbs.forEach(cb => {
            cb(route)
          })
        }
      },
      err => {
        if (onAbort) {
          onAbort(err)
        }
        if (err && !this.ready) {
          this.ready = true
          this.readyErrorCbs.forEach(cb => {
            cb(err)
          })
        }
      }
    )
  }

  confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
    const current = this.current
    const abort = err => {
      // after merging https://github.com/vuejs/vue-router/pull/2771 we
      // When the user navigates through history through back/forward buttons
      // we do not want to throw the error. We only throw it if directly calling
      // push/replace. That's why it's not included in isError
      if (!isRouterError(err, NavigationFailureType.duplicated) && isError(err)) {
        if (this.errorCbs.length) {
          this.errorCbs.forEach(cb => {
            cb(err)
          })
        } else {
          warn(false, 'uncaught error during route navigation:')
          console.error(err)
        }
      }
      onAbort && onAbort(err)
    }
    if (
      isSameRoute(route, current) &&
      // in the case the route map has been dynamically appended to
      route.matched.length === current.matched.length
    ) {
      this.ensureURL()
      return abort(createNavigationDuplicatedError(current, route))
    }

    const { updated, deactivated, activated } = resolveQueue(
      this.current.matched,
      route.matched
    )

    const queue: Array<?NavigationGuard> = [].concat(
      // in-component leave guards
      extractLeaveGuards(deactivated),
      // global before hooks
      this.router.beforeHooks,
      // in-component update hooks
      extractUpdateHooks(updated),
      // in-config enter guards
      activated.map(m => m.beforeEnter),
      // async components
      resolveAsyncComponents(activated)
    )

    this.pending = route
    const iterator = (hook: NavigationGuard, next) => {
      if (this.pending !== route) {
        return abort(createNavigationCancelledError(current, route))
      }
      try {
        hook(route, current, (to: any) => {
          if (to === false) {
            // next(false) -> abort navigation, ensure current URL
            this.ensureURL(true)
            abort(createNavigationAbortedError(current, route))
          } else if (isError(to)) {
            this.ensureURL(true)
            abort(to)
          } else if (
            typeof to === 'string' ||
            (typeof to === 'object' &&
              (typeof to.path === 'string' || typeof to.name === 'string'))
          ) {
            // next('/') or next({ path: '/' }) -> redirect
            abort(createNavigationRedirectedError(current, route))
            if (typeof to === 'object' && to.replace) {
              this.replace(to)
            } else {
              this.push(to)
            }
          } else {
            // confirm transition and pass on the value
            next(to)
          }
        })
      } catch (e) {
        abort(e)
      }
    }

    runQueue(queue, iterator, () => {
      const postEnterCbs = []
      const isValid = () => this.current === route
      // wait until async components are resolved before
      // extracting in-component enter guards
      const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
      const queue = enterGuards.concat(this.router.resolveHooks)
      runQueue(queue, iterator, () => {
        if (this.pending !== route) {
          return abort()
        }
        this.pending = null
        onComplete(route)
        if (this.router.app) {
          this.router.app.$nextTick(() => {
            postEnterCbs.forEach(cb => {
              cb()
            })
          })
        }
      })
    })
  }

  updateRoute (route: Route) {
    this.current = route
    this.cb && this.cb(route)
  }

  setupListeners () {
    // Default implementation is empty
  }

  teardownListeners () {
    this.listeners.forEach(cleanupListener => {
      cleanupListener()
    })
    this.listeners = []
  }
}

function normalizeBase (base: ?string): string {
  if (!base) {
    if (inBrowser) {
      // respect <base> tag
      const baseEl = document.querySelector('base')
      base = (baseEl && baseEl.getAttribute('href')) || '/'
      // strip full URL origin
      base = base.replace(/^https?:\/\/[^\/]+/, '')
    } else {
      base = '/'
    }
  }
  // make sure there's the starting slash
  if (base.charAt(0) !== '/') {
    base = '/' + base
  }
  // remove trailing slash
  return base.replace(/\/$/, '')
}

function resolveQueue (
  current: Array<RouteRecord>,
  next: Array<RouteRecord>
): {
  updated: Array<RouteRecord>,
  activated: Array<RouteRecord>,
  deactivated: Array<RouteRecord>
} {
  let i
  const max = Math.max(current.length, next.length)
  for (i = 0; i < max; i++) {
    if (current[i] !== next[i]) {
      break
    }
  }
  return {
    updated: next.slice(0, i),
    activated: next.slice(i),
    deactivated: current.slice(i)
  }
}

function extractGuards (
  records: Array<RouteRecord>,
  name: string,
  bind: Function,
  reverse?: boolean
): Array<?Function> {
  const guards = flatMapComponents(records, (def, instance, match, key) => {
    const guard = extractGuard(def, name)
    if (guard) {
      return Array.isArray(guard)
        ? guard.map(guard => bind(guard, instance, match, key))
        : bind(guard, instance, match, key)
    }
  })
  return flatten(reverse ? guards.reverse() : guards)
}

function extractGuard (
  def: Object | Function,
  key: string
): NavigationGuard | Array<NavigationGuard> {
  if (typeof def !== 'function') {
    // extend now so that global mixins are applied.
    def = _Vue.extend(def)
  }
  return def.options[key]
}

function extractLeaveGuards (deactivated: Array<RouteRecord>): Array<?Function> {
  return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
}

function extractUpdateHooks (updated: Array<RouteRecord>): Array<?Function> {
  return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
}

function bindGuard (guard: NavigationGuard, instance: ?_Vue): ?NavigationGuard {
  if (instance) {
    return function boundRouteGuard () {
      return guard.apply(instance, arguments)
    }
  }
}

function extractEnterGuards (
  activated: Array<RouteRecord>,
  cbs: Array<Function>,
  isValid: () => boolean
): Array<?Function> {
  return extractGuards(
    activated,
    'beforeRouteEnter',
    (guard, _, match, key) => {
      return bindEnterGuard(guard, match, key, cbs, isValid)
    }
  )
}

function bindEnterGuard (
  guard: NavigationGuard,
  match: RouteRecord,
  key: string,
  cbs: Array<Function>,
  isValid: () => boolean
): NavigationGuard {
  return function routeEnterGuard (to, from, next) {
    return guard(to, from, cb => {
      if (typeof cb === 'function') {
        cbs.push(() => {
          // #750
          // if a router-view is wrapped with an out-in transition,
          // the instance may not have been registered at this time.
          // we will need to poll for registration until current route
          // is no longer valid.
          poll(cb, match.instances, key, isValid)
        })
      }
      next(cb)
    })
  }
}

function poll (
  cb: any, // somehow flow cannot infer this is a function
  instances: Object,
  key: string,
  isValid: () => boolean
) {
  if (
    instances[key] &&
    !instances[key]._isBeingDestroyed // do not reuse being destroyed instance
  ) {
    cb(instances[key])
  } else if (isValid()) {
    setTimeout(() => {
      poll(cb, instances, key, isValid)
    }, 16)
  }
}
<commit_msg>fix(errors): avoid unnecessary log of errors<commit_after>/* @flow */

import { _Vue } from '../install'
import type Router from '../index'
import { inBrowser } from '../util/dom'
import { runQueue } from '../util/async'
import { warn, isError, isRouterError } from '../util/warn'
import { START, isSameRoute } from '../util/route'
import {
  flatten,
  flatMapComponents,
  resolveAsyncComponents
} from '../util/resolve-components'
import {
  createNavigationDuplicatedError,
  createNavigationCancelledError,
  createNavigationRedirectedError,
  createNavigationAbortedError
} from './errors'

export class History {
  router: Router
  base: string
  current: Route
  pending: ?Route
  cb: (r: Route) => void
  ready: boolean
  readyCbs: Array<Function>
  readyErrorCbs: Array<Function>
  errorCbs: Array<Function>
  listeners: Array<Function>
  cleanupListeners: Function

  // implemented by sub-classes
  +go: (n: number) => void
  +push: (loc: RawLocation) => void
  +replace: (loc: RawLocation) => void
  +ensureURL: (push?: boolean) => void
  +getCurrentLocation: () => string
  +setupListeners: Function

  constructor (router: Router, base: ?string) {
    this.router = router
    this.base = normalizeBase(base)
    // start with a route object that stands for "nowhere"
    this.current = START
    this.pending = null
    this.ready = false
    this.readyCbs = []
    this.readyErrorCbs = []
    this.errorCbs = []
    this.listeners = []
  }

  listen (cb: Function) {
    this.cb = cb
  }

  onReady (cb: Function, errorCb: ?Function) {
    if (this.ready) {
      cb()
    } else {
      this.readyCbs.push(cb)
      if (errorCb) {
        this.readyErrorCbs.push(errorCb)
      }
    }
  }

  onError (errorCb: Function) {
    this.errorCbs.push(errorCb)
  }

  transitionTo (
    location: RawLocation,
    onComplete?: Function,
    onAbort?: Function
  ) {
    const route = this.router.match(location, this.current)
    this.confirmTransition(
      route,
      () => {
        const prev = this.current
        this.updateRoute(route)
        onComplete && onComplete(route)
        this.ensureURL()
        this.router.afterHooks.forEach(hook => {
          hook && hook(route, prev)
        })

        // fire ready cbs once
        if (!this.ready) {
          this.ready = true
          this.readyCbs.forEach(cb => {
            cb(route)
          })
        }
      },
      err => {
        if (onAbort) {
          onAbort(err)
        }
        if (err && !this.ready) {
          this.ready = true
          this.readyErrorCbs.forEach(cb => {
            cb(err)
          })
        }
      }
    )
  }

  confirmTransition (route: Route, onComplete: Function, onAbort?: Function) {
    const current = this.current
    const abort = err => {
      // changed after adding errors with
      // https://github.com/vuejs/vue-router/pull/3047 before that change,
      // redirect and aborted navigation would produce an err == null
      if (!isRouterError(err) && isError(err)) {
        if (this.errorCbs.length) {
          this.errorCbs.forEach(cb => {
            cb(err)
          })
        } else {
          warn(false, 'uncaught error during route navigation:')
          console.error(err)
        }
      }
      onAbort && onAbort(err)
    }
    if (
      isSameRoute(route, current) &&
      // in the case the route map has been dynamically appended to
      route.matched.length === current.matched.length
    ) {
      this.ensureURL()
      return abort(createNavigationDuplicatedError(current, route))
    }

    const { updated, deactivated, activated } = resolveQueue(
      this.current.matched,
      route.matched
    )

    const queue: Array<?NavigationGuard> = [].concat(
      // in-component leave guards
      extractLeaveGuards(deactivated),
      // global before hooks
      this.router.beforeHooks,
      // in-component update hooks
      extractUpdateHooks(updated),
      // in-config enter guards
      activated.map(m => m.beforeEnter),
      // async components
      resolveAsyncComponents(activated)
    )

    this.pending = route
    const iterator = (hook: NavigationGuard, next) => {
      if (this.pending !== route) {
        return abort(createNavigationCancelledError(current, route))
      }
      try {
        hook(route, current, (to: any) => {
          if (to === false) {
            // next(false) -> abort navigation, ensure current URL
            this.ensureURL(true)
            abort(createNavigationAbortedError(current, route))
          } else if (isError(to)) {
            this.ensureURL(true)
            abort(to)
          } else if (
            typeof to === 'string' ||
            (typeof to === 'object' &&
              (typeof to.path === 'string' || typeof to.name === 'string'))
          ) {
            // next('/') or next({ path: '/' }) -> redirect
            abort(createNavigationRedirectedError(current, route))
            if (typeof to === 'object' && to.replace) {
              this.replace(to)
            } else {
              this.push(to)
            }
          } else {
            // confirm transition and pass on the value
            next(to)
          }
        })
      } catch (e) {
        abort(e)
      }
    }

    runQueue(queue, iterator, () => {
      const postEnterCbs = []
      const isValid = () => this.current === route
      // wait until async components are resolved before
      // extracting in-component enter guards
      const enterGuards = extractEnterGuards(activated, postEnterCbs, isValid)
      const queue = enterGuards.concat(this.router.resolveHooks)
      runQueue(queue, iterator, () => {
        if (this.pending !== route) {
          return abort()
        }
        this.pending = null
        onComplete(route)
        if (this.router.app) {
          this.router.app.$nextTick(() => {
            postEnterCbs.forEach(cb => {
              cb()
            })
          })
        }
      })
    })
  }

  updateRoute (route: Route) {
    this.current = route
    this.cb && this.cb(route)
  }

  setupListeners () {
    // Default implementation is empty
  }

  teardownListeners () {
    this.listeners.forEach(cleanupListener => {
      cleanupListener()
    })
    this.listeners = []
  }
}

function normalizeBase (base: ?string): string {
  if (!base) {
    if (inBrowser) {
      // respect <base> tag
      const baseEl = document.querySelector('base')
      base = (baseEl && baseEl.getAttribute('href')) || '/'
      // strip full URL origin
      base = base.replace(/^https?:\/\/[^\/]+/, '')
    } else {
      base = '/'
    }
  }
  // make sure there's the starting slash
  if (base.charAt(0) !== '/') {
    base = '/' + base
  }
  // remove trailing slash
  return base.replace(/\/$/, '')
}

function resolveQueue (
  current: Array<RouteRecord>,
  next: Array<RouteRecord>
): {
  updated: Array<RouteRecord>,
  activated: Array<RouteRecord>,
  deactivated: Array<RouteRecord>
} {
  let i
  const max = Math.max(current.length, next.length)
  for (i = 0; i < max; i++) {
    if (current[i] !== next[i]) {
      break
    }
  }
  return {
    updated: next.slice(0, i),
    activated: next.slice(i),
    deactivated: current.slice(i)
  }
}

function extractGuards (
  records: Array<RouteRecord>,
  name: string,
  bind: Function,
  reverse?: boolean
): Array<?Function> {
  const guards = flatMapComponents(records, (def, instance, match, key) => {
    const guard = extractGuard(def, name)
    if (guard) {
      return Array.isArray(guard)
        ? guard.map(guard => bind(guard, instance, match, key))
        : bind(guard, instance, match, key)
    }
  })
  return flatten(reverse ? guards.reverse() : guards)
}

function extractGuard (
  def: Object | Function,
  key: string
): NavigationGuard | Array<NavigationGuard> {
  if (typeof def !== 'function') {
    // extend now so that global mixins are applied.
    def = _Vue.extend(def)
  }
  return def.options[key]
}

function extractLeaveGuards (deactivated: Array<RouteRecord>): Array<?Function> {
  return extractGuards(deactivated, 'beforeRouteLeave', bindGuard, true)
}

function extractUpdateHooks (updated: Array<RouteRecord>): Array<?Function> {
  return extractGuards(updated, 'beforeRouteUpdate', bindGuard)
}

function bindGuard (guard: NavigationGuard, instance: ?_Vue): ?NavigationGuard {
  if (instance) {
    return function boundRouteGuard () {
      return guard.apply(instance, arguments)
    }
  }
}

function extractEnterGuards (
  activated: Array<RouteRecord>,
  cbs: Array<Function>,
  isValid: () => boolean
): Array<?Function> {
  return extractGuards(
    activated,
    'beforeRouteEnter',
    (guard, _, match, key) => {
      return bindEnterGuard(guard, match, key, cbs, isValid)
    }
  )
}

function bindEnterGuard (
  guard: NavigationGuard,
  match: RouteRecord,
  key: string,
  cbs: Array<Function>,
  isValid: () => boolean
): NavigationGuard {
  return function routeEnterGuard (to, from, next) {
    return guard(to, from, cb => {
      if (typeof cb === 'function') {
        cbs.push(() => {
          // #750
          // if a router-view is wrapped with an out-in transition,
          // the instance may not have been registered at this time.
          // we will need to poll for registration until current route
          // is no longer valid.
          poll(cb, match.instances, key, isValid)
        })
      }
      next(cb)
    })
  }
}

function poll (
  cb: any, // somehow flow cannot infer this is a function
  instances: Object,
  key: string,
  isValid: () => boolean
) {
  if (
    instances[key] &&
    !instances[key]._isBeingDestroyed // do not reuse being destroyed instance
  ) {
    cb(instances[key])
  } else if (isValid()) {
    setTimeout(() => {
      poll(cb, instances, key, isValid)
    }, 16)
  }
}
<|endoftext|>


<commit_before>'use strict';

const chai = require('chai')
const sinon = require('sinon')
const sinonChai = require('sinon-chai')
const expect = chai.expect

chai.use(sinonChai)

describe("Filters", function () {
    var MultiIni = require('../src');

    it("Availability of the filters", function () {
        expect(MultiIni.filters).not.to.be.undefined;
        expect(MultiIni.filters).not.to.be.null;
    });
});
<commit_msg>Added tests for filters<commit_after>'use strict';

const chai = require('chai')
const sinon = require('sinon')
const sinonChai = require('sinon-chai')
const expect = chai.expect

chai.use(sinonChai)

describe("Filters", function () {
    var MultiIni = require('../src');

    it("Availability of the filters", function () {
        expect(MultiIni.filters).not.to.be.undefined;
        expect(MultiIni.filters).not.to.be.null;
    });

    describe("lowercase", function () {
        it("is available", function () {
            expect(MultiIni.filters.lowercase).to.be.defined;
        });

        it("string should be lowercase", function () {
            expect(MultiIni.filters.lowercase('Test')).to.equal('test');
        });

        it("anything else then string will be returned unmodified", function () {
            expect(MultiIni.filters.lowercase(false)).to.equal(false);
        });
    });

    describe("uppercase", function () {
        it("is available", function () {
            expect(MultiIni.filters.uppercase).to.be.defined;
        });

        it("string should be uppercase", function () {
            expect(MultiIni.filters.uppercase('Test')).to.equal('TEST');
        });

        it("anything else then string will be returned unmodified", function () {
            expect(MultiIni.filters.uppercase(false)).to.equal(false);
        });
    });

    describe("trim", function () {
        it("is available", function () {
            expect(MultiIni.filters.trim).to.be.defined;
        });

        it("string should be trimmed", function () {
            expect(MultiIni.filters.trim(' Test ')).to.equal('Test');
        });

        it("anything else then string will be returned unmodified", function () {
            expect(MultiIni.filters.trim(false)).to.equal(false);
        });
    });

    describe("constants", function () {
        it("is available", function () {
            expect(MultiIni.filters.constants).to.be.defined;
        });

        it("string should have replaced constants", function () {
            const options = {constants: {CONSTANT: 'replaced'}};

            expect(MultiIni.filters.constants('"Test " CONSTANT', options)).to.equal('"Test replaced"');
            expect(MultiIni.filters.constants('"Test " CONSTANT " Test"', options)).to.equal('"Test replaced Test"');
            expect(MultiIni.filters.constants('CONSTANT " Test"', options)).to.equal('"replaced Test"');
        });

        it("anything else then string will be returned unmodified", function () {
            expect(MultiIni.filters.constants(false)).to.equal(false);
        });
    });

});
<|endoftext|>


<commit_before>/**
 * --------------------------------------------------------------------------
 * Bootstrap (v5.0.2): dropdown.js
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
 * --------------------------------------------------------------------------
 */

import * as Popper from '@popperjs/core'

import {
  defineJQueryPlugin,
  getElement,
  getElementFromSelector,
  getNextActiveElement,
  isDisabled,
  isElement,
  isRTL,
  isVisible,
  noop,
  typeCheckConfig
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
import SelectorEngine from './dom/selector-engine'
import BaseComponent from './base-component'

/**
 * ------------------------------------------------------------------------
 * Constants
 * ------------------------------------------------------------------------
 */

const NAME = 'dropdown'
const DATA_KEY = 'bs.dropdown'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'

const ESCAPE_KEY = 'Escape'
const SPACE_KEY = 'Space'
const TAB_KEY = 'Tab'
const ARROW_UP_KEY = 'ArrowUp'
const ARROW_DOWN_KEY = 'ArrowDown'
const RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button

const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`)

const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`

const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_DROPUP = 'dropup'
const CLASS_NAME_DROPEND = 'dropend'
const CLASS_NAME_DROPSTART = 'dropstart'
const CLASS_NAME_NAVBAR = 'navbar'

const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]'
const SELECTOR_MENU = '.dropdown-menu'
const SELECTOR_NAVBAR_NAV = '.navbar-nav'
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'

const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'
const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'
const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'
const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'
const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'
const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'

const Default = {
  offset: [0, 2],
  boundary: 'clippingParents',
  reference: 'toggle',
  display: 'dynamic',
  popperConfig: null,
  autoClose: true
}

const DefaultType = {
  offset: '(array|string|function)',
  boundary: '(string|element)',
  reference: '(string|element|object)',
  display: 'string',
  popperConfig: '(null|object|function)',
  autoClose: '(boolean|string)'
}

/**
 * ------------------------------------------------------------------------
 * Class Definition
 * ------------------------------------------------------------------------
 */

class Dropdown extends BaseComponent {
  constructor(element, config) {
    super(element)

    this._popper = null
    this._config = this._getConfig(config)
    this._menu = this._getMenuElement()
    this._inNavbar = this._detectNavbar()
  }

  // Getters

  static get Default() {
    return Default
  }

  static get DefaultType() {
    return DefaultType
  }

  static get NAME() {
    return NAME
  }

  // Public

  toggle() {
    return this._isShown() ? this.hide() : this.show()
  }

  show() {
    if (isDisabled(this._element) || this._isShown(this._menu)) {
      return
    }

    const parent = Dropdown.getParentFromElement(this._element)
    const relatedTarget = {
      relatedTarget: this._element
    }

    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)

    if (showEvent.defaultPrevented) {
      return
    }

    // Totally disable Popper for Dropdowns in Navbar
    if (this._inNavbar) {
      Manipulator.setDataAttribute(this._menu, 'popper', 'none')
    } else {
      if (typeof Popper === 'undefined') {
        throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
      }

      let referenceElement = this._element

      if (this._config.reference === 'parent') {
        referenceElement = parent
      } else if (isElement(this._config.reference)) {
        referenceElement = getElement(this._config.reference)
      } else if (typeof this._config.reference === 'object') {
        referenceElement = this._config.reference
      }

      const popperConfig = this._getPopperConfig()
      const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false)

      this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)

      if (isDisplayStatic) {
        Manipulator.setDataAttribute(this._menu, 'popper', 'static')
      }
    }

    // If this is a touch-enabled device we add extra
    // empty mouseover listeners to the body's immediate children;
    // only needed because of broken event delegation on iOS
    // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
    if ('ontouchstart' in document.documentElement &&
      !parent.closest(SELECTOR_NAVBAR_NAV)) {
      [].concat(...document.body.children)
        .forEach(elem => EventHandler.on(elem, 'mouseover', noop))
    }

    this._element.focus()
    this._element.setAttribute('aria-expanded', true)

    this._menu.classList.add(CLASS_NAME_SHOW)
    this._element.classList.add(CLASS_NAME_SHOW)
    EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)
  }

  hide() {
    if (isDisabled(this._element) || !this._isShown(this._menu)) {
      return
    }

    const relatedTarget = {
      relatedTarget: this._element
    }

    this._completeHide(relatedTarget)
  }

  dispose() {
    if (this._popper) {
      this._popper.destroy()
    }

    super.dispose()
  }

  update() {
    this._inNavbar = this._detectNavbar()
    if (this._popper) {
      this._popper.update()
    }
  }

  // Private

  _completeHide(relatedTarget) {
    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)
    if (hideEvent.defaultPrevented) {
      return
    }

    // If this is a touch-enabled device we remove the extra
    // empty mouseover listeners we added for iOS support
    if ('ontouchstart' in document.documentElement) {
      [].concat(...document.body.children)
        .forEach(elem => EventHandler.off(elem, 'mouseover', noop))
    }

    if (this._popper) {
      this._popper.destroy()
    }

    this._menu.classList.remove(CLASS_NAME_SHOW)
    this._element.classList.remove(CLASS_NAME_SHOW)
    this._element.setAttribute('aria-expanded', 'false')
    Manipulator.removeDataAttribute(this._menu, 'popper')
    EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
  }

  _getConfig(config) {
    config = {
      ...this.constructor.Default,
      ...Manipulator.getDataAttributes(this._element),
      ...config
    }

    typeCheckConfig(NAME, config, this.constructor.DefaultType)

    if (typeof config.reference === 'object' && !isElement(config.reference) &&
      typeof config.reference.getBoundingClientRect !== 'function'
    ) {
      // Popper virtual elements require a getBoundingClientRect method
      throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
    }

    return config
  }

  _isShown(element = this._element) {
    return element.classList.contains(CLASS_NAME_SHOW)
  }

  _getMenuElement() {
    return SelectorEngine.next(this._element, SELECTOR_MENU)[0]
  }

  _getPlacement() {
    const parentDropdown = this._element.parentNode

    if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
      return PLACEMENT_RIGHT
    }

    if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
      return PLACEMENT_LEFT
    }

    // We need to trim the value because custom properties can also include spaces
    const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'

    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
      return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP
    }

    return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM
  }

  _detectNavbar() {
    return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null
  }

  _getOffset() {
    const { offset } = this._config

    if (typeof offset === 'string') {
      return offset.split(',').map(val => Number.parseInt(val, 10))
    }

    if (typeof offset === 'function') {
      return popperData => offset(popperData, this._element)
    }

    return offset
  }

  _getPopperConfig() {
    const defaultBsPopperConfig = {
      placement: this._getPlacement(),
      modifiers: [{
        name: 'preventOverflow',
        options: {
          boundary: this._config.boundary
        }
      },
      {
        name: 'offset',
        options: {
          offset: this._getOffset()
        }
      }]
    }

    // Disable Popper if we have a static display
    if (this._config.display === 'static') {
      defaultBsPopperConfig.modifiers = [{
        name: 'applyStyles',
        enabled: false
      }]
    }

    return {
      ...defaultBsPopperConfig,
      ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
    }
  }

  _selectMenuItem({ key, target }) {
    const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)

    if (!items.length) {
      return
    }

    // if target isn't included in items (e.g. when expanding the dropdown)
    // allow cycling to get the last item in case key equals ARROW_UP_KEY
    getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()
  }

  // Static

  static jQueryInterface(config) {
    return this.each(function () {
      const data = Dropdown.getOrCreateInstance(this, config)

      if (typeof config !== 'string') {
        return
      }

      if (typeof data[config] === 'undefined') {
        throw new TypeError(`No method named "${config}"`)
      }

      data[config]()
    })
  }

  static clearMenus(event) {
    if (event && (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY))) {
      return
    }

    const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)

    for (let i = 0, len = toggles.length; i < len; i++) {
      const context = Dropdown.getInstance(toggles[i])
      if (!context || context._config.autoClose === false) {
        continue
      }

      if (!context._isShown()) {
        continue
      }

      const relatedTarget = {
        relatedTarget: context._element
      }

      if (event) {
        const composedPath = event.composedPath()
        const isMenuTarget = composedPath.includes(context._menu)
        if (
          composedPath.includes(context._element) ||
          (context._config.autoClose === 'inside' && !isMenuTarget) ||
          (context._config.autoClose === 'outside' && isMenuTarget)
        ) {
          continue
        }

        // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
        if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {
          continue
        }

        if (event.type === 'click') {
          relatedTarget.clickEvent = event
        }
      }

      context._completeHide(relatedTarget)
    }
  }

  static getParentFromElement(element) {
    return getElementFromSelector(element) || element.parentNode
  }

  static dataApiKeydownHandler(event) {
    // If not input/textarea:
    //  - And not a key in REGEXP_KEYDOWN => not a dropdown command
    // If input/textarea:
    //  - If space key => not a dropdown command
    //  - If key is other than escape
    //    - If key is not up or down => not a dropdown command
    //    - If trigger inside the menu => not a dropdown command
    if (/input|textarea/i.test(event.target.tagName) ?
      event.key === SPACE_KEY || (event.key !== ESCAPE_KEY &&
      ((event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY) ||
        event.target.closest(SELECTOR_MENU))) :
      !REGEXP_KEYDOWN.test(event.key)) {
      return
    }

    const isActive = this.classList.contains(CLASS_NAME_SHOW)

    if (!isActive && event.key === ESCAPE_KEY) {
      return
    }

    event.preventDefault()
    event.stopPropagation()

    if (isDisabled(this)) {
      return
    }

    const getToggleButton = () => this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]

    if (event.key === ESCAPE_KEY) {
      getToggleButton().focus()
      Dropdown.clearMenus()
      return
    }

    if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) {
      if (!isActive) {
        getToggleButton().click()
      }

      Dropdown.getInstance(getToggleButton())._selectMenuItem(event)
      return
    }

    if (!isActive || event.key === SPACE_KEY) {
      Dropdown.clearMenus()
    }
  }
}

/**
 * ------------------------------------------------------------------------
 * Data Api implementation
 * ------------------------------------------------------------------------
 */

EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
  event.preventDefault()
  Dropdown.getOrCreateInstance(this).toggle()
})

/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
 * add .Dropdown to jQuery only if jQuery is present
 */

defineJQueryPlugin(Dropdown)

export default Dropdown
<commit_msg>extract createPopper method<commit_after>/**
 * --------------------------------------------------------------------------
 * Bootstrap (v5.0.2): dropdown.js
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
 * --------------------------------------------------------------------------
 */

import * as Popper from '@popperjs/core'

import {
  defineJQueryPlugin,
  getElement,
  getElementFromSelector,
  getNextActiveElement,
  isDisabled,
  isElement,
  isRTL,
  isVisible,
  noop,
  typeCheckConfig
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
import SelectorEngine from './dom/selector-engine'
import BaseComponent from './base-component'

/**
 * ------------------------------------------------------------------------
 * Constants
 * ------------------------------------------------------------------------
 */

const NAME = 'dropdown'
const DATA_KEY = 'bs.dropdown'
const EVENT_KEY = `.${DATA_KEY}`
const DATA_API_KEY = '.data-api'

const ESCAPE_KEY = 'Escape'
const SPACE_KEY = 'Space'
const TAB_KEY = 'Tab'
const ARROW_UP_KEY = 'ArrowUp'
const ARROW_DOWN_KEY = 'ArrowDown'
const RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button

const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY}`)

const EVENT_HIDE = `hide${EVENT_KEY}`
const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`

const CLASS_NAME_SHOW = 'show'
const CLASS_NAME_DROPUP = 'dropup'
const CLASS_NAME_DROPEND = 'dropend'
const CLASS_NAME_DROPSTART = 'dropstart'
const CLASS_NAME_NAVBAR = 'navbar'

const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]'
const SELECTOR_MENU = '.dropdown-menu'
const SELECTOR_NAVBAR_NAV = '.navbar-nav'
const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'

const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'
const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'
const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'
const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'
const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'
const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'

const Default = {
  offset: [0, 2],
  boundary: 'clippingParents',
  reference: 'toggle',
  display: 'dynamic',
  popperConfig: null,
  autoClose: true
}

const DefaultType = {
  offset: '(array|string|function)',
  boundary: '(string|element)',
  reference: '(string|element|object)',
  display: 'string',
  popperConfig: '(null|object|function)',
  autoClose: '(boolean|string)'
}

/**
 * ------------------------------------------------------------------------
 * Class Definition
 * ------------------------------------------------------------------------
 */

class Dropdown extends BaseComponent {
  constructor(element, config) {
    super(element)

    this._popper = null
    this._config = this._getConfig(config)
    this._menu = this._getMenuElement()
    this._inNavbar = this._detectNavbar()
  }

  // Getters

  static get Default() {
    return Default
  }

  static get DefaultType() {
    return DefaultType
  }

  static get NAME() {
    return NAME
  }

  // Public

  toggle() {
    return this._isShown() ? this.hide() : this.show()
  }

  show() {
    if (isDisabled(this._element) || this._isShown(this._menu)) {
      return
    }

    const relatedTarget = {
      relatedTarget: this._element
    }

    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)

    if (showEvent.defaultPrevented) {
      return
    }

    const parent = Dropdown.getParentFromElement(this._element)
    // Totally disable Popper for Dropdowns in Navbar
    if (this._inNavbar) {
      Manipulator.setDataAttribute(this._menu, 'popper', 'none')
    } else {
      this._createPopper(parent)
    }

    // If this is a touch-enabled device we add extra
    // empty mouseover listeners to the body's immediate children;
    // only needed because of broken event delegation on iOS
    // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
    if ('ontouchstart' in document.documentElement &&
      !parent.closest(SELECTOR_NAVBAR_NAV)) {
      [].concat(...document.body.children)
        .forEach(elem => EventHandler.on(elem, 'mouseover', noop))
    }

    this._element.focus()
    this._element.setAttribute('aria-expanded', true)

    this._menu.classList.add(CLASS_NAME_SHOW)
    this._element.classList.add(CLASS_NAME_SHOW)
    EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)
  }

  hide() {
    if (isDisabled(this._element) || !this._isShown(this._menu)) {
      return
    }

    const relatedTarget = {
      relatedTarget: this._element
    }

    this._completeHide(relatedTarget)
  }

  dispose() {
    if (this._popper) {
      this._popper.destroy()
    }

    super.dispose()
  }

  update() {
    this._inNavbar = this._detectNavbar()
    if (this._popper) {
      this._popper.update()
    }
  }

  // Private

  _completeHide(relatedTarget) {
    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)
    if (hideEvent.defaultPrevented) {
      return
    }

    // If this is a touch-enabled device we remove the extra
    // empty mouseover listeners we added for iOS support
    if ('ontouchstart' in document.documentElement) {
      [].concat(...document.body.children)
        .forEach(elem => EventHandler.off(elem, 'mouseover', noop))
    }

    if (this._popper) {
      this._popper.destroy()
    }

    this._menu.classList.remove(CLASS_NAME_SHOW)
    this._element.classList.remove(CLASS_NAME_SHOW)
    this._element.setAttribute('aria-expanded', 'false')
    Manipulator.removeDataAttribute(this._menu, 'popper')
    EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
  }

  _getConfig(config) {
    config = {
      ...this.constructor.Default,
      ...Manipulator.getDataAttributes(this._element),
      ...config
    }

    typeCheckConfig(NAME, config, this.constructor.DefaultType)

    if (typeof config.reference === 'object' && !isElement(config.reference) &&
      typeof config.reference.getBoundingClientRect !== 'function'
    ) {
      // Popper virtual elements require a getBoundingClientRect method
      throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
    }

    return config
  }

  _createPopper(parent) {
    if (typeof Popper === 'undefined') {
      throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
    }

    let referenceElement = this._element

    if (this._config.reference === 'parent') {
      referenceElement = parent
    } else if (isElement(this._config.reference)) {
      referenceElement = getElement(this._config.reference)
    } else if (typeof this._config.reference === 'object') {
      referenceElement = this._config.reference
    }

    const popperConfig = this._getPopperConfig()
    const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false)

    this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)

    if (isDisplayStatic) {
      Manipulator.setDataAttribute(this._menu, 'popper', 'static')
    }
  }

  _isShown(element = this._element) {
    return element.classList.contains(CLASS_NAME_SHOW)
  }

  _getMenuElement() {
    return SelectorEngine.next(this._element, SELECTOR_MENU)[0]
  }

  _getPlacement() {
    const parentDropdown = this._element.parentNode

    if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
      return PLACEMENT_RIGHT
    }

    if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
      return PLACEMENT_LEFT
    }

    // We need to trim the value because custom properties can also include spaces
    const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'

    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
      return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP
    }

    return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM
  }

  _detectNavbar() {
    return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null
  }

  _getOffset() {
    const { offset } = this._config

    if (typeof offset === 'string') {
      return offset.split(',').map(val => Number.parseInt(val, 10))
    }

    if (typeof offset === 'function') {
      return popperData => offset(popperData, this._element)
    }

    return offset
  }

  _getPopperConfig() {
    const defaultBsPopperConfig = {
      placement: this._getPlacement(),
      modifiers: [{
        name: 'preventOverflow',
        options: {
          boundary: this._config.boundary
        }
      },
      {
        name: 'offset',
        options: {
          offset: this._getOffset()
        }
      }]
    }

    // Disable Popper if we have a static display
    if (this._config.display === 'static') {
      defaultBsPopperConfig.modifiers = [{
        name: 'applyStyles',
        enabled: false
      }]
    }

    return {
      ...defaultBsPopperConfig,
      ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
    }
  }

  _selectMenuItem({ key, target }) {
    const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible)

    if (!items.length) {
      return
    }

    // if target isn't included in items (e.g. when expanding the dropdown)
    // allow cycling to get the last item in case key equals ARROW_UP_KEY
    getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()
  }

  // Static

  static jQueryInterface(config) {
    return this.each(function () {
      const data = Dropdown.getOrCreateInstance(this, config)

      if (typeof config !== 'string') {
        return
      }

      if (typeof data[config] === 'undefined') {
        throw new TypeError(`No method named "${config}"`)
      }

      data[config]()
    })
  }

  static clearMenus(event) {
    if (event && (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY))) {
      return
    }

    const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE)

    for (let i = 0, len = toggles.length; i < len; i++) {
      const context = Dropdown.getInstance(toggles[i])
      if (!context || context._config.autoClose === false) {
        continue
      }

      if (!context._isShown()) {
        continue
      }

      const relatedTarget = {
        relatedTarget: context._element
      }

      if (event) {
        const composedPath = event.composedPath()
        const isMenuTarget = composedPath.includes(context._menu)
        if (
          composedPath.includes(context._element) ||
          (context._config.autoClose === 'inside' && !isMenuTarget) ||
          (context._config.autoClose === 'outside' && isMenuTarget)
        ) {
          continue
        }

        // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
        if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {
          continue
        }

        if (event.type === 'click') {
          relatedTarget.clickEvent = event
        }
      }

      context._completeHide(relatedTarget)
    }
  }

  static getParentFromElement(element) {
    return getElementFromSelector(element) || element.parentNode
  }

  static dataApiKeydownHandler(event) {
    // If not input/textarea:
    //  - And not a key in REGEXP_KEYDOWN => not a dropdown command
    // If input/textarea:
    //  - If space key => not a dropdown command
    //  - If key is other than escape
    //    - If key is not up or down => not a dropdown command
    //    - If trigger inside the menu => not a dropdown command
    if (/input|textarea/i.test(event.target.tagName) ?
      event.key === SPACE_KEY || (event.key !== ESCAPE_KEY &&
      ((event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY) ||
        event.target.closest(SELECTOR_MENU))) :
      !REGEXP_KEYDOWN.test(event.key)) {
      return
    }

    const isActive = this.classList.contains(CLASS_NAME_SHOW)

    if (!isActive && event.key === ESCAPE_KEY) {
      return
    }

    event.preventDefault()
    event.stopPropagation()

    if (isDisabled(this)) {
      return
    }

    const getToggleButton = () => this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0]

    if (event.key === ESCAPE_KEY) {
      getToggleButton().focus()
      Dropdown.clearMenus()
      return
    }

    if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) {
      if (!isActive) {
        getToggleButton().click()
      }

      Dropdown.getInstance(getToggleButton())._selectMenuItem(event)
      return
    }

    if (!isActive || event.key === SPACE_KEY) {
      Dropdown.clearMenus()
    }
  }
}

/**
 * ------------------------------------------------------------------------
 * Data Api implementation
 * ------------------------------------------------------------------------
 */

EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
  event.preventDefault()
  Dropdown.getOrCreateInstance(this).toggle()
})

/**
 * ------------------------------------------------------------------------
 * jQuery
 * ------------------------------------------------------------------------
 * add .Dropdown to jQuery only if jQuery is present
 */

defineJQueryPlugin(Dropdown)

export default Dropdown
<|endoftext|>


<commit_before>/**
 * Exports: World, world
 */

var WORLD_VERSION = 3;
var DUNGEON_SIZE = 100;

var world = null;

function World(map) {
    this.map = map || Map.empty();
    this.maps = {};
    this.player = new Player(0, 0);
    this.time = 0;
    this.focus = {
        x: 0,
        y: 0
    };
    this.active = true;
    this.lastSave = 0;
    this.version = WORLD_VERSION;
}

World.prototype.display = function() {
    this.map.computeVisible(this.player);
    this.map.display();
    this.map.monsters.forEach(withThis('display'));
    if (this.active) {
        this.player.display();
        controls.display();
    }

    /* Stats */
    display.$name.text(this.player.name);
    display.$level.text(this.player.level);
    display.$dlevel.text(this.map.level);
    display.$experience.text(this.player.experience +
                             ' / ' + this.player.nextLevel());
    display.$health.text(this.player.hp + ' / ' + this.player.maxhp);
    display.$mana.text(this.player.mp + ' / ' + this.player.maxmp);
    display.$strength.text(this.player.strength);
    display.$dexterity.text(this.player.dexterity);
    display.$mind.text(this.player.mind);
};

World.prototype.look = function(x, y) {
    if (y != null) {
        this.focus.x = x;
        this.focus.y = y;
    } if (x) {
        var thing = x;
        this.focus.x = thing.x;
        this.focus.y = thing.y;
    } else {
        this.focus.x = this.player.x;
        this.focus.y = this.player.y;
    }
};

/**
 * @returns the monster at the position.
 */
World.prototype.monsterAt = function(x, y) {
    var monsters = this.map.monsters.concat([this.player]);
    for (var i = 0; i < monsters.length; i++) {
        if (monsters[i].isAt(x, y)) return monsters[i];
    }
    return undefined;
};

World.prototype.isSolid = function(x, y) {
    return this.map.isSolid(x, y);
};

/**
 * @returns true if the place is passable by a monster.
 */
World.prototype.isPassable = function(x, y) {
    return !this.isSolid(x, y) && !this.monsterAt(x, y);
};

World.prototype.isVisible = function(x, y) {
    return this.map.isVisible(x, y);
};

World.prototype.spawn = function(type) {
    var p = this.map.random(function(place) { return !place.solid; });
    if (!this.monsterAt(p.x, p.y)) this.map.monsters.push(new type(p.x, p.y));
};

/**
 * Remove a monster from the world.
 * @param {Monster} monster
 */
World.prototype.remove = function(monster) {
    if (monster === this.player) {
        log('You were derezzed.');
        world.gameOver();
    } else {
        log('%s was derezzed.', monster);
        this.map.monsters = this.map.monsters.filter(function(m) {
            return m !== monster;
        });
        var exp = monster.maxhp + Math.max(monster.dexterity, monster.mind);
        this.player.addExperience(exp);
    }
};

/**
 * Run the next world event.
 */
World.prototype.run = function() {
    if (!this.active) return;
    var all = [this.player].concat(this.map.monsters);
    var wait = Math.max(0, all.reduce(function(max, m) {
        return Math.min(max, m.timer);
    }, Infinity));
    var movers = all.filter(function(m) {
        m.timer -= wait;
        return m.timer <= 0;
    });
    world.time += wait;

    if (world.time - world.lastSave > 2000) {
        this.save();
        world.lastSave = world.time;
    }

    while (world.time > this.map.nextspawn) {
        this.map.nextspawn += R.exponential() * this.map.spawnrate *
            Math.max(1, Math.log(this.map.monsters.length));
        // Occasionally spawn higher level monsters
        var mod = Math.floor(R.exponential() * 0.5);
        this.spawn(Mindex.random(this.map.level + mod));
    }

    var mover = movers.pop();
    mover.timer = Math.max(20 - bonus(mover.dexterity), 1);
    mover.act(this.run.bind(this));
};

World.prototype.gameOver = function() {
    this.active = false;
    Save.clear('world');
    this.look();
    this.display();
};

World.prototype.save = function() {
    if (this.active) {
        var start = Date.now();
        Save.save('world');
    }
};

/**
 * Try to load the world from the save.
 */
World.load = function() {
    if (Save.exists('world')) {
        Save.load('world');
        if (world.version !== WORLD_VERSION) {
            world = null;
            return false;
        }
        return true;
    } else {
        return false;
    }
};

/**
 * Use the stairs at the player's location.
 */
World.prototype.useStairs = function() {
    var place = this.map.get(this.player.x, this.player.y);
    if (place instanceof Stair) {
        if (!place.map) {
            var map = Map.dungeon(DUNGEON_SIZE, DUNGEON_SIZE,
                                  this.map.level / 10);
            this.maps[map.id] = map;
            place.map = map.id;
            map.level = this.map.level + 1;
            var pos = map.random(function(place) {
                return !(place.solid || place instanceof Stair);
            });
            var up = new StairUp(this.map.id);
            up.x = this.player.x;
            up.y = this.player.y;
            map.set(pos.x, pos.y, up);
            place.x = pos.x;
            place.y = pos.y;
        }
        this.maps[this.map.id] = this.map;
        this.map = this.maps[place.map];
        this.maps[place.map.id] = null;
        this.player.x = place.x;
        this.player.y = place.y;
        this.map.nextspawn = Math.max(this.map.nextspawn, world.time);
        return true;
    } else {
        return false;
    }
};

/**
 * Return a list of monsters currently in view.
 */
World.prototype.visibleMonsters = function() {
    var that = this;
    return this.map.monsters.filter(function(m) {
        return that.map.isVisible(m.x, m.y);
    });
};

World.reset = function() {
    log('Greetings, program.');
    world = new World(Map.dungeon(DUNGEON_SIZE, DUNGEON_SIZE));
    var start = world.map.random(function(place) { return !place.solid; });
    world.player.move(start.x, start.y);
    world.look();
};

/**
 * Find the nearest position that meets the predicate.
 * @param f The predicate function f(place, x, y).
 * @param [x=this.player.x] The source x-position.
 * @param [y=this.player.y] The source y-position.
 */
World.prototype.nearest = function(f, x, y) {
    x = x == null ? this.player.x : x;
    y = y == null ? this.player.y : y;
    var dist2 = Infinity;
    var select = null;
    var that = this;
    Object.keys(this.map.grid).forEach(function(key) {
        var pos = key.split(',').map(parseFloat);
        if (f(that.map.grid[key], pos[0], pos[1])) {
            var dx = pos[0] - x;
            var dy = pos[1] - y;
            var d2 = dx * dx + dy * dy;
            if (d2 < dist2) {
                select = pos;
                dist2 = d2;
            }
        }
    });
    if (select) {
        return {x: select[0], y: select[1]};
    } else {
        return null;
    }
};

World.prototype.selectNext = function(reverse) {
    var that = this;
    var monsters = this.map.monsters.filter(function(m) {
        return that.isVisible(m.x, m.y);
    });
    monsters.sort(function(a, b) {
        return a.dist(world.player) - b.dist(world.player);
    });
    if (monsters.length > 0) {
        if (controls.selected) {
            var x = controls.selected.x, y = controls.selected.y;
            for (var i = 0; i < monsters.length; i++) {
                if (monsters[i].x === x && monsters[i].y === y) {
                    if (reverse) {
                        controls.selected =
                            monsters[(i - 1 + monsters.length)
                                     % monsters.length];
                    } else {
                        controls.selected =
                            monsters[(i + 1) % monsters.length];
                    }
                    return true;
                }
                controls.selected = monsters[0];
                return true;
            }
        } else {
            controls.selected = monsters[0];
            return true;
        }
    } else {
        return false;
    }
};
<commit_msg>More gracefully fail to load.<commit_after>/**
 * Exports: World, world
 */

var WORLD_VERSION = 3;
var DUNGEON_SIZE = 100;

var world = null;

function World(map) {
    this.map = map || Map.empty();
    this.maps = {};
    this.player = new Player(0, 0);
    this.time = 0;
    this.focus = {
        x: 0,
        y: 0
    };
    this.active = true;
    this.lastSave = 0;
    this.version = WORLD_VERSION;
}

World.prototype.display = function() {
    this.map.computeVisible(this.player);
    this.map.display();
    this.map.monsters.forEach(withThis('display'));
    if (this.active) {
        this.player.display();
        controls.display();
    }

    /* Stats */
    display.$name.text(this.player.name);
    display.$level.text(this.player.level);
    display.$dlevel.text(this.map.level);
    display.$experience.text(this.player.experience +
                             ' / ' + this.player.nextLevel());
    display.$health.text(this.player.hp + ' / ' + this.player.maxhp);
    display.$mana.text(this.player.mp + ' / ' + this.player.maxmp);
    display.$strength.text(this.player.strength);
    display.$dexterity.text(this.player.dexterity);
    display.$mind.text(this.player.mind);
};

World.prototype.look = function(x, y) {
    if (y != null) {
        this.focus.x = x;
        this.focus.y = y;
    } if (x) {
        var thing = x;
        this.focus.x = thing.x;
        this.focus.y = thing.y;
    } else {
        this.focus.x = this.player.x;
        this.focus.y = this.player.y;
    }
};

/**
 * @returns the monster at the position.
 */
World.prototype.monsterAt = function(x, y) {
    var monsters = this.map.monsters.concat([this.player]);
    for (var i = 0; i < monsters.length; i++) {
        if (monsters[i].isAt(x, y)) return monsters[i];
    }
    return undefined;
};

World.prototype.isSolid = function(x, y) {
    return this.map.isSolid(x, y);
};

/**
 * @returns true if the place is passable by a monster.
 */
World.prototype.isPassable = function(x, y) {
    return !this.isSolid(x, y) && !this.monsterAt(x, y);
};

World.prototype.isVisible = function(x, y) {
    return this.map.isVisible(x, y);
};

World.prototype.spawn = function(type) {
    var p = this.map.random(function(place) { return !place.solid; });
    if (!this.monsterAt(p.x, p.y)) this.map.monsters.push(new type(p.x, p.y));
};

/**
 * Remove a monster from the world.
 * @param {Monster} monster
 */
World.prototype.remove = function(monster) {
    if (monster === this.player) {
        log('You were derezzed.');
        world.gameOver();
    } else {
        log('%s was derezzed.', monster);
        this.map.monsters = this.map.monsters.filter(function(m) {
            return m !== monster;
        });
        var exp = monster.maxhp + Math.max(monster.dexterity, monster.mind);
        this.player.addExperience(exp);
    }
};

/**
 * Run the next world event.
 */
World.prototype.run = function() {
    if (!this.active) return;
    var all = [this.player].concat(this.map.monsters);
    var wait = Math.max(0, all.reduce(function(max, m) {
        return Math.min(max, m.timer);
    }, Infinity));
    var movers = all.filter(function(m) {
        m.timer -= wait;
        return m.timer <= 0;
    });
    world.time += wait;

    if (world.time - world.lastSave > 2000) {
        this.save();
        world.lastSave = world.time;
    }

    while (world.time > this.map.nextspawn) {
        this.map.nextspawn += R.exponential() * this.map.spawnrate *
            Math.max(1, Math.log(this.map.monsters.length));
        // Occasionally spawn higher level monsters
        var mod = Math.floor(R.exponential() * 0.5);
        this.spawn(Mindex.random(this.map.level + mod));
    }

    var mover = movers.pop();
    mover.timer = Math.max(20 - bonus(mover.dexterity), 1);
    mover.act(this.run.bind(this));
};

World.prototype.gameOver = function() {
    this.active = false;
    Save.clear('world');
    this.look();
    this.display();
};

World.prototype.save = function() {
    if (this.active) {
        var start = Date.now();
        Save.save('world');
    }
};

/**
 * Try to load the world from the save.
 */
World.load = function() {
    if (Save.exists('world')) {
        try {
            Save.load('world');
            if (world.version !== WORLD_VERSION) {
                world = null;
                return false;
            }
        } catch (e) {
            /* Load failed, give up. */
            Save.clear('world');
            world = null;
            return false;
        }
        return true;
    } else {
        return false;
    }
};

/**
 * Use the stairs at the player's location.
 */
World.prototype.useStairs = function() {
    var place = this.map.get(this.player.x, this.player.y);
    if (place instanceof Stair) {
        if (!place.map) {
            var map = Map.dungeon(DUNGEON_SIZE, DUNGEON_SIZE,
                                  this.map.level / 10);
            this.maps[map.id] = map;
            place.map = map.id;
            map.level = this.map.level + 1;
            var pos = map.random(function(place) {
                return !(place.solid || place instanceof Stair);
            });
            var up = new StairUp(this.map.id);
            up.x = this.player.x;
            up.y = this.player.y;
            map.set(pos.x, pos.y, up);
            place.x = pos.x;
            place.y = pos.y;
        }
        this.maps[this.map.id] = this.map;
        this.map = this.maps[place.map];
        this.maps[place.map.id] = null;
        this.player.x = place.x;
        this.player.y = place.y;
        this.map.nextspawn = Math.max(this.map.nextspawn, world.time);
        return true;
    } else {
        return false;
    }
};

/**
 * Return a list of monsters currently in view.
 */
World.prototype.visibleMonsters = function() {
    var that = this;
    return this.map.monsters.filter(function(m) {
        return that.map.isVisible(m.x, m.y);
    });
};

World.reset = function() {
    log('Greetings, program.');
    world = new World(Map.dungeon(DUNGEON_SIZE, DUNGEON_SIZE));
    var start = world.map.random(function(place) { return !place.solid; });
    world.player.move(start.x, start.y);
    world.look();
};

/**
 * Find the nearest position that meets the predicate.
 * @param f The predicate function f(place, x, y).
 * @param [x=this.player.x] The source x-position.
 * @param [y=this.player.y] The source y-position.
 */
World.prototype.nearest = function(f, x, y) {
    x = x == null ? this.player.x : x;
    y = y == null ? this.player.y : y;
    var dist2 = Infinity;
    var select = null;
    var that = this;
    Object.keys(this.map.grid).forEach(function(key) {
        var pos = key.split(',').map(parseFloat);
        if (f(that.map.grid[key], pos[0], pos[1])) {
            var dx = pos[0] - x;
            var dy = pos[1] - y;
            var d2 = dx * dx + dy * dy;
            if (d2 < dist2) {
                select = pos;
                dist2 = d2;
            }
        }
    });
    if (select) {
        return {x: select[0], y: select[1]};
    } else {
        return null;
    }
};

World.prototype.selectNext = function(reverse) {
    var that = this;
    var monsters = this.map.monsters.filter(function(m) {
        return that.isVisible(m.x, m.y);
    });
    monsters.sort(function(a, b) {
        return a.dist(world.player) - b.dist(world.player);
    });
    if (monsters.length > 0) {
        if (controls.selected) {
            var x = controls.selected.x, y = controls.selected.y;
            for (var i = 0; i < monsters.length; i++) {
                if (monsters[i].x === x && monsters[i].y === y) {
                    if (reverse) {
                        controls.selected =
                            monsters[(i - 1 + monsters.length)
                                     % monsters.length];
                    } else {
                        controls.selected =
                            monsters[(i + 1) % monsters.length];
                    }
                    return true;
                }
                controls.selected = monsters[0];
                return true;
            }
        } else {
            controls.selected = monsters[0];
            return true;
        }
    } else {
        return false;
    }
};
<|endoftext|>