<commit_before>/*!
 * Comment Core Library CommentManager
 * @license MIT
 * @author Jim Chen
 *
 * Copyright (c) 2014 Jim Chen
 */
var CommentManager = (function() {
	var getRotMatrix = function(yrot, zrot) {
		// Courtesy of @StarBrilliant, re-adapted to look better
		var DEG2RAD = Math.PI/180;
		var yr = yrot * DEG2RAD;
		var zr = zrot * DEG2RAD;
		var COS = Math.cos;
		var SIN = Math.sin;
		var matrix = [
			COS(yr) * COS(zr)    , COS(yr) * SIN(zr)     , SIN(yr)  , 0,
			(-SIN(zr))           , COS(zr)               , 0        , 0,
			(-SIN(yr) * COS(zr)) , (-SIN(yr) * SIN(zr))  , COS(yr)  , 0,
			0                    , 0                     , 0        , 1
		];
		// CSS does not recognize scientific notation (e.g. 1e-6), truncating it.
		for(var i = 0; i < matrix.length;i++){
			if(Math.abs(matrix[i]) < 0.000001){
				matrix[i] = 0;
			}
		}
		return "matrix3d(" + matrix.join(",") + ")";
	};

	function CommentManager(stageObject){
		var __timer = 0;

		this._listeners = {};
		this._lastPosition = 0;

		this.stage = stageObject;
		this.options = {
			global:{
				opacity:1,
				scale:1,
				className:"cmt"
			},
			scroll:{
				opacity:1,
				scale:1
			},
			limit: 0
		};
		this.timeline = [];
		this.runline = [];
		this.position = 0;
		this.limiter = 0;
		this.filter = null;
		this.csa = {
			scroll: new CommentSpaceAllocator(0,0),
			top:new AnchorCommentSpaceAllocator(0,0),
			bottom:new AnchorCommentSpaceAllocator(0,0),
			reverse:new CommentSpaceAllocator(0,0),
			scrollbtm:new CommentSpaceAllocator(0,0)
		};

		/** Precompute the offset width **/
		this.width = this.stage.offsetWidth;
		this.height = this.stage.offsetHeight;
		this.startTimer = function(){
			if(__timer > 0)
				return;
			var lastTPos = new Date().getTime();
			var cmMgr = this;
			__timer = window.setInterval(function(){
				var elapsed = new Date().getTime() - lastTPos;
				lastTPos = new Date().getTime();
				cmMgr.onTimerEvent(elapsed,cmMgr);
			},10);
		};
		this.stopTimer = function(){
			window.clearInterval(__timer);
			__timer = 0;
		};
	}

	/** Public **/
	CommentManager.prototype.stop = function(){
		this.stopTimer();
	};

	CommentManager.prototype.start = function(){
		this.startTimer();
	};

	CommentManager.prototype.seek = function(time){
		this.position = BinArray.bsearch(this.timeline, time, function(a,b){
			if(a < b.stime) return -1
			else if(a > b.stime) return 1;
			else return 0;
		});
	};

	CommentManager.prototype.validate = function(cmt){
		if(cmt == null)
			return false;
		return this.filter.doValidate(cmt);
	};

	CommentManager.prototype.load = function(a){
		this.timeline = a;
		this.timeline.sort(function(a,b){
			if(a.stime > b.stime) return 2;
			else if(a.stime < b.stime) return -2;
			else{
				if(a.date > b.date) return 1;
				else if(a.date < b.date) return -1;
				else if(a.dbid != null && b.dbid != null){
					if(a.dbid > b.dbid) return 1;
					else if(a.dbid < b.dbid) return -1;
					return 0;
				}else
					return 0;
			}
		});
		this.dispatchEvent("load");
	};

	CommentManager.prototype.insert = function(c){
		var index = BinArray.binsert(this.timeline, c, function(a,b){
			if(a.stime > b.stime) return 2;
			else if(a.stime < b.stime) return -2;
			else{
				if(a.date > b.date) return 1;
				else if(a.date < b.date) return -1;
				else if(a.dbid != null && b.dbid != null){
					if(a.dbid > b.dbid) return 1;
					else if(a.dbid < b.dbid) return -1;
					return 0;
				}else
					return 0;
			}
		});
		if(index <= this.position){
			this.position++;
		}
		this.dispatchEvent("insert");
	};

	CommentManager.prototype.clear = function(){
		while(this.runline.length > 0){
			this.runline[0].finish();
		}
		this.dispatchEvent("clear");
	};

	CommentManager.prototype.setBounds = function(){
		this.width = this.stage.offsetWidth;
		this.height= this.stage.offsetHeight;
		this.dispatchEvent("resize");
		for(var comAlloc in this.csa){
			this.csa[comAlloc].setBounds(this.width,this.height);
		}
		// Update 3d perspective
		this.stage.style.perspective = this.width * Math.tan(40 * Math.PI/180) / 2 + "px";
		this.stage.style.webkitPerspective = this.width * Math.tan(40 * Math.PI/180) / 2 + "px";
	};
	CommentManager.prototype.init = function () {
		this.setBounds();
		if (this.filter == null) {
			this.filter = new CommentFilter(); //Only create a filter if none exist
		}
	};
	CommentManager.prototype.time = function(time){
		time = time - 1;
		if(this.position >= this.timeline.length || Math.abs(this._lastPosition - time) >= 2000){
			this.seek(time);
			this._lastPosition = time;
			if(this.timeline.length <= this.position) {
				return;
			}
		}else{
			this._lastPosition = time;
		}
		for(;this.position < this.timeline.length;this.position++){
			if(this.timeline[this.position]['stime']<=time){
				if(this.options.limit > 0 && this.runline.length > this.limiter) {
					continue; // Skip comments but still move the position pointer
				} else if(this.validate(this.timeline[this.position])){
					this.send(this.timeline[this.position]);
				}
			}else{
				break;
			}
		}
	};
	CommentManager.prototype.rescale = function(){

	};
	CommentManager.prototype.send = function(data){
		if(data.mode === 8){
			console.log(data);
			if(this.scripting){
				console.log(this.scripting.eval(data.code));
			}
			return;
		}
		if(this.filter != null){
			data = this.filter.doModify(data);
			if(data == null) return;
		}
		if(data.mode === 1 || data.mode === 2 || data.mode === 6){
			var cmt = new ScrollComment(this, data);
		}else{
			var cmt = new CoreComment(this, data);
		}
		switch(cmt.mode){
			case 1:cmt.align = 0;break;
			case 2:cmt.align = 2;break;
			case 4:cmt.align = 2;break;
			case 5:cmt.align = 0;break;
			case 6:cmt.align = 1;break;
		}
		cmt.init();
		this.stage.appendChild(cmt.dom);
		switch(cmt.mode){
			default:
			case 1:{this.csa.scroll.add(cmt);}break;
			case 2:{this.csa.scrollbtm.add(cmt);}break;
			case 4:{this.csa.bottom.add(cmt);}break;
			case 5:{this.csa.top.add(cmt);}break;
			case 6:{this.csa.reverse.add(cmt);}break;
			case 17:
			case 7:{
				if(data.rY !== 0 || data.rZ !== 0){
					/** TODO: revise when browser manufacturers make up their mind on Transform APIs **/
					cmt.dom.style.transform = getRotMatrix(data.rY, data.rZ);
					cmt.dom.style.webkitTransform = getRotMatrix(data.rY, data.rZ);
					cmt.dom.style.OTransform = getRotMatrix(data.rY, data.rZ);
					cmt.dom.style.MozTransform = getRotMatrix(data.rY, data.rZ);
					cmt.dom.style.MSTransform = getRotMatrix(data.rY, data.rZ);
				}
			}break;
		}
		cmt.y = cmt.y;
		this.dispatchEvent("enterComment", cmt);
		this.runline.push(cmt);
	};
	CommentManager.prototype.sendComment = function(data){
		console.log("CommentManager.sendComment is deprecated. Please use send instead");
		this.send(data); // Wrapper for Backwards Compatible APIs
	};
	CommentManager.prototype.finish = function(cmt){
		this.dispatchEvent("exitComment", cmt);
		this.stage.removeChild(cmt.dom);
		var index = this.runline.indexOf(cmt);
		if(index >= 0){
			this.runline.splice(index, 1);
		}
		switch(cmt.mode){
			default:
			case 1:{this.csa.scroll.remove(cmt);}break;
			case 2:{this.csa.scrollbtm.remove(cmt);}break;
			case 4:{this.csa.bottom.remove(cmt);}break;
			case 5:{this.csa.top.remove(cmt);}break;
			case 6:{this.csa.reverse.remove(cmt);}break;
			case 7:break;
		}
	};
	CommentManager.prototype.addEventListener = function(event, listener){
		if(typeof this._listeners[event] !== "undefined"){
			this._listeners[event].push(listener);
		}else{
			this._listeners[event] = [listener];
		}
	};
	CommentManager.prototype.dispatchEvent = function(event, data){
		if(typeof this._listeners[event] !== "undefined"){
			for(var i = 0; i < this._listeners[event].length; i++){
				try{
					this._listeners[event][i](data);
				}catch(e){
					console.err(e.stack);
				}
			}
		}
	};
	/** Static Functions **/
	CommentManager.prototype.onTimerEvent = function(timePassed,cmObj){
		for(var i= 0;i < cmObj.runline.length; i++){
			var cmt = cmObj.runline[i];
			cmt.time(timePassed);
		}
	};
	return CommentManager;
})();
<commit_msg>Fix some errors and indentation<commit_after>/*!
 * Comment Core Library CommentManager
 * @license MIT
 * @author Jim Chen
 *
 * Copyright (c) 2014 Jim Chen
 */
var CommentManager = (function() {
    var getRotMatrix = function (yrot, zrot) {
        // Courtesy of @StarBrilliant, re-adapted to look better
        var DEG2RAD = Math.PI/180;
        var yr = yrot * DEG2RAD;
        var zr = zrot * DEG2RAD;
        var COS = Math.cos;
        var SIN = Math.sin;
        var matrix = [
            COS(yr) * COS(zr)    , COS(yr) * SIN(zr)     , SIN(yr)  , 0,
            (-SIN(zr))           , COS(zr)               , 0        , 0,
            (-SIN(yr) * COS(zr)) , (-SIN(yr) * SIN(zr))  , COS(yr)  , 0,
            0                    , 0                     , 0        , 1
        ];
        // CSS does not recognize scientific notation (e.g. 1e-6), truncating it.
        for (var i = 0; i < matrix.length;i++) {
            if (Math.abs(matrix[i]) < 0.000001) {
                matrix[i] = 0;
            }
        }
        return "matrix3d(" + matrix.join(",") + ")";
    };

    var defaultComparator = function (a,b) {
        if (a.stime > b.stime) {
            return 2;
        } else if (a.stime < b.stime) {
            return -2;
        } else {
            if (a.date > b.date) {
                return 1;
            } else if (a.date < b.date) {
                return -1;
            } else if (a.dbid != null && b.dbid != null) {
                if (a.dbid > b.dbid) {
                    return 1;
                } else if (a.dbid < b.dbid) {
                    return -1;
                }
                return 0;
            } else {
                return 0;
            }
        }
    };

    function CommentManager(stageObject){
        var __timer = 0;

        this._listeners = {};
        this._lastPosition = 0;

        this.stage = stageObject;
        this.options = {
            global:{
                opacity:1,
                scale:1,
                className:"cmt"
            },
            scroll:{
                opacity:1,
                scale:1
            },
            limit: 0
        };
        this.timeline = [];
        this.runline = [];
        this.position = 0;
        this.limiter = 0;
        this.filter = null;
        this.csa = {
            scroll: new CommentSpaceAllocator(0,0),
            top: new AnchorCommentSpaceAllocator(0,0),
            bottom: new AnchorCommentSpaceAllocator(0,0),
            reverse: new CommentSpaceAllocator(0,0),
            scrollbtm: new CommentSpaceAllocator(0,0)
        };

        /** Precompute the offset width **/
        this.width = this.stage.offsetWidth;
        this.height = this.stage.offsetHeight;
        this.startTimer = function () {
            if (__timer > 0) {
                return;
            }
            var lastTPos = new Date().getTime();
            var cmMgr = this;
            __timer = window.setInterval(function () {
                var elapsed = new Date().getTime() - lastTPos;
                lastTPos = new Date().getTime();
                cmMgr.onTimerEvent(elapsed,cmMgr);
            },10);
        };
        this.stopTimer = function () {
            window.clearInterval(__timer);
            __timer = 0;
        };
    }

    /** Public **/
    CommentManager.prototype.stop = function(){
        this.stopTimer();
    };

    CommentManager.prototype.start = function(){
        this.startTimer();
    };

    CommentManager.prototype.seek = function(time){
        this.position = BinArray.bsearch(this.timeline, time, function(a,b){
            if (a < b.stime) {
                return -1
            } else if(a > b.stime) {
                return 1;
            } else {
                return 0;
            }
        });
    };

    CommentManager.prototype.validate = function(cmt){
        if (cmt == null) {
            return false;
        }
        return this.filter.doValidate(cmt);
    };

    CommentManager.prototype.load = function(a){
        this.timeline = a;
        this.timeline.sort(_defaultComparator);
        this.dispatchEvent("load");
    };

    CommentManager.prototype.insert = function(c){
        var index = BinArray.binsert(this.timeline, c, _defaultComparator);
        if (index <= this.position) {
            this.position++;
        }
        this.dispatchEvent("insert");
    };

    CommentManager.prototype.clear = function () {
        while (this.runline.length > 0) {
            this.runline[0].finish();
        }
        this.dispatchEvent("clear");
    };

    CommentManager.prototype.setBounds = function () {
        this.width = this.stage.offsetWidth;
        this.height= this.stage.offsetHeight;
        this.dispatchEvent("resize");
        for (var comAlloc in this.csa) {
            this.csa[comAlloc].setBounds(this.width,this.height);
        }
        // Update 3d perspective
        this.stage.style.perspective = this.width * Math.tan(40 * Math.PI/180) / 2 + "px";
        this.stage.style.webkitPerspective = this.width * Math.tan(40 * Math.PI/180) / 2 + "px";
    };

    CommentManager.prototype.init = function () {
        this.setBounds();
        if (this.filter == null) {
            this.filter = new CommentFilter(); //Only create a filter if none exist
        }
    };

    CommentManager.prototype.time = function (time) {
        time = time - 1;
        if (this.position >= this.timeline.length || Math.abs(this._lastPosition - time) >= 2000) {
            this.seek(time);
            this._lastPosition = time;
            if (this.timeline.length <= this.position) {
                return;
            }
        } else {
            this._lastPosition = time;
        }
        for (;this.position < this.timeline.length;this.position++) {
            if (this.timeline[this.position]['stime']<=time) {
                if (this.options.limit > 0 && this.runline.length > this.limiter) {
                    continue; // Skip comments but still move the position pointer
                } else if (this.validate(this.timeline[this.position])) {
                    this.send(this.timeline[this.position]);
                }
            } else {
                break;
            }
        }
    };

    CommentManager.prototype.rescale = function () {

    };

    CommentManager.prototype.send = function (data) {
        if (data.mode === 8) {
            console.log(data);
            if (this.scripting) {
                console.log(this.scripting.eval(data.code));
            }
            return;
        }
        if (this.filter != null) {
            data = this.filter.doModify(data);
            if (data == null) {
                return;
            }
        }
        if (data.mode === 1 || data.mode === 2 || data.mode === 6) {
            var cmt = new ScrollComment(this, data);
        } else {
            var cmt = new CoreComment(this, data);
        }
        switch (cmt.mode) {
            case 1:cmt.align = 0;break;
            case 2:cmt.align = 2;break;
            case 4:cmt.align = 2;break;
            case 5:cmt.align = 0;break;
            case 6:cmt.align = 1;break;
        }
        cmt.init();
        this.stage.appendChild(cmt.dom);
        switch (cmt.mode) {
            default:
            case 1:{this.csa.scroll.add(cmt);}break;
            case 2:{this.csa.scrollbtm.add(cmt);}break;
            case 4:{this.csa.bottom.add(cmt);}break;
            case 5:{this.csa.top.add(cmt);}break;
            case 6:{this.csa.reverse.add(cmt);}break;
            case 17:
            case 7:{
                if (data.rY !== 0 || data.rZ !== 0) {
                    /** TODO: revise when browser manufacturers make up their mind on Transform APIs **/
                    cmt.dom.style.transform = getRotMatrix(data.rY, data.rZ);
                    cmt.dom.style.webkitTransform = getRotMatrix(data.rY, data.rZ);
                    cmt.dom.style.OTransform = getRotMatrix(data.rY, data.rZ);
                    cmt.dom.style.MozTransform = getRotMatrix(data.rY, data.rZ);
                    cmt.dom.style.MSTransform = getRotMatrix(data.rY, data.rZ);
                }
            }break;
        }
        cmt.y = cmt.y;
        this.dispatchEvent("enterComment", cmt);
        this.runline.push(cmt);
    };

    CommentManager.prototype.finish = function (cmt) {
        this.dispatchEvent("exitComment", cmt);
        this.stage.removeChild(cmt.dom);
        var index = this.runline.indexOf(cmt);
        if (index >= 0) {
            this.runline.splice(index, 1);
        }
        switch (cmt.mode) {
            default:
            case 1: {this.csa.scroll.remove(cmt);} break;
            case 2: {this.csa.scrollbtm.remove(cmt);} break;
            case 4: {this.csa.bottom.remove(cmt);} break;
            case 5: {this.csa.top.remove(cmt);} break;
            case 6: {this.csa.reverse.remove(cmt);} break;
            case 7: break;
        }
    };

    CommentManager.prototype.addEventListener = function (event, listener) {
        if (typeof this._listeners[event] !== "undefined") {
            this._listeners[event].push(listener);
        } else {
            this._listeners[event] = [listener];
        }
    };

    CommentManager.prototype.dispatchEvent = function (event, data) {
        if (typeof this._listeners[event] !== "undefined") {
            for (var i = 0; i < this._listeners[event].length; i++) {
                try {
                    this._listeners[event][i](data);
                } catch (e) {
                    console.err(e.stack);
                }
            }
        }
    };

    /** Static Functions **/
    CommentManager.prototype.onTimerEvent = function (timePassed,cmObj) {
        for (var i= 0;i < cmObj.runline.length; i++) {
            var cmt = cmObj.runline[i];
            cmt.time(timePassed);
        }
    };

    return CommentManager;
})();
<|endoftext|>


<commit_before>import CanvasControl from './jsiso/canvas/Control';
import CanvasInput from './jsiso/canvas/Input';
import imgLoader from './jsiso/img/load';
import jsonLoader from './jsiso/json/load';
import TileField from './jsiso/tile/Field';
import pathfind from './jsiso/pathfind/pathfind';

import Player from './player';
import ActionExecutor from './action';
import EventEmitting from './EventEmitter';

import TextOutput from './extensions/TextOutput';
import KeyboardInput from './extensions/KeyboardInput';
import MouseInput from './extensions/MouseInput';

import {appendHtml, computeOnce} from './util';

let requestAnimFrame = (function() {
  return window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame  ||
  window.mozRequestAnimationFrame     ||
  window.oRequestAnimationFrame       ||
  window.msRequestAnimationFrame      ||
  function(callback, element) {
    window.setTimeout(callback, 1000 / 60);
  };
})();

const CONTAINER_NAME = 'container';

export default class TileEngine extends EventEmitting(Object) {

  constructor(x, y, xrange, yrange, overrides) {
    super();

    let self = this;
    overrides = Object.assign({}, overrides);

    let parent = overrides.parent || document.body;
    if (!overrides.useCustomElements) {
      appendHtml(parent, '

');
    }
    const container = document.getElementById(CONTAINER_NAME);

    const controlWidth = container.clientWidth;
    const controlHeight = container.clientHeight;
    const context = CanvasControl.create("canvas", controlWidth, controlHeight, {}, CONTAINER_NAME, true);

    let currentMap;

    let paused = false;
    let mapLayers = [];
    let players = [];
    let playerMap = {};

    let actionExecutor = new ActionExecutor();
    actionExecutor.registerAction('toggleTile', (options, engine, player) => {
      let layers = mapLayers.filter((layer) => layer.zIndex === player.properties.zIndex);
      layers.forEach((layer) => {
        let currentTile = layer.getTile(options.target.x, options.target.y);
        let currentIndex = options.tiles.indexOf(currentTile);
        layer.setTile(options.target.x, options.target.y, options.tiles[(currentIndex + 1) % options.tiles.length]);
      })
    });

    let getActions = () => currentMap.actions || [];

    let interact = (player, tile) => {
      if (paused) {
        this.drawMessages();
      } else {
        if (!player.isMoving()) {
          getActions()
            .filter((action) => action.type !== actionExecutor.TYPE_POSITIONAL)
            .filter((action) => action.x === tile.x && action.y == tile.y)
            .forEach((action) => actionExecutor.execute(action, self, player));
        }
      }
    };

    let pause = () => {
      paused = true;
    }

    let unpause = () => {
      if (paused) {
        paused = false;
        draw();
      }
    }

    let getCharacter = (id) => playerMap[id];

    let setPlayerLighting = (tile) => {
      mapLayers.forEach((layer) => layer.setLight(tile.x, tile.y));
    }

    let drawLayer = (layer) => {
      for (let i = 0; i < (layer.width || xrange); i++) {
        for (let j = 0; j < (layer.height || yrange); j++) {
          layer.draw(i, j, void 0, (layer.x || x), (layer.y || y));
        }
      }
    }

    let drawPlayer = (player) => {
      player.draw();
      player.move();
      if (player.useLighting) {
        setPlayerLighting(player.getTile());
      }
    }

    let previousTime = 0;
    let timeToDraw = (time) => !overrides.lockedFrameRate || (time - previousTime) >= 1000 / overrides.lockedFrameRate;

    let draw = (time) => {
      if (!timeToDraw(time)) {
        requestAnimationFrame(draw);
      } else {
        previousTime = time;
        context.clearRect(0, 0, controlWidth, controlHeight);
        let comparator = (a, b) => a.zIndex > b.zIndex;
        let thingsToDraw = mapLayers.sort(comparator);
        let playersToDraw = players.slice().sort(comparator);
        for (let thing of thingsToDraw) {
          while (playersToDraw.length > 0 && playersToDraw[0].zIndex < thing.zIndex) {
            drawPlayer(playersToDraw.shift());
          }
          if (thing.visible) {
            drawLayer(thing);
          }
        }
        playersToDraw.forEach(drawPlayer);
        this.drawMessages();
        if (!paused) {
          requestAnimationFrame(draw);
        }
      }
    }

    let initLayer = (layer) => {
      let mapLayer = new TileField(context, controlWidth, controlHeight);
      mapLayer.setup(layer);
      mapLayer.flip("horizontal");
      mapLayer.rotate("left");
      mapLayer.setLightmap(layer.lightmap);
      mapLayer = Object.assign(mapLayer, layer);
      return mapLayer;
    }

    let createEmptyLayer = computeOnce((map) => {
      let layer = {
        width: map.width,
        height: map.height,
        layout: Array(map.width * map.height).fill(0)
      }
      return initLayer(layer);
    });

    let init = (map) => {
      currentMap = map;
      mapLayers = map.layers.map(initLayer);
      draw();
      let promises = [];
      let characters = map.characters || {};
      for (let characterId of Object.keys(characters)) {
        let playerOptions = characters[characterId];
        if (playerOptions) {
          promises.push(imgLoader([{
            graphics: [playerOptions.sprites],
            spritesheet: {
              width: playerOptions.width,
              height: playerOptions.height
            }
          }]).then((playerImages) => {
            playerOptions.files = playerImages[0].files;
            playerOptions.layer = mapLayers[0];
            playerOptions.pathfindingLayer = mapLayers[playerOptions.pathfindingLayer] || createEmptyLayer(map);
            playerOptions.tileWidth = map.tileWidth;
            playerOptions.tileHeight = map.tileHeight;

            let player = new Player(context, playerOptions, playerOptions.x, playerOptions.y, pathfind);
            player.on("changeTile", (p, tile) => {
              getActions().filter((action) => action.type === actionExecutor.TYPE_POSITIONAL).forEach((action) => {
                if (action.x === tile.x && action.y === tile.y) {
                  actionExecutor.execute(action, self, p);
                }
              })
            });
            players.push(player);
            playerMap[characterId] = player;
          }));
        }
      }
      return Promise.all(promises)
        .then(() => {
          const input = new CanvasInput(document, CanvasControl());
          const player = getCharacter('player');

          if (overrides.enableMouseInput) {
            MouseInput(input, self, player);
          }
          if (overrides.enableKeyboardInput) {
            KeyboardInput(input, self, player);
          }
          if (overrides.enableTextOutput) {
            TextOutput(parent, self, overrides);
          }
        })
        .catch(console.error);
    }

    this.init = init;
    this.pause = pause;
    this.unpause = unpause;
    this.paused = paused;
    this.getCharacter = getCharacter;
    this.interact = interact;

    this.actionExecutor = actionExecutor;
    this.currentMap = currentMap;

    this.clearText = () => {
      this.createEvent('clearText', arguments);
    }

    this.displayText = () => {
      this.createEvent('displayText', arguments);
    }

    this.drawMessages = () => {
      this.createEvent('drawMessages', arguments);
    }
  }
}
<commit_msg>Add events for pause, unpause, and interact<commit_after>import CanvasControl from './jsiso/canvas/Control';
import CanvasInput from './jsiso/canvas/Input';
import imgLoader from './jsiso/img/load';
import jsonLoader from './jsiso/json/load';
import TileField from './jsiso/tile/Field';
import pathfind from './jsiso/pathfind/pathfind';

import Player from './player';
import ActionExecutor from './action';
import EventEmitting from './EventEmitter';

import TextOutput from './extensions/TextOutput';
import KeyboardInput from './extensions/KeyboardInput';
import MouseInput from './extensions/MouseInput';

import {appendHtml, computeOnce} from './util';

let requestAnimFrame = (function() {
  return window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame  ||
  window.mozRequestAnimationFrame     ||
  window.oRequestAnimationFrame       ||
  window.msRequestAnimationFrame      ||
  function(callback, element) {
    window.setTimeout(callback, 1000 / 60);
  };
})();

const CONTAINER_NAME = 'container';

export default class TileEngine extends EventEmitting(Object) {

  constructor(x, y, xrange, yrange, overrides) {
    super();

    let self = this;
    overrides = Object.assign({}, overrides);

    let parent = overrides.parent || document.body;
    if (!overrides.useCustomElements) {
      appendHtml(parent, '

');
    }
    const container = document.getElementById(CONTAINER_NAME);

    const controlWidth = container.clientWidth;
    const controlHeight = container.clientHeight;
    const context = CanvasControl.create("canvas", controlWidth, controlHeight, {}, CONTAINER_NAME, true);

    let currentMap;

    let paused = false;
    let mapLayers = [];
    let players = [];
    let playerMap = {};

    let actionExecutor = new ActionExecutor();
    actionExecutor.registerAction('toggleTile', (options, engine, player) => {
      let layers = mapLayers.filter((layer) => layer.zIndex === player.properties.zIndex);
      layers.forEach((layer) => {
        let currentTile = layer.getTile(options.target.x, options.target.y);
        let currentIndex = options.tiles.indexOf(currentTile);
        layer.setTile(options.target.x, options.target.y, options.tiles[(currentIndex + 1) % options.tiles.length]);
      })
    });

    let getActions = () => currentMap.actions || [];

    let interact = (player, tile) => {
      this.createEvent('interact', arguments);
      if (paused) {
        this.drawMessages();
      } else {
        if (!player.isMoving()) {
          getActions()
            .filter((action) => action.type !== actionExecutor.TYPE_POSITIONAL)
            .filter((action) => action.x === tile.x && action.y == tile.y)
            .forEach((action) => actionExecutor.execute(action, self, player));
        }
      }
    };

    let pause = () => {
      this.createEvent('pause');
      paused = true;
    }

    let unpause = () => {
      if (paused) {
        this.createEvent('unpause');
        paused = false;
        draw();
      }
    }

    let getCharacter = (id) => playerMap[id];

    let setPlayerLighting = (tile) => {
      mapLayers.forEach((layer) => layer.setLight(tile.x, tile.y));
    }

    let drawLayer = (layer) => {
      for (let i = 0; i < (layer.width || xrange); i++) {
        for (let j = 0; j < (layer.height || yrange); j++) {
          layer.draw(i, j, void 0, (layer.x || x), (layer.y || y));
        }
      }
    }

    let drawPlayer = (player) => {
      player.draw();
      player.move();
      if (player.useLighting) {
        setPlayerLighting(player.getTile());
      }
    }

    let previousTime = 0;
    let timeToDraw = (time) => !overrides.lockedFrameRate || (time - previousTime) >= 1000 / overrides.lockedFrameRate;

    let draw = (time) => {
      if (!timeToDraw(time)) {
        requestAnimationFrame(draw);
      } else {
        previousTime = time;
        context.clearRect(0, 0, controlWidth, controlHeight);
        let comparator = (a, b) => a.zIndex > b.zIndex;
        let thingsToDraw = mapLayers.sort(comparator);
        let playersToDraw = players.slice().sort(comparator);
        for (let thing of thingsToDraw) {
          while (playersToDraw.length > 0 && playersToDraw[0].zIndex < thing.zIndex) {
            drawPlayer(playersToDraw.shift());
          }
          if (thing.visible) {
            drawLayer(thing);
          }
        }
        playersToDraw.forEach(drawPlayer);
        this.drawMessages();
        if (!paused) {
          requestAnimationFrame(draw);
        }
      }
    }

    let initLayer = (layer) => {
      let mapLayer = new TileField(context, controlWidth, controlHeight);
      mapLayer.setup(layer);
      mapLayer.flip("horizontal");
      mapLayer.rotate("left");
      mapLayer.setLightmap(layer.lightmap);
      mapLayer = Object.assign(mapLayer, layer);
      return mapLayer;
    }

    let createEmptyLayer = computeOnce((map) => {
      let layer = {
        width: map.width,
        height: map.height,
        layout: Array(map.width * map.height).fill(0)
      }
      return initLayer(layer);
    });

    let init = (map) => {
      currentMap = map;
      mapLayers = map.layers.map(initLayer);
      draw();
      let promises = [];
      let characters = map.characters || {};
      for (let characterId of Object.keys(characters)) {
        let playerOptions = characters[characterId];
        if (playerOptions) {
          promises.push(imgLoader([{
            graphics: [playerOptions.sprites],
            spritesheet: {
              width: playerOptions.width,
              height: playerOptions.height
            }
          }]).then((playerImages) => {
            playerOptions.files = playerImages[0].files;
            playerOptions.layer = mapLayers[0];
            playerOptions.pathfindingLayer = mapLayers[playerOptions.pathfindingLayer] || createEmptyLayer(map);
            playerOptions.tileWidth = map.tileWidth;
            playerOptions.tileHeight = map.tileHeight;

            let player = new Player(context, playerOptions, playerOptions.x, playerOptions.y, pathfind);
            player.on("changeTile", (p, tile) => {
              getActions().filter((action) => action.type === actionExecutor.TYPE_POSITIONAL).forEach((action) => {
                if (action.x === tile.x && action.y === tile.y) {
                  actionExecutor.execute(action, self, p);
                }
              })
            });
            players.push(player);
            playerMap[characterId] = player;
          }));
        }
      }
      return Promise.all(promises)
        .then(() => {
          const input = new CanvasInput(document, CanvasControl());
          const player = getCharacter('player');

          if (overrides.enableMouseInput) {
            MouseInput(input, self, player);
          }
          if (overrides.enableKeyboardInput) {
            KeyboardInput(input, self, player);
          }
          if (overrides.enableTextOutput) {
            TextOutput(parent, self, overrides);
          }
        })
        .catch(console.error);
    }

    this.init = init;
    this.pause = pause;
    this.unpause = unpause;
    this.paused = paused;
    this.getCharacter = getCharacter;
    this.interact = interact;

    this.actionExecutor = actionExecutor;
    this.currentMap = currentMap;

    this.clearText = () => {
      this.createEvent('clearText', arguments);
    }

    this.displayText = () => {
      this.createEvent('displayText', arguments);
    }

    this.drawMessages = () => {
      this.createEvent('drawMessages', arguments);
    }
  }
}
<|endoftext|>


<commit_before>var chai = require('chai');
var expect = chai.expect;
var util = require('./util');

describe('widget' , function() {
    beforeEach(function() {
        util.cleanup();
    });

    it('should create widgets with the expected properties', function() {

        var widget = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        expect(widget.id).to.be.a('string');
        expect(widget.emit).to.be.a('function');
        expect(widget.on).to.be.a('function');
        expect(widget.once).to.be.a('function');
        expect(widget.addListener).to.be.a('function');
        expect(widget.subscribeTo).to.be.a('function');
        expect(widget.getElId).to.be.a('function');
        expect(widget.elId).to.be.a('function');
        expect(widget.getEl).to.be.a('function');
        expect(widget.destroy).to.be.a('function');
        expect(widget.isDestroyed).to.be.a('function');
        expect(widget.rerender).to.be.a('function');
        expect(widget.detach).to.be.a('function');
        expect(widget.appendTo).to.be.a('function');
        expect(widget.replace).to.be.a('function');
        expect(widget.replaceChildrenOf).to.be.a('function');
        expect(widget.insertBefore).to.be.a('function');
        expect(widget.insertAfter).to.be.a('function');
        expect(widget.prependTo).to.be.a('function');
        expect(widget.ready).to.be.a('function');
        expect(widget.$).to.be.a('function');
    });

    it('should create widgets that extend EventEmitter', function() {
        var widget = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        var fooEvent = null;
        var fooEventThis = null;

        function fooListener() {
            fooEvent = arguments;
            fooEventThis = this;
        }

        widget.on('foo', fooListener);

        widget.emit('foo', 'a', 'b');

        expect(fooEvent[0]).to.equal('a');

        expect(fooEvent[1]).to.equal('b');
        expect(fooEventThis).to.equal(widget);

        fooEvent = null;

        widget.removeListener('foo', fooListener);

        widget.emit('foo', 'a', 'b');

        expect(fooEvent).to.equal(null);
    });

    it('should create widgets that allow subscribeTo', function() {
        var widget1 = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        var widget2 = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        var fooEvent = null;
        var fooEventThis = null;

        widget1.subscribeTo(widget2)
            .on('foo', function fooListener() {
                fooEvent = arguments;
                fooEventThis = this;
            });

        widget2.emit('foo', 'a', 'b');

        expect(fooEvent[0]).to.equal('a');
        expect(fooEvent[1]).to.equal('b');
        expect(fooEventThis).to.equal(widget2);

        fooEvent = null;

        widget2.destroy();

        widget2.emit('foo', 'a', 'b');

        expect(fooEvent).to.equal(null);
    });

    it('should create widgets that supports this.$(...)', function() {
        var widget = require('./fixtures/components/app-jquery-proxy')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        widget.test();
    });

    it('should create widgets that supports rerender', function() {
        var previousSibling = document.createElement('div');
        document.getElementById('target').appendChild(previousSibling);

        var widget = require('./fixtures/components/app-rerender')
            .render({
                label: 'Foo'
            })
            .appendTo(document.getElementById('target'))
            .getWidget();

        var nextSibling = document.createElement('div');
        document.getElementById('target').appendChild(nextSibling);

        expect(widget.el.previousSibling).to.equal(previousSibling);
        expect(widget.el.nextSibling).to.equal(nextSibling);

        var parentNode = widget.el.parentNode;

        expect(widget.el.innerHTML).to.equal('Foo');

        var newWidget = widget.rerender({
            label: 'Bar'
        });

        expect(newWidget.el.parentNode).to.equal(parentNode);
        expect(widget.el.parentNode == null).to.equal(true);

        expect(document.getElementById('target').childNodes.length).to.equal(3);
        expect(document.getElementById('target').childNodes[0]).to.equal(previousSibling);
        expect(document.getElementById('target').childNodes[1]).to.equal(newWidget.el);
        expect(document.getElementById('target').childNodes[2]).to.equal(nextSibling);
    });
});

<commit_msg>Added test for destroy cleanup<commit_after>var chai = require('chai');
var expect = chai.expect;
var util = require('./util');

describe('widget' , function() {
    beforeEach(function() {
        util.cleanup();
    });

    it('should create widgets with the expected properties', function() {

        var widget = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        expect(widget.id).to.be.a('string');
        expect(widget.emit).to.be.a('function');
        expect(widget.on).to.be.a('function');
        expect(widget.once).to.be.a('function');
        expect(widget.addListener).to.be.a('function');
        expect(widget.subscribeTo).to.be.a('function');
        expect(widget.getElId).to.be.a('function');
        expect(widget.elId).to.be.a('function');
        expect(widget.getEl).to.be.a('function');
        expect(widget.destroy).to.be.a('function');
        expect(widget.isDestroyed).to.be.a('function');
        expect(widget.rerender).to.be.a('function');
        expect(widget.detach).to.be.a('function');
        expect(widget.appendTo).to.be.a('function');
        expect(widget.replace).to.be.a('function');
        expect(widget.replaceChildrenOf).to.be.a('function');
        expect(widget.insertBefore).to.be.a('function');
        expect(widget.insertAfter).to.be.a('function');
        expect(widget.prependTo).to.be.a('function');
        expect(widget.ready).to.be.a('function');
        expect(widget.$).to.be.a('function');
    });

    it('should create widgets that extend EventEmitter', function() {
        var widget = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        var fooEvent = null;
        var fooEventThis = null;

        function fooListener() {
            fooEvent = arguments;
            fooEventThis = this;
        }

        widget.on('foo', fooListener);

        widget.emit('foo', 'a', 'b');

        expect(fooEvent[0]).to.equal('a');

        expect(fooEvent[1]).to.equal('b');
        expect(fooEventThis).to.equal(widget);

        fooEvent = null;

        widget.removeListener('foo', fooListener);

        widget.emit('foo', 'a', 'b');

        expect(fooEvent).to.equal(null);
    });

    it('should create widgets that allow subscribeTo', function() {
        var widget1 = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        var widget2 = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        var fooEvent = null;
        var fooEventThis = null;

        widget1.subscribeTo(widget2)
            .on('foo', function fooListener() {
                fooEvent = arguments;
                fooEventThis = this;
            });

        widget2.emit('foo', 'a', 'b');

        expect(fooEvent[0]).to.equal('a');
        expect(fooEvent[1]).to.equal('b');
        expect(fooEventThis).to.equal(widget2);

        fooEvent = null;

        widget2.destroy();

        widget2.emit('foo', 'a', 'b');

        expect(fooEvent).to.equal(null);
    });

    it('should create widgets that supports this.$(...)', function() {
        var widget = require('./fixtures/components/app-jquery-proxy')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        widget.test();
    });

    it('should create widgets that supports rerender', function() {
        var previousSibling = document.createElement('div');
        document.getElementById('target').appendChild(previousSibling);

        var widget = require('./fixtures/components/app-rerender')
            .render({
                label: 'Foo'
            })
            .appendTo(document.getElementById('target'))
            .getWidget();

        var nextSibling = document.createElement('div');
        document.getElementById('target').appendChild(nextSibling);

        expect(widget.el.previousSibling).to.equal(previousSibling);
        expect(widget.el.nextSibling).to.equal(nextSibling);

        var parentNode = widget.el.parentNode;

        expect(widget.el.innerHTML).to.equal('Foo');

        var newWidget = widget.rerender({
            label: 'Bar'
        });

        expect(newWidget.el.parentNode).to.equal(parentNode);
        expect(widget.el.parentNode == null).to.equal(true);

        expect(document.getElementById('target').childNodes.length).to.equal(3);
        expect(document.getElementById('target').childNodes[0]).to.equal(previousSibling);
        expect(document.getElementById('target').childNodes[1]).to.equal(newWidget.el);
        expect(document.getElementById('target').childNodes[2]).to.equal(nextSibling);
    });

    it('should remove destroyed widgets from scoped widget collection', function() {
        var fooWidget = require('./fixtures/components/app-foo')
            .render({})
            .appendTo(document.getElementById('target'))
            .getWidget();

        expect(fooWidget.widgets.bar).to.not.be.empty;

        fooWidget.widgets.bar.destroy();

        expect(fooWidget.widgets.bar).to.be.empty;
    });
});

<|endoftext|>


<commit_before>function camelize(str) {
  return str
    .toLowerCase()
    .replace(/_([a-z])/g, ([,letter]) => letter.toUpperCase());
}

function listToMap(list) {
  const map = list.reduce((map, name) => {
    map[name] = camelize(name);
    return map;
  }, {});

  map.keys = list;
  return map;
}

const ErrorTypes = listToMap([
  "NETWORK_ERROR",
  "MEDIA_ERROR",
  "ENCRYPTED_MEDIA_ERROR",
  "INDEX_ERROR",
  "OTHER_ERROR",
]);

const RequestErrorTypes = listToMap([
  "TIMEOUT",
  "ERROR_EVENT",
  "ERROR_HTTP_CODE",
  "PARSE_ERROR",
]);

const ErrorCodes = listToMap([
  "PIPELINE_RESOLVE_ERROR",
  "PIPELINE_LOAD_ERROR",
  "PIPELINE_PARSING_ERROR",

  "MANIFEST_PARSE_ERROR",
  "MANIFEST_INCOMPATIBLE_CODECS_ERROR",

  "MEDIA_IS_ENCRYPTED_ERROR",

  "KEY_ERROR",
  "KEY_STATUS_CHANGE_ERROR",
  "KEY_UPDATE_ERROR",
  "KEY_LOAD_ERROR",
  "KEY_LOAD_TIMEOUT",
  "INCOMPATIBLE_KEYSYSTEMS",

  "BUFFER_APPEND_ERROR",
  "BUFFER_FULL_ERROR",
  "BUFFER_INDEX_ERROR",
  "BUFFER_TYPE_UNKNOWN",

  "MEDIA_ERR_ABORTED",
  "MEDIA_ERR_NETWORK",
  "MEDIA_ERR_DECODE",
  "MEDIA_ERR_SRC_NOT_SUPPORTED",

  "MEDIA_SOURCE_NOT_SUPPORTED",
  "MEDIA_KEYS_NOT_SUPPORTED",

  "OUT_OF_INDEX_ERROR",
  "UNKNOWN_INDEX",

  "NONE",
]);

function errorMessage(name, code, reason) {
  return `${name}(${code})${reason ? ": " + reason.message : ""}`;
}

function MediaError(code, reason, fatal) {
  this.name = "MediaError";
  this.type = ErrorTypes.MEDIA_ERROR;

  this.reason = reason;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, this.reason);
}
MediaError.prototype = new Error();

function NetworkError(code, reason, fatal) {
  this.name = "NetworkError";
  this.type = ErrorTypes.NETWORK_ERROR;

  this.xhr = reason.xhr;
  this.url = reason.url;
  this.status = reason.status;
  this.reqType = reason.type;

  this.reason = reason;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, this.reason);
}
NetworkError.prototype = new Error();

NetworkError.prototype.isHttpError = function(httpErrorCode) {
  return (
    this.reqType == RequestErrorTypes.ERROR_HTTP_CODE &&
    this.status == httpErrorCode
  );
};

function EncryptedMediaError(code, reason, fatal) {
  this.name = "EncryptedMediaError";
  this.type = ErrorTypes.ENCRYPTED_MEDIA_ERROR;

  this.reason = reason;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, this.reason);
}
EncryptedMediaError.prototype = new Error();

function IndexError(code, indexType, fatal) {
  this.name = "IndexError";
  this.type = ErrorTypes.INDEX_ERROR;

  this.indexType = indexType;

  this.reason = null;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, null);
}
IndexError.prototype = new Error();

function OtherError(code, reason, fatal) {
  this.name = "OtherError";
  this.type = ErrorTypes.OTHER_ERROR;

  this.reason = reason;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, this.reason);
}
OtherError.prototype = new Error();

function RequestError(xhr, request, type) {
  this.name = "RequestError";
  this.url = request.url;
  this.xhr = xhr;
  this.status = xhr.status;
  this.type = type;
  this.message = type;
}
RequestError.prototype = new Error();

function isKnownError(error) {
  return (!!error && !!error.type && ErrorTypes.keys.indexOf(error.type) >= 0);
}

module.exports = {
  ErrorTypes,
  ErrorCodes,

  MediaError,
  NetworkError,
  EncryptedMediaError,
  IndexError,
  OtherError,

  RequestError,
  RequestErrorTypes,
  isKnownError,
};
<commit_msg>errors: do not camelize names<commit_after>function listToMap(list) {
  const map = list.reduce((map, name) => {
    map[name] = name;
    return map;
  }, {});

  map.keys = list;
  return map;
}

const ErrorTypes = listToMap([
  "NETWORK_ERROR",
  "MEDIA_ERROR",
  "ENCRYPTED_MEDIA_ERROR",
  "INDEX_ERROR",
  "OTHER_ERROR",
]);

const RequestErrorTypes = listToMap([
  "TIMEOUT",
  "ERROR_EVENT",
  "ERROR_HTTP_CODE",
  "PARSE_ERROR",
]);

const ErrorCodes = listToMap([
  "PIPELINE_RESOLVE_ERROR",
  "PIPELINE_LOAD_ERROR",
  "PIPELINE_PARSING_ERROR",

  "MANIFEST_PARSE_ERROR",
  "MANIFEST_INCOMPATIBLE_CODECS_ERROR",

  "MEDIA_IS_ENCRYPTED_ERROR",

  "KEY_ERROR",
  "KEY_STATUS_CHANGE_ERROR",
  "KEY_UPDATE_ERROR",
  "KEY_LOAD_ERROR",
  "KEY_LOAD_TIMEOUT",
  "INCOMPATIBLE_KEYSYSTEMS",

  "BUFFER_APPEND_ERROR",
  "BUFFER_FULL_ERROR",
  "BUFFER_INDEX_ERROR",
  "BUFFER_TYPE_UNKNOWN",

  "MEDIA_ERR_ABORTED",
  "MEDIA_ERR_NETWORK",
  "MEDIA_ERR_DECODE",
  "MEDIA_ERR_SRC_NOT_SUPPORTED",

  "MEDIA_SOURCE_NOT_SUPPORTED",
  "MEDIA_KEYS_NOT_SUPPORTED",

  "OUT_OF_INDEX_ERROR",
  "UNKNOWN_INDEX",

  "NONE",
]);

function errorMessage(name, code, reason) {
  return `${name}(${code})${reason ? ": " + reason.message : ""}`;
}

function MediaError(code, reason, fatal) {
  this.name = "MediaError";
  this.type = ErrorTypes.MEDIA_ERROR;

  this.reason = reason;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, this.reason);
}
MediaError.prototype = new Error();

function NetworkError(code, reason, fatal) {
  this.name = "NetworkError";
  this.type = ErrorTypes.NETWORK_ERROR;

  this.xhr = reason.xhr;
  this.url = reason.url;
  this.status = reason.status;
  this.reqType = reason.type;

  this.reason = reason;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, this.reason);
}
NetworkError.prototype = new Error();

NetworkError.prototype.isHttpError = function(httpErrorCode) {
  return (
    this.reqType == RequestErrorTypes.ERROR_HTTP_CODE &&
    this.status == httpErrorCode
  );
};

function EncryptedMediaError(code, reason, fatal) {
  this.name = "EncryptedMediaError";
  this.type = ErrorTypes.ENCRYPTED_MEDIA_ERROR;

  this.reason = reason;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, this.reason);
}
EncryptedMediaError.prototype = new Error();

function IndexError(code, indexType, fatal) {
  this.name = "IndexError";
  this.type = ErrorTypes.INDEX_ERROR;

  this.indexType = indexType;

  this.reason = null;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, null);
}
IndexError.prototype = new Error();

function OtherError(code, reason, fatal) {
  this.name = "OtherError";
  this.type = ErrorTypes.OTHER_ERROR;

  this.reason = reason;
  this.code = ErrorCodes[code];
  this.fatal = fatal;
  this.message = errorMessage(this.name, this.code, this.reason);
}
OtherError.prototype = new Error();

function RequestError(xhr, request, type) {
  this.name = "RequestError";
  this.url = request.url;
  this.xhr = xhr;
  this.status = xhr.status;
  this.type = type;
  this.message = type;
}
RequestError.prototype = new Error();

function isKnownError(error) {
  return (!!error && !!error.type && ErrorTypes.keys.indexOf(error.type) >= 0);
}

module.exports = {
  ErrorTypes,
  ErrorCodes,

  MediaError,
  NetworkError,
  EncryptedMediaError,
  IndexError,
  OtherError,

  RequestError,
  RequestErrorTypes,
  isKnownError,
};
<|endoftext|>


<commit_before>'use strict';

// This file hosts our error definitions
// We use custom error "types" so that we can act on them when we need it
// e.g.: if error instanceof errors.UnparsableJSON then..

var inherits = require('inherits');

function AlgoliaSearchError(message, extraProperties) {
  var forEach = require('foreach');

  var error = this;

  // try to get a stacktrace
  if (typeof Error.captureStackTrace === 'function') {
    Error.captureStackTrace(this, this.constructor);
  } else {
    error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old';
  }

  this.name = 'AlgoliaSearchError';
  this.message = message || 'Unknown error';

  if (extraProperties) {
    forEach(extraProperties, function addToErrorObject(value, key) {
      error[key] = value;
    });
  }
}

inherits(AlgoliaSearchError, Error);

function createCustomError(name, message) {
  function AlgoliaSearchCustomError() {
    var args = Array.prototype.slice.call(arguments, 0);

    // custom message not set, use default
    if (typeof args[0] !== 'string') {
      args.unshift(message);
    }

    AlgoliaSearchError.apply(this, args);
    this.name = 'AlgoliaSearch' + name + 'Error';
  }

  inherits(AlgoliaSearchCustomError, AlgoliaSearchError);

  return AlgoliaSearchCustomError;
}

// late exports to let various fn defs and inherits take place
module.exports = {
  AlgoliaSearchError: AlgoliaSearchError,
  UnparsableJSON: createCustomError(
    'UnparsableJSON',
    'Could not parse the incoming response as JSON, see err.more for details'
  ),
  RequestTimeout: createCustomError(
    'RequestTimeout',
    'Request timedout before getting a response'
  ),
  Network: createCustomError(
    'Network',
    'Network issue, see err.more for details'
  ),
  JSONPScriptFail: createCustomError(
    'JSONPScriptFail',
    '<script> was loaded but did not call our provided callback'
  ),
  JSONPScriptError: createCustomError(
    'JSONPScriptError',
    '<script> unable to load due to an `error` event on it'
  ),
  Unknown: createCustomError(
    'Unknown',
    'Unknown error occured'
  )
};
<commit_msg>chore(dx): fix error message for timeouts<commit_after>'use strict';

// This file hosts our error definitions
// We use custom error "types" so that we can act on them when we need it
// e.g.: if error instanceof errors.UnparsableJSON then..

var inherits = require('inherits');

function AlgoliaSearchError(message, extraProperties) {
  var forEach = require('foreach');

  var error = this;

  // try to get a stacktrace
  if (typeof Error.captureStackTrace === 'function') {
    Error.captureStackTrace(this, this.constructor);
  } else {
    error.stack = (new Error()).stack || 'Cannot get a stacktrace, browser is too old';
  }

  this.name = 'AlgoliaSearchError';
  this.message = message || 'Unknown error';

  if (extraProperties) {
    forEach(extraProperties, function addToErrorObject(value, key) {
      error[key] = value;
    });
  }
}

inherits(AlgoliaSearchError, Error);

function createCustomError(name, message) {
  function AlgoliaSearchCustomError() {
    var args = Array.prototype.slice.call(arguments, 0);

    // custom message not set, use default
    if (typeof args[0] !== 'string') {
      args.unshift(message);
    }

    AlgoliaSearchError.apply(this, args);
    this.name = 'AlgoliaSearch' + name + 'Error';
  }

  inherits(AlgoliaSearchCustomError, AlgoliaSearchError);

  return AlgoliaSearchCustomError;
}

// late exports to let various fn defs and inherits take place
module.exports = {
  AlgoliaSearchError: AlgoliaSearchError,
  UnparsableJSON: createCustomError(
    'UnparsableJSON',
    'Could not parse the incoming response as JSON, see err.more for details'
  ),
  RequestTimeout: createCustomError(
    'RequestTimeout',
    'Request timed out before getting a response'
  ),
  Network: createCustomError(
    'Network',
    'Network issue, see err.more for details'
  ),
  JSONPScriptFail: createCustomError(
    'JSONPScriptFail',
    '<script> was loaded but did not call our provided callback'
  ),
  JSONPScriptError: createCustomError(
    'JSONPScriptError',
    '<script> unable to load due to an `error` event on it'
  ),
  Unknown: createCustomError(
    'Unknown',
    'Unknown error occured'
  )
};
<|endoftext|>


<commit_before>'use strict'

const Qs = require('qs')
const qsDefaultEncoder = require('qs/lib/utils').encode
const isNode = require('detect-node')
const ndjson = require('ndjson')
const pump = require('pump')
const once = require('once')
const getFilesStream = require('./get-files-stream')
const streamToValue = require('./stream-to-value')
const streamToJsonValue = require('./stream-to-json-value')
const request = require('./request')

// -- Internal

function parseError (res, cb) {
  const error = new Error(`Server responded with ${res.statusCode}`)

  streamToJsonValue(res, (err, payload) => {
    if (err) {
      return cb(err)
    }

    if (payload) {
      error.code = payload.Code
      error.message = payload.Message || payload.toString()
    }
    cb(error)
  })
}

function onRes (buffer, cb) {
  return (res) => {
    const stream = Boolean(res.headers['x-stream-output'])
    const chunkedObjects = Boolean(res.headers['x-chunked-output'])
    const isJson = res.headers['content-type'] &&
                   res.headers['content-type'].indexOf('application/json') === 0

    if (res.statusCode >= 400 || !res.statusCode) {
      return parseError(res, cb)
    }

    // Return the response stream directly
    if (stream && !buffer) {
      return cb(null, res)
    }

    // Return a stream of JSON objects
    if (chunkedObjects && isJson) {
      const outputStream = pump(res, ndjson.parse())
      return cb(null, outputStream)
    }

    // Return a JSON object
    if (isJson) {
      return streamToJsonValue(res, cb)
    }

    // Return a value
    return streamToValue(res, cb)
  }
}

function requestAPI (config, options, callback) {
  callback = once(callback)
  options.qs = options.qs || {}

  if (Array.isArray(options.files)) {
    options.qs.recursive = true
  }

  if (Array.isArray(options.path)) {
    options.path = options.path.join('/')
  }
  if (options.args && !Array.isArray(options.args)) {
    options.args = [options.args]
  }
  if (options.args) {
    options.qs.arg = options.args
  }
  if (options.files && !Array.isArray(options.files)) {
    options.files = [options.files]
  }

  if (options.qs.r) {
    options.qs.recursive = options.qs.r
    // From IPFS 0.4.0, it throws an error when both r and recursive are passed
    delete options.qs.r
  }

  options.qs['stream-channels'] = true

  let stream
  if (options.files) {
    stream = getFilesStream(options.files, options.qs)
  }

  // this option is only used internally, not passed to daemon
  delete options.qs.followSymlinks

  const method = 'POST'
  const headers = {}

  if (isNode) {
    // Browsers do not allow you to modify the user agent
    headers['User-Agent'] = config['user-agent']
  }

  if (options.files) {
    if (!stream.boundary) {
      return callback(new Error('No boundary in multipart stream'))
    }

    headers['Content-Type'] = `multipart/form-data; boundary=${stream.boundary}`
  }

  const qs = Qs.stringify(options.qs, {
    arrayFormat: 'repeat',
    encoder: data => {
      // TODO: future releases of qs will provide the default
      // encoder as a 2nd argument to this function; it will
      // no longer be necessary to import qsDefaultEncoder
      if (Buffer.isBuffer(data)) {
        let uriEncoded = ''
        for (const byte of data) {
          // https://tools.ietf.org/html/rfc3986#page-14
          // ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E)
          if (
            (byte >= 0x41 && byte <= 0x5A) ||
            (byte >= 0x61 && byte <= 0x7A) ||
            (byte >= 0x30 && byte <= 0x39) ||
            (byte === 0x2D) ||
            (byte === 0x2E) ||
            (byte === 0x5F) ||
            (byte === 0x7E)
          ) {
            uriEncoded += String.fromCharCode(byte)
          } else {
            const hex = byte.toString(16)
            // String.prototype.padStart() not widely supported yet
            const padded = hex.length === 1 ? `0${hex}` : hex
            uriEncoded += `%${padded}`
          }
        }
        return uriEncoded
      }
      return qsDefaultEncoder(data)
    }
  })
  const req = request(config.protocol)({
    hostname: config.host,
    path: `${config['api-path']}${options.path}?${qs}`,
    port: config.port,
    method: method,
    headers: headers
  }, onRes(options.buffer, callback))

  req.on('error', (err) => {
    callback(err)
  })

  if (options.files) {
    stream.pipe(req)
  } else {
    req.end()
  }

  return req
}

//
// -- Module Interface

exports = module.exports = (config) => {
  /*
   * options: {
   *   path:   // API path (like /add or /config) - type: string
   *   args:   // Arguments to the command - type: object
   *   qs:     // Opts as query string opts to the command --something - type: object
   *   files:  // files to be sent - type: string, buffer or array of strings or buffers
   *   buffer: // buffer the request before sending it - type: bool
   * }
   */
  const send = (options, callback) => {
    if (typeof options !== 'object') {
      return callback(new Error('no options were passed'))
    }

    return requestAPI(config, options, callback)
  }

  // Send a HTTP request and pass via a transform function
  // to convert the response data to wanted format before
  // returning it to the callback.
  // Eg. send.andTransform({}, (e) => JSON.parse(e), (err, res) => ...)
  send.andTransform = (options, transform, callback) => {
    return send(options, (err, res) => {
      if (err) {
        return callback(err)
      }
      transform(res, callback)
    })
  }

  return send
}
<commit_msg>fix: pass the config protocol to http requests (#609)<commit_after>'use strict'

const Qs = require('qs')
const qsDefaultEncoder = require('qs/lib/utils').encode
const isNode = require('detect-node')
const ndjson = require('ndjson')
const pump = require('pump')
const once = require('once')
const getFilesStream = require('./get-files-stream')
const streamToValue = require('./stream-to-value')
const streamToJsonValue = require('./stream-to-json-value')
const request = require('./request')

// -- Internal

function parseError (res, cb) {
  const error = new Error(`Server responded with ${res.statusCode}`)

  streamToJsonValue(res, (err, payload) => {
    if (err) {
      return cb(err)
    }

    if (payload) {
      error.code = payload.Code
      error.message = payload.Message || payload.toString()
    }
    cb(error)
  })
}

function onRes (buffer, cb) {
  return (res) => {
    const stream = Boolean(res.headers['x-stream-output'])
    const chunkedObjects = Boolean(res.headers['x-chunked-output'])
    const isJson = res.headers['content-type'] &&
                   res.headers['content-type'].indexOf('application/json') === 0

    if (res.statusCode >= 400 || !res.statusCode) {
      return parseError(res, cb)
    }

    // Return the response stream directly
    if (stream && !buffer) {
      return cb(null, res)
    }

    // Return a stream of JSON objects
    if (chunkedObjects && isJson) {
      const outputStream = pump(res, ndjson.parse())
      return cb(null, outputStream)
    }

    // Return a JSON object
    if (isJson) {
      return streamToJsonValue(res, cb)
    }

    // Return a value
    return streamToValue(res, cb)
  }
}

function requestAPI (config, options, callback) {
  callback = once(callback)
  options.qs = options.qs || {}

  if (Array.isArray(options.files)) {
    options.qs.recursive = true
  }

  if (Array.isArray(options.path)) {
    options.path = options.path.join('/')
  }
  if (options.args && !Array.isArray(options.args)) {
    options.args = [options.args]
  }
  if (options.args) {
    options.qs.arg = options.args
  }
  if (options.files && !Array.isArray(options.files)) {
    options.files = [options.files]
  }

  if (options.qs.r) {
    options.qs.recursive = options.qs.r
    // From IPFS 0.4.0, it throws an error when both r and recursive are passed
    delete options.qs.r
  }

  options.qs['stream-channels'] = true

  let stream
  if (options.files) {
    stream = getFilesStream(options.files, options.qs)
  }

  // this option is only used internally, not passed to daemon
  delete options.qs.followSymlinks

  const method = 'POST'
  const headers = {}

  if (isNode) {
    // Browsers do not allow you to modify the user agent
    headers['User-Agent'] = config['user-agent']
  }

  if (options.files) {
    if (!stream.boundary) {
      return callback(new Error('No boundary in multipart stream'))
    }

    headers['Content-Type'] = `multipart/form-data; boundary=${stream.boundary}`
  }

  const qs = Qs.stringify(options.qs, {
    arrayFormat: 'repeat',
    encoder: data => {
      // TODO: future releases of qs will provide the default
      // encoder as a 2nd argument to this function; it will
      // no longer be necessary to import qsDefaultEncoder
      if (Buffer.isBuffer(data)) {
        let uriEncoded = ''
        for (const byte of data) {
          // https://tools.ietf.org/html/rfc3986#page-14
          // ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E)
          if (
            (byte >= 0x41 && byte <= 0x5A) ||
            (byte >= 0x61 && byte <= 0x7A) ||
            (byte >= 0x30 && byte <= 0x39) ||
            (byte === 0x2D) ||
            (byte === 0x2E) ||
            (byte === 0x5F) ||
            (byte === 0x7E)
          ) {
            uriEncoded += String.fromCharCode(byte)
          } else {
            const hex = byte.toString(16)
            // String.prototype.padStart() not widely supported yet
            const padded = hex.length === 1 ? `0${hex}` : hex
            uriEncoded += `%${padded}`
          }
        }
        return uriEncoded
      }
      return qsDefaultEncoder(data)
    }
  })
  const req = request(config.protocol)({
    hostname: config.host,
    path: `${config['api-path']}${options.path}?${qs}`,
    port: config.port,
    method: method,
    headers: headers,
    protocol: `${config.protocol}:`
  }, onRes(options.buffer, callback))

  req.on('error', (err) => {
    callback(err)
  })

  if (options.files) {
    stream.pipe(req)
  } else {
    req.end()
  }

  return req
}

//
// -- Module Interface

exports = module.exports = (config) => {
  /*
   * options: {
   *   path:   // API path (like /add or /config) - type: string
   *   args:   // Arguments to the command - type: object
   *   qs:     // Opts as query string opts to the command --something - type: object
   *   files:  // files to be sent - type: string, buffer or array of strings or buffers
   *   buffer: // buffer the request before sending it - type: bool
   * }
   */
  const send = (options, callback) => {
    if (typeof options !== 'object') {
      return callback(new Error('no options were passed'))
    }

    return requestAPI(config, options, callback)
  }

  // Send a HTTP request and pass via a transform function
  // to convert the response data to wanted format before
  // returning it to the callback.
  // Eg. send.andTransform({}, (e) => JSON.parse(e), (err, res) => ...)
  send.andTransform = (options, transform, callback) => {
    return send(options, (err, res) => {
      if (err) {
        return callback(err)
      }
      transform(res, callback)
    })
  }

  return send
}
<|endoftext|>


<commit_before>import BaseRecipe from './baseRecipe'
import eslint from 'gulp-eslint'
import extend from 'extend'
//import jscs from 'gulp-jscs'
//import stylish from 'gulp-jscs-stylish'
import debug from 'gulp-debug'
import gulpif from 'gulp-if'
import Util from 'gulp-util'

let PluginError = Util.PluginError

export const Default = {
  debug: false,
  presetType: 'javascripts',
  task: {
    name: 'eslint'
  },
  watch: {
    glob: '**/*.js',
    options: {
      //cwd: ** resolved from preset **
    }
  },
  source: {
    glob: '**/*.js',
    options: {
      //cwd: ** resolved from preset **
    }
  },
  options: {}
}

const EsLint = class extends BaseRecipe {

  /**
   *
   * @param gulp - gulp instance
   * @param preset - base preset configuration - either one from presets.js or a custom hash
   * @param config - customized overrides for this recipe
   */
  constructor(gulp, preset, config = {}) {
    super(gulp, preset, extend(true, {}, Default, config))
  }

  run(watching = false) {
    // eslint() attaches the lint output to the "eslint" property of the file object so it can be used by other modules.
    let bundle = this.gulp.src(this.config.source.glob, this.config.source.options)
      .pipe(gulpif(this.config.debug, debug(this.debugOptions())))
      .pipe(eslint(this.config.options))
      .pipe(eslint.format()) // outputs the lint results to the console. Alternatively use eslint.formatEach() (see Docs).

      // this should emit the error, but we aren't notified
      .pipe(gulpif(!watching, eslint.failAfterError())) // To have the process exit with an error code (1) on lint error, return the stream and pipe to failAfterError last.

      // 1. HACK solution that works with first error, but is very ugly

      // make sure we are notified of any error (this really should be happening in eslint.failAfterError(), but not sure where it is lost)
      .pipe(eslint.result((results) => { // this is single file #result not #results, we don't get notified on #results
        let count = results.errorCount;
        if (count > 0) {
          throw new PluginError(
            'gulp-eslint',
            {
              message: 'Failed with' + (count === 1 ? ' error' : ' errors')
            }
          )
        }
      }))
      .on('error', (error) => {
        this.notifyError(error, watching)
      })

    // FIXME: even including any remnant of JSCS at this point broke everything through the unfound requirement of babel 5.x through babel-jscs.  I can't tell where this occurred, but omitting gulp-jscs for now gets me past this issue.  Revisit this when there are clear updates to use babel 6
    //.pipe(jscs())      // enforce style guide
    //.pipe(stylish())  // log style errors
    //.pipe(jscs.reporter('fail')) // fail on error

    return bundle
  }
}

export default EsLint
<commit_msg>committing all attempts at resolving https://github.com/adametry/gulp-eslint/issues/135#issuecomment-180595782<commit_after>import BaseRecipe from './baseRecipe'
import eslint from 'gulp-eslint'
import extend from 'extend'
//import jscs from 'gulp-jscs'
//import stylish from 'gulp-jscs-stylish'
import debug from 'gulp-debug'
import gulpif from 'gulp-if'
import Util from 'gulp-util'

let PluginError = Util.PluginError

export const Default = {
  debug: false,
  presetType: 'javascripts',
  task: {
    name: 'eslint'
  },
  watch: {
    glob: '**/*.js',
    options: {
      //cwd: ** resolved from preset **
    }
  },
  source: {
    glob: '**/*.js',
    options: {
      //cwd: ** resolved from preset **
    }
  },
  options: {}
}

const EsLint = class extends BaseRecipe {

  /**
   *
   * @param gulp - gulp instance
   * @param preset - base preset configuration - either one from presets.js or a custom hash
   * @param config - customized overrides for this recipe
   */
  constructor(gulp, preset, config = {}) {
    super(gulp, preset, extend(true, {}, Default, config))
  }

  run(watching = false) {
    // eslint() attaches the lint output to the "eslint" property of the file object so it can be used by other modules.
    let bundle = this.gulp.src(this.config.source.glob, this.config.source.options)
      .pipe(gulpif(this.config.debug, debug(this.debugOptions())))
      .pipe(eslint(this.config.options))
      .pipe(eslint.format()) // outputs the lint results to the console. Alternatively use eslint.formatEach() (see Docs).

      //1. HACK solution that works with first error, but is very ugly
      // this should emit the error, but we aren't notified
      .pipe(gulpif(!watching, eslint.failAfterError())) // To have the process exit with an error code (1) on lint error, return the stream and pipe to failAfterError last.

      // make sure we are notified of any error (this really should be happening in eslint.failAfterError(), but not sure where it is lost)
      .pipe(eslint.result((results) => { // this is single file #result not #results, we don't get notified on #results
        let count = results.errorCount;
        if (count > 0) {
          throw new PluginError(
            'gulp-eslint',
            {
              message: 'Failed with' + (count === 1 ? ' error' : ' errors')
            }
          )
        }
      }))
      .on('error', (error) => {
        this.notifyError(error, watching)
      })

      // 2. Attempt now that returns are in place with the gulpif
      // this should emit the error, but we aren't notified
      //.pipe(gulpif(!watching, eslint.failAfterError())) // To have the process exit with an error code (1) on lint error, return the stream and pipe to failAfterError last.
      //.on('error', (error) => {
      //  this.notifyError(error, watching)
      //})

      //// 3. Attempt now that returns are in place WITHOUT gulpif
      //// this should emit the error, but we aren't notified
      //.pipe( eslint.failAfterError()) // To have the process exit with an error code (1) on lint error, return the stream and pipe to failAfterError last.
      //.on('error', (error) => {
      //  this.notifyError(error, watching)
      //})

      // 4. https://github.com/adametry/gulp-eslint/issues/135#issuecomment-180555978
      //.pipe(eslint.results(function (results) {
      //  var count = results.errorCount;
      //  console.log('Total ESLint Error Count: ' + count);
      //  if (count > 0) {
      //    throw new Error('Failed with Errors');
      //  }
      //}))
      //.on('error', function (error) {
      //  console.log('Total ESLint Error Count: ' + error);
      //})
      //.on('finish', function () {
      //  console.log('eslint.results finished');
      //})
      //.on('end', function () {
      //  console.log('eslint.results ended');
      //})

      //// 5. notification is emitted
      //.pipe(eslint.results(function (results) {
      //  var count = results.errorCount;
      //  console.log('*****Error Count: ' + count);
      //  if (count > 0) {
      //    throw new Error('******My custom error');
      //  }
      //}))
      //.on('error', (error) => {
      //  this.notifyError(error, watching)
      //})

      //// 6. notification is emitted
      //.pipe(eslint.results(function (results) {
      //  var count = results.errorCount;
      //  console.log('*****Error Count: ' + count);
      //  if (count > 0) {
      //    throw new PluginError('******My custom error');
      //  }
      //}))
      //.on('error', (error) => {
      //  this.notifyError(error, watching)
      //})

      //// 7. notification is emitted, except when watching
      //.pipe(eslint.results(function (results) {
      //  let count = results.errorCount;
      //  console.error('****************in results handler')
      //  if (count > 0) {
      //    throw new PluginError('gulp-eslint', { message: 'Failed with ' + count + (count === 1 ? ' error' : ' errors') })
      //  }
      //}))
      //.on('error', (error) => {
      //  console.error('****************in error handler')
      //  this.notifyError(error, watching)
      //})

      //.pipe( eslint.failAfterError())
      //.on('error', (error) => {
      //  this.notifyError(error, watching)
      //})

    // FIXME: even including any remnant of JSCS at this point broke everything through the unfound requirement of babel 5.x through babel-jscs.  I can't tell where this occurred, but omitting gulp-jscs for now gets me past this issue.  Revisit this when there are clear updates to use babel 6
    //.pipe(jscs())      // enforce style guide
    //.pipe(stylish())  // log style errors
    //.pipe(jscs.reporter('fail')) // fail on error

    return bundle
  }
}

export default EsLint
<|endoftext|>


<commit_before>/*#ifndef(UMD)*/
"use strict";
/*#endif*/

var
    /**
     * GPF Event class
     *
     * @param {String} type
     * @param {Object} [params={}] params
     * @param {Boolean} [cancelable=false] cancelable
     * @param {Object} [scope=undefined] scope
     * @constructor
     * @class _Event
     * @alias gpf.events.Event
     */
    _Event = function (type, params, cancelable, scope) {
        gpf.setReadOnlyProperty(this, "type", type);
        if (undefined !== params) {
            this._params = params;
        }
        if (cancelable) {
            this._cancelable = true;
        }
//            this._timeStamp = new Date();
//            this._returnValue = undefined;
        if (scope) {
            this._scope = scope;
        }
    },

    /**
     * Count the number of gpf.events.fire calls
     *
     * @type {number}
     * @private
     */
    _firing = 0,

    /**
     * Fire the event onto the eventsHandler
     *
     * @param {gpf.events.Event} event event object to fire
     * @param {Object} scope scope of the event
     * @param {gpf.events.Handler} eventsHandler
     */
    _fire = function (event, scope, eventsHandler) {
        var eventHandler,
            overriddenScope;
        gpf.ASSERT(eventsHandler, "Expected eventsHandler");

        // Event dispatcher expected interface
        if (eventsHandler._dispatchEvent) {
            eventsHandler._dispatchEvent(event);

        // Basic function handler
        } else if ("function" === typeof eventsHandler
            || eventsHandler instanceof gpf.Callback) {
            // Compatible with Function & gpf.Callback
            eventsHandler.apply(scope, [event]);

        // Composite with a specific event handler
        } else {
            eventHandler = eventsHandler[event.type()];
            if (undefined === eventHandler) {
                // Try with a default handler
                eventHandler = eventsHandler["*"];
            }
            if (undefined !== eventHandler) {
                overriddenScope = eventsHandler.scope;
                if (undefined !== overriddenScope) {
                    scope = overriddenScope;
                }
                eventHandler.apply(scope, [event]);
            }
        }
    };

// _Event interface
gpf.extend(_Event.prototype, {

    /**
     * Event type
     *
     * @type {String}
     * @read-only
     */
    type: "",

    /**
     * Event parameters
     *
     * @type {Object} Map of key to value
     * @private
     */
    _params: {},

    /**
     * Event can be cancelled
     *
     * @type {Boolean}
     * @private
     */
    _cancelable: false,

    /**
     * Event propagation was stopped
     *
     * @type {Boolean}
     * @private
     */
    _propagationStopped: false,

    /**
     * Event default handling is prevented
     *
     * @type {Boolean}
     * @private
     */
    _defaultPrevented: false,

    /**
     * Event scope
     *
     * @type {Object|null}
     * @private
     */
    _scope: null,

    /**
     * Event scope
     *
     * @return {Object}
     */
    scope: function () {
        return gpf.Callback.resolveScope(this._scope);
    },

    /**
     * Event can be cancelled
     *
     * @return {Boolean}
     */
    cancelable: function () {
        return this._cancelable;
    },

    /**
     * Cancel the event if it is cancelable, meaning that any default
     * action normally taken by the implementation as a result of the event
     * will not occur
     */
    preventDefault: function () {
        this._defaultPrevented = true;
    },

    /**
     * Returns true if preventDefault has been called at least once
     *
     * @return {Boolean}
     */
    defaultPrevented: function () {
        return this._defaultPrevented;
    },

    /**
     * To prevent further propagation of an event during event flow
     */
    stopPropagation: function () {
        this._propagationStopped = true;
    },

    /**
     * Get any additional event information
     *
     * @param {String} name parameter name
     * @return {*} value of parameter
     */
    get: function (name) {
        return this._params[name];
    },

    /**
     * Fire the event on the provided eventsHandler
     *
     * @param {gpf.events.Broadcaster/gpf.Callback/Function} eventsHandler
     * @return {gpf.events.Event} this
     */
    fire: function (eventsHandler) {
        return gpf.events.fire(this, eventsHandler);
    }

});

gpf.events = {

    Event: _Event,

    /**
     * Event Handler,
     * - gpf.events.Broadcaster: broadcastEvent(event)
     * - gpf.Callback|Function: apply(scope, [event])
     * - Object: consider a map between event type and callback function
     * @type {gpf.events.Target|gpf.Callback|Function|Object}
     * @alias {gpf.events.Handler}
     */

    /**
     * If necessary, build an event object and use the provided media
     * (broadcaster or callback function) to throw it.
     *
     * NOTE: this is transmitted through the call
     *
     * @param {String/gpf.events.Event} event string or event object to fire
     * @param {Object} [params={}] params parameter of the event
     *                 (when type is a string)
     * @param {gpf.events.Handler} eventsHandler
     * @return {gpf.events.Event} the event object
     */
    fire: function (event, params, eventsHandler) {
        var scope;
        if (undefined === eventsHandler) {
            // no last param: shift parameters
            eventsHandler = params;
            params = undefined;
        }
        if (!(event instanceof Event)) {
            event = new gpf.events.Event(event, params, true, this);
        }
        scope = gpf.Callback.resolveScope(this);
        /**
         * This is used both to limit the number of recursion and increase
         * the efficiency of the algorithm.
         */
        if (++_firing > 10) {
            // Too much recursion
            gpf.defer(_fire,  0, null, [event, scope, eventsHandler]);
        } else {
            _fire(event, scope, eventsHandler);
        }
        --_firing;
        return event;
    }
};<commit_msg>gpf.events.Event (WIP)<commit_after>/*#ifndef(UMD)*/
"use strict";
/*#endif*/

var
    /**
     * GPF Event class
     *
     * @param {String} type
     * @param {Object} [params={}] params
     * @param {Boolean} [cancelable=false] cancelable
     * @param {Object} [scope=undefined] scope
     * @constructor
     * @class _Event
     * @alias gpf.events.Event
     */
    _Event = function (type, params, scope) {
        gpf.setReadOnlyProperty(this, "type", type);
        if (undefined !== params) {
            this._params = params;
        }
        if (scope) {
            this._scope = scope;
        }
    },

    /**
     * Count the number of gpf.events.fire calls
     *
     * @type {number}
     * @private
     */
    _firing = 0,

    /**
     * Fire the event onto the eventsHandler
     *
     * @param {gpf.events.Event} event event object to fire
     * @param {Object} scope scope of the event
     * @param {gpf.events.Handler} eventsHandler
     */
    _fire = function (event, scope, eventsHandler) {
        var eventHandler,
            overriddenScope;
        gpf.ASSERT(eventsHandler, "Expected eventsHandler");

        // Event dispatcher expected interface
        if (eventsHandler._dispatchEvent) {
            eventsHandler._dispatchEvent(event);

        // Basic function handler
        } else if ("function" === typeof eventsHandler
            || eventsHandler instanceof gpf.Callback) {
            // Compatible with Function & gpf.Callback
            eventsHandler.apply(scope, [event]);

        // Composite with a specific event handler
        } else {
            eventHandler = eventsHandler[event.type()];
            if (undefined === eventHandler) {
                // Try with a default handler
                eventHandler = eventsHandler["*"];
            }
            if (undefined !== eventHandler) {
                overriddenScope = eventsHandler.scope;
                if (undefined !== overriddenScope) {
                    scope = overriddenScope;
                }
                eventHandler.apply(scope, [event]);
            }
        }
    },

    /**
     * Check parameters array and re-assign default values considering that:
     * the eventsHandler parameter is *always* the last one provided
     * all other parameters are optional and can be defaulted provided the
     * defaultArgs array
     *
     * Sample usage:
     *
     *  function fire (event, params, synchronous, eventsHandler) {
     *      _gpfLookForEventsHandler(arguments, ['', {}, false]);
     *
     *
     * @param {arguments} thatArgs Function arguments
     * @param {Array} defaultArgs List of default values for all expected
     * arguments *but* the eventsHandler
     * @private
     */
    _gpfLookForEventsHandler = function (thatArgs, defaultArgs) {
        var
            expectedLen = defaultArgs.length + 1,
            argsLen = thatArgs.lenth,
            argIdx;
        if (argsLen.length !== expectedLen) {
            argIdx = argsLen - 1;
            // The last argument is *always* the eventsHandler
            thatArgs[expectedLen - 1] = thatArgs[argIdx];
            // Then apply missing defaults
            while (argIdx ) {
            }
        }
    };

// _Event interface
gpf.extend(_Event.prototype, {

    /**
     * Event type
     *
     * @type {String}
     * @read-only
     */
    type: "",

    /**
     * Event parameters
     *
     * @type {Object} Map of key to value
     * @private
     */
    _params: {},

    /**
     * Event propagation was stopped
     *
     * @type {Boolean}
     * @private
     */
    _propagationStopped: false,

    /**
     * Event default handling is prevented
     *
     * @type {Boolean}
     * @private
     */
    _defaultPrevented: false,

    /**
     * Event scope
     *
     * @type {Object|null}
     * @private
     */
    _scope: null,

    /**
     * Event scope
     *
     * @return {Object}
     */
    scope: function () {
        return gpf.Callback.resolveScope(this._scope);
    },

    /**
     * Cancel the event if it is cancelable, meaning that any default
     * action normally taken by the implementation as a result of the event
     * will not occur
     */
    preventDefault: function () {
        this._defaultPrevented = true;
    },

    /**
     * Returns true if preventDefault has been called at least once
     *
     * @return {Boolean}
     */
    defaultPrevented: function () {
        return this._defaultPrevented;
    },

    /**
     * To prevent further propagation of an event during event flow
     */
    stopPropagation: function () {
        this._propagationStopped = true;
    },

    /**
     * Get any additional event information
     *
     * @param {String} name parameter name
     * @return {*} value of parameter
     */
    get: function (name) {
        return this._params[name];
    },

    /**
     * Fire the event on the provided eventsHandler
     *
     * @param {gpf.events.Broadcaster/gpf.Callback/Function} eventsHandler
     * @return {gpf.events.Event} this
     */
    fire: function (eventsHandler) {
        return gpf.events.fire(this, eventsHandler);
    }

});

gpf.events = {

    Event: _Event,

    /**
     * Event Handler,
     * - gpf.events.Broadcaster: broadcastEvent(event)
     * - gpf.Callback|Function: apply(scope, [event])
     * - Object: consider a map between event type and callback function
     * @type {gpf.events.Target|gpf.Callback|Function|Object}
     * @alias {gpf.events.Handler}
     */

    /**
     * If necessary, build an event object and use the provided media
     * (broadcaster or callback function) to throw it.
     *
     * NOTE: this is transmitted through the call
     *
     * @param {String/gpf.events.Event} event string or event object to fire
     * @param {Object} [params={}] params parameter of the event
     *                 (when type is a string)
     * @param {gpf.events.Handler} eventsHandler
     * @return {gpf.events.Event} the event object
     */
    fire: function (event, params, eventsHandler) {
        var scope;
        _gpfLookForEventsHandler(arguments, [0, {}]);
        if (!(event instanceof _Event)) {
            event = new gpf.events.Event(event, params, true, this);
        }
        scope = gpf.Callback.resolveScope(this);
        /**
         * This is used both to limit the number of recursion and increase
         * the efficiency of the algorithm.
         */
        if (++_firing > 10) {
            // Too much recursion
            gpf.defer(_fire,  0, null, [event, scope, eventsHandler]);
        } else {
            _fire(event, scope, eventsHandler);
        }
        --_firing;
        return event;
    }
};<|endoftext|>


<commit_before>import {empty} from 'most'
import fromEvent from './fromEvent'
import {makeIsStrictlyInRootScope} from './select'

let matchesSelector
try {
  matchesSelector = require(`matches-selector`)
} catch (err) {
  matchesSelector = () => {}
}

function makeEventsSelector(element$, selector) {
  return function eventsSelector(type, useCapture = false) {
    if (typeof type !== `string`) {
      throw new Error(`DOM drivers events() expects argument to be a ` +
        `string representing the event type to listen for.`)
    }
    return element$
      .map(elements => {
        if (!elements) {
          return empty()
        }

        if (matchesSelector(elements, selector.join(` `))) {
          return fromEvent(type, elements, useCapture)
        }

        return fromEvent(type, elements, useCapture)
          .filter(ev => {
            if (matchesSelector(ev.srcElement, selector.join(` `)) ||
              matchesSelector(ev.srcElement, selector.join(``)))
            {
              return makeIsStrictlyInRootScope(selector)(ev.srcElement)
            }
            return false
          })
      })
      .switch()
      .multicast()
  }
}

export default makeEventsSelector
<commit_msg>feat(events): avoid recreating the same eventListener<commit_after>import {empty} from 'most'
import fromEvent from './fromEvent'
import {makeIsStrictlyInRootScope} from './select'

let matchesSelector
try {
  matchesSelector = require(`matches-selector`)
} catch (err) {
  matchesSelector = () => {}
}

function makeEventsSelector(element$, selector) {
  return function eventsSelector(type, useCapture = false) {
    if (typeof type !== `string`) {
      throw new Error(`DOM drivers events() expects argument to be a ` +
        `string representing the event type to listen for.`)
    }
    return element$
      .map(element => {
        return {element, selector}
      })
      .skipRepeatsWith((prev, curr) => {
        return prev.selector.join(``) === curr.selector.join(``)
      })
      .map(({element}) => element)
      .map(elements => {
        if (!elements) {
          return empty()
        }

        if (matchesSelector(elements, selector.join(` `))) {
          return fromEvent(type, elements, useCapture)
        }

        return fromEvent(type, elements, useCapture)
          .filter(ev => {
            if (matchesSelector(ev.srcElement, selector.join(` `)) ||
              matchesSelector(ev.srcElement, selector.join(``)))
            {
              return makeIsStrictlyInRootScope(selector)(ev.srcElement)
            }
            return false
          })
      })
      .switch()
      .multicast()
  }
}

export default makeEventsSelector
<|endoftext|>


<commit_before>var http = require('http'),
  request = require('request'),
  _ = require('underscore')._,
  querystring = require('querystring');

function EchoNestAPI_v4(apiKey, options) {
  this.version = '4';
  this.apiKey = apiKey;
  this.apiUrl = 'http://developer.echonest.com/api/v4/'
}

module.exports = EchoNestAPI_v4;

EchoNestAPI_v4.prototype.howdy = function() {
  return "Howdy!";
};

EchoNestAPI_v4.prototype.execute = function(type, method, availableParams, givenParams, callback) {
  var finalParams = { api_key : this.apiKey, format : 'json' };

  for (var i = 0; i < availableParams.length; i++) {
    currentParam = availableParams[i];
    if (typeof givenParams[currentParam] !== 'undefined')
      finalParams[currentParam] = givenParams[currentParam];
  }
  var uri = this.apiUrl + type + '/' + method + '?' + querystring.stringify(finalParams);
  request(uri, function (error, response, body) {
    var parsedResponse;
    if (error) {
      callback({
        error : 'Unable to connect to the Echo Nest API endpoint.',
        code : 'xxx'
      });
    } else {
      try {
        parsedResponse = JSON.parse(body);
      } catch (error) {
        callback({ error : 'Error parsing JSON answer from the Echo Nest API.', code : 'xxx'});
      }
      callback(parsedResponse);
    }
  });
};<commit_msg>if the Echo Nest API gives you a non-200 HTTP status, error.<commit_after>var http = require('http'),
  request = require('request'),
  _ = require('underscore')._,
  querystring = require('querystring');

function EchoNestAPI_v4(apiKey, options) {
  this.version = '4';
  this.apiKey = apiKey;
  this.apiUrl = 'http://developer.echonest.com/api/v4/'
}

module.exports = EchoNestAPI_v4;

EchoNestAPI_v4.prototype.howdy = function() {
  return "Howdy!";
};

EchoNestAPI_v4.prototype.execute = function(type, method, availableParams, givenParams, callback) {
  var finalParams = { api_key : this.apiKey, format : 'json' };

  for (var i = 0; i < availableParams.length; i++) {
    currentParam = availableParams[i];
    if (typeof givenParams[currentParam] !== 'undefined')
      finalParams[currentParam] = givenParams[currentParam];
  }
  var uri = this.apiUrl + type + '/' + method + '?' + querystring.stringify(finalParams);
  request(uri, function (error, response, body) {
    var parsedResponse;
    if (error || response.statusCode != 200 ) {
      callback({
        error : 'Unable to connect to the Echo Nest API endpoint.',
        code : response.statusCode
      });
    } else {
      try {
        parsedResponse = JSON.parse(body);
      } catch (error) {
        callback({ error : 'Error parsing JSON answer from the Echo Nest API.', code : 'xxx'});
      }
      callback(parsedResponse);
    }
  });
};<|endoftext|>


<commit_before>import invariant from 'invariant';

export default async (patterns) => {
	invariant(
		Array.isArray(patterns),
		'Argument must be of type Array. Instead got "%s"',
		typeof patterns
	);
};
<commit_msg>feat(parse-patterns): no-op if input is empty array<commit_after>import invariant from 'invariant';

export default async (patterns) => {
	invariant(
		Array.isArray(patterns),
		'Argument must be of type Array. Instead got "%s"',
		typeof patterns
	);

	return [];
};
<|endoftext|>