<commit_before>var Events = require('./Events');
var Viewport = require('./viewport/index.js');
var ComponentLoader = require('./componentloader.js');
var ShaderLoader = require('./shaderloader.js');

function Editor () {
  this.enabled = false;
  // Detect if the scene is already loaded
  if (document.readyState === 'complete' || document.readyState === 'loaded') {
    this.onDomLoaded();
  } else {
    document.addEventListener('DOMContentLoaded', this.onDomLoaded.bind(this));
  }
}

Editor.prototype = {
  /**
   * Callback once the DOM is completely loaded so we could query the scene
   */
  onDomLoaded: function () {
    this.componentLoader = new ComponentLoader();
    this.shaderLoader = new ShaderLoader();

    this.sceneEl = document.querySelector('a-scene');
    if (this.sceneEl.hasLoaded) {
      this.onSceneLoaded();
    } else {
      this.sceneEl.addEventListener('loaded', this.onSceneLoaded.bind(this));
    }
  },

  onSceneLoaded: function () {
    this.container = document.querySelector('.a-canvas');
    this.currentCameraEl = document.querySelector('[camera]');

    this.editorCameraEl = document.createElement('a-entity');
    this.editorCameraEl.isEditor = true;
    this.editorCameraEl.addEventListener('loaded', function (entity) {
      this.DEFAULT_CAMERA = this.editorCameraEl.getObject3D('camera');
      this.initUI();
    }.bind(this));
    this.editorCameraEl.setAttribute('camera', {far: 10000, fov: 50, near: 1, active: true});
    document.querySelector('a-scene').appendChild(this.editorCameraEl);
  },

  initUI: function () {
    this.DEFAULT_CAMERA.position.set(20, 10, 20);
    this.DEFAULT_CAMERA.lookAt(new THREE.Vector3());
    this.DEFAULT_CAMERA.updateMatrixWorld();

    this.camera = this.DEFAULT_CAMERA;

    this.initEvents();

    this.selected = null;

    window.dispatchEvent(new Event('editor-loaded'));

    this.scene = this.sceneEl.object3D;
    this.helpers = {};
    this.sceneHelpers = new THREE.Scene();
    this.sceneHelpers.visible = true; // false;
    this.editorActive = false;

    this.viewport = new Viewport(this);
    Events.emit('windowResize');

    var scope = this;

    function addObjects (object) {
      for (var i = 0; i < object.children.length; i++) {
        var obj = object.children[i];
        for (var j = 0; j < obj.children.length; j++) {
          scope.addObject(obj.children[j]);
        }
      }
    }
    addObjects(this.sceneEl.object3D);

    document.addEventListener('model-loaded', function (event) {
      this.addObject(event.target.object3D);
    }.bind(this));

    document.addEventListener('componentchanged', function (event) {
      this.addObject(event.target.object3D);
    }.bind(this));

    this.scene.add(this.sceneHelpers);

    this.enable();
  },
/*
  removeObject: function (object) {
    if (object.parent === null) return; // avoid deleting the camera or scene

    var scope = this;

    object.traverse(function (child) {
      scope.removeHelper(child);
    });

    object.parent.remove(object);

    Events.emit('objectRemoved', object);
    Events.emit('sceneGraphChanged');
  },
*/
  addHelper: (function () {
    var geometry = new THREE.SphereBufferGeometry(2, 4, 2);
    var material = new THREE.MeshBasicMaterial({ color: 0xff0000, visible: false });

    return function (object) {
      var helper;
      if (object instanceof THREE.Camera) {
        helper = new THREE.CameraHelper(object, 1);
      } else if (object instanceof THREE.PointLight) {
        helper = new THREE.PointLightHelper(object, 1);
      } else if (object instanceof THREE.DirectionalLight) {
        helper = new THREE.DirectionalLightHelper(object, 1);
      } else if (object instanceof THREE.SpotLight) {
        helper = new THREE.SpotLightHelper(object, 1);
      } else if (object instanceof THREE.HemisphereLight) {
        helper = new THREE.HemisphereLightHelper(object, 1);
      } else if (object instanceof THREE.SkinnedMesh) {
        helper = new THREE.SkeletonHelper(object);
      } else {
        // no helper for this object type
        return;
      }

      var picker = new THREE.Mesh(geometry, material);
      picker.name = 'picker';
      picker.userData.object = object;
      helper.add(picker);

      this.sceneHelpers.add(helper);
      this.helpers[ object.id ] = helper;

      Events.emit('helperAdded', helper);
    };
  })(),

  removeHelper: function (object) {
    if (this.helpers[ object.id ] !== undefined) {
      var helper = this.helpers[ object.id ];
      helper.parent.remove(helper);

      delete this.helpers[ object.id ];

      Events.emit('helperRemoved', helper);
    }
  },

  selectEntity: function (entity, emit) {
    this.selectedEntity = entity;
    if (entity) {
      this.select(entity.object3D);
    } else {
      this.select(null);
    }

    if (emit === undefined) {
      Events.emit('entitySelected', entity);
    }
  },
  initEvents: function () {
    Events.on('entitySelected', function (entity) {
      this.selectEntity(entity, false);
    }.bind(this));

    Events.on('editorModeChanged', function (active) {
      this.editorActive = active;
      this.sceneHelpers.visible = this.editorActive;
    }.bind(this));

    Events.on('createNewEntity', function (definition) {
      this.createNewEntity(definition);
    }.bind(this));

/*
    window.addEventListener('resize', Events.emit('windowResize'), false);

    Events.emit('showModal');//.add(function (content) {
      this.panels.modal.show(content);
    }.bind(this));
    Events.emit('hideModal');//.add(function () {
      this.panels.modal.hide();
    }.bind(this));

    var entities = document.querySelectorAll('a-entity');
    for (var i = 0; i < entities.length; ++i) {
      var entity = entities[i];
      entity.addEventListener('componentchanged',
        function (evt) {
          if (this.selected && evt.srcElement === this.selected.el) {
            aframeEditor.editor.emit('componentChanged',evt);
          }
        }.bind(this));
    }
*/
  },
  selectById: function (id) {
    if (id === this.camera.id) {
      this.select(this.camera);
      return;
    }
    this.select(this.scene.getObjectById(id, true));
  },

  // Change to select object
  select: function (object) {
    if (this.selected === object) {
      return;
    }

    this.selected = object;
    Events.emit('objectSelected', object);
  },

  deselect: function () {
    this.select(null);
  },

  clear: function () {
    this.camera.copy(this.DEFAULT_CAMERA);
    this.deselect();
    document.querySelector('a-scene').innerHTML = '';
    Events.emit('editorCleared');
  },
  /**
   * Helper function to add a new entity with a list of components
   * @param  {object} definition Entity definition to add:
   *                             {element: 'a-entity', components: {geometry: 'primitive:box'}}
   * @return {Element}            Entity created
   */
  createNewEntity: function (definition) {
    var entity = document.createElement(definition.element);

    // load default attributes
    for (var attr in definition.components) {
      entity.setAttribute(attr, definition.components[attr]);
    }

    // Ensure the components are loaded before update the UI
    entity.addEventListener('loaded', function () {
      this.addEntity(entity);
    }.bind(this));

    this.sceneEl.appendChild(entity);

    return entity;
  },
  addEntity: function (entity) {
    this.addObject(entity.object3D);
    this.selectEntity(entity);
  },

  open: function () {
//    this.panels.sidebar.show();
//    this.panels.menubar.show();
    this.enabled = true;
    Events.emit('editorModeChanged', true);
    this.sceneEl.pause();
  },

  close: function () {
//    this.panels.sidebar.hide();
//    this.panels.menubar.hide();
    this.enabled = false;
    Events.emit('editorModeChanged', false);
    this.sceneEl.play();
  // @todo Removelisteners
  },

  addObject: function (object) {
    var scope = this;
    object.traverse(function (child) {
      if (!child.el || !child.el.isEditor) {
        scope.addHelper(child);
      }
    });

    Events.emit('objectAdded', object);
    Events.emit('sceneGraphChanged');
  }
};

module.exports = Editor;
<commit_msg>Fixes an uncaught s/enable/open in the PR #238<commit_after>var Events = require('./Events');
var Viewport = require('./viewport/index.js');
var ComponentLoader = require('./componentloader.js');
var ShaderLoader = require('./shaderloader.js');

function Editor () {
  this.enabled = false;
  // Detect if the scene is already loaded
  if (document.readyState === 'complete' || document.readyState === 'loaded') {
    this.onDomLoaded();
  } else {
    document.addEventListener('DOMContentLoaded', this.onDomLoaded.bind(this));
  }
}

Editor.prototype = {
  /**
   * Callback once the DOM is completely loaded so we could query the scene
   */
  onDomLoaded: function () {
    this.componentLoader = new ComponentLoader();
    this.shaderLoader = new ShaderLoader();

    this.sceneEl = document.querySelector('a-scene');
    if (this.sceneEl.hasLoaded) {
      this.onSceneLoaded();
    } else {
      this.sceneEl.addEventListener('loaded', this.onSceneLoaded.bind(this));
    }
  },

  onSceneLoaded: function () {
    this.container = document.querySelector('.a-canvas');
    this.currentCameraEl = document.querySelector('[camera]');

    this.editorCameraEl = document.createElement('a-entity');
    this.editorCameraEl.isEditor = true;
    this.editorCameraEl.addEventListener('loaded', function (entity) {
      this.DEFAULT_CAMERA = this.editorCameraEl.getObject3D('camera');
      this.initUI();
    }.bind(this));
    this.editorCameraEl.setAttribute('camera', {far: 10000, fov: 50, near: 1, active: true});
    document.querySelector('a-scene').appendChild(this.editorCameraEl);
  },

  initUI: function () {
    this.DEFAULT_CAMERA.position.set(20, 10, 20);
    this.DEFAULT_CAMERA.lookAt(new THREE.Vector3());
    this.DEFAULT_CAMERA.updateMatrixWorld();

    this.camera = this.DEFAULT_CAMERA;

    this.initEvents();

    this.selected = null;

    window.dispatchEvent(new Event('editor-loaded'));

    this.scene = this.sceneEl.object3D;
    this.helpers = {};
    this.sceneHelpers = new THREE.Scene();
    this.sceneHelpers.visible = true; // false;
    this.editorActive = false;

    this.viewport = new Viewport(this);
    Events.emit('windowResize');

    var scope = this;

    function addObjects (object) {
      for (var i = 0; i < object.children.length; i++) {
        var obj = object.children[i];
        for (var j = 0; j < obj.children.length; j++) {
          scope.addObject(obj.children[j]);
        }
      }
    }
    addObjects(this.sceneEl.object3D);

    document.addEventListener('model-loaded', function (event) {
      this.addObject(event.target.object3D);
    }.bind(this));

    document.addEventListener('componentchanged', function (event) {
      this.addObject(event.target.object3D);
    }.bind(this));

    this.scene.add(this.sceneHelpers);

    this.open();
  },
/*
  removeObject: function (object) {
    if (object.parent === null) return; // avoid deleting the camera or scene

    var scope = this;

    object.traverse(function (child) {
      scope.removeHelper(child);
    });

    object.parent.remove(object);

    Events.emit('objectRemoved', object);
    Events.emit('sceneGraphChanged');
  },
*/
  addHelper: (function () {
    var geometry = new THREE.SphereBufferGeometry(2, 4, 2);
    var material = new THREE.MeshBasicMaterial({ color: 0xff0000, visible: false });

    return function (object) {
      var helper;
      if (object instanceof THREE.Camera) {
        helper = new THREE.CameraHelper(object, 1);
      } else if (object instanceof THREE.PointLight) {
        helper = new THREE.PointLightHelper(object, 1);
      } else if (object instanceof THREE.DirectionalLight) {
        helper = new THREE.DirectionalLightHelper(object, 1);
      } else if (object instanceof THREE.SpotLight) {
        helper = new THREE.SpotLightHelper(object, 1);
      } else if (object instanceof THREE.HemisphereLight) {
        helper = new THREE.HemisphereLightHelper(object, 1);
      } else if (object instanceof THREE.SkinnedMesh) {
        helper = new THREE.SkeletonHelper(object);
      } else {
        // no helper for this object type
        return;
      }

      var picker = new THREE.Mesh(geometry, material);
      picker.name = 'picker';
      picker.userData.object = object;
      helper.add(picker);

      this.sceneHelpers.add(helper);
      this.helpers[ object.id ] = helper;

      Events.emit('helperAdded', helper);
    };
  })(),

  removeHelper: function (object) {
    if (this.helpers[ object.id ] !== undefined) {
      var helper = this.helpers[ object.id ];
      helper.parent.remove(helper);

      delete this.helpers[ object.id ];

      Events.emit('helperRemoved', helper);
    }
  },

  selectEntity: function (entity, emit) {
    this.selectedEntity = entity;
    if (entity) {
      this.select(entity.object3D);
    } else {
      this.select(null);
    }

    if (emit === undefined) {
      Events.emit('entitySelected', entity);
    }
  },
  initEvents: function () {
    Events.on('entitySelected', function (entity) {
      this.selectEntity(entity, false);
    }.bind(this));

    Events.on('editorModeChanged', function (active) {
      this.editorActive = active;
      this.sceneHelpers.visible = this.editorActive;
    }.bind(this));

    Events.on('createNewEntity', function (definition) {
      this.createNewEntity(definition);
    }.bind(this));

/*
    window.addEventListener('resize', Events.emit('windowResize'), false);

    Events.emit('showModal');//.add(function (content) {
      this.panels.modal.show(content);
    }.bind(this));
    Events.emit('hideModal');//.add(function () {
      this.panels.modal.hide();
    }.bind(this));

    var entities = document.querySelectorAll('a-entity');
    for (var i = 0; i < entities.length; ++i) {
      var entity = entities[i];
      entity.addEventListener('componentchanged',
        function (evt) {
          if (this.selected && evt.srcElement === this.selected.el) {
            aframeEditor.editor.emit('componentChanged',evt);
          }
        }.bind(this));
    }
*/
  },
  selectById: function (id) {
    if (id === this.camera.id) {
      this.select(this.camera);
      return;
    }
    this.select(this.scene.getObjectById(id, true));
  },

  // Change to select object
  select: function (object) {
    if (this.selected === object) {
      return;
    }

    this.selected = object;
    Events.emit('objectSelected', object);
  },

  deselect: function () {
    this.select(null);
  },

  clear: function () {
    this.camera.copy(this.DEFAULT_CAMERA);
    this.deselect();
    document.querySelector('a-scene').innerHTML = '';
    Events.emit('editorCleared');
  },
  /**
   * Helper function to add a new entity with a list of components
   * @param  {object} definition Entity definition to add:
   *                             {element: 'a-entity', components: {geometry: 'primitive:box'}}
   * @return {Element}            Entity created
   */
  createNewEntity: function (definition) {
    var entity = document.createElement(definition.element);

    // load default attributes
    for (var attr in definition.components) {
      entity.setAttribute(attr, definition.components[attr]);
    }

    // Ensure the components are loaded before update the UI
    entity.addEventListener('loaded', function () {
      this.addEntity(entity);
    }.bind(this));

    this.sceneEl.appendChild(entity);

    return entity;
  },
  addEntity: function (entity) {
    this.addObject(entity.object3D);
    this.selectEntity(entity);
  },

  open: function () {
//    this.panels.sidebar.show();
//    this.panels.menubar.show();
    this.enabled = true;
    Events.emit('editorModeChanged', true);
    this.sceneEl.pause();
  },

  close: function () {
//    this.panels.sidebar.hide();
//    this.panels.menubar.hide();
    this.enabled = false;
    Events.emit('editorModeChanged', false);
    this.sceneEl.play();
  // @todo Removelisteners
  },

  addObject: function (object) {
    var scope = this;
    object.traverse(function (child) {
      if (!child.el || !child.el.isEditor) {
        scope.addHelper(child);
      }
    });

    Events.emit('objectAdded', object);
    Events.emit('sceneGraphChanged');
  }
};

module.exports = Editor;
<|endoftext|>


<commit_before>(function(root) {

var gametree = root.gametree
var setting = root.setting
var fs = null

if (typeof require != 'undefined') {
    gametree = require('./gametree')
    setting = require('./setting')
    fs = require('fs')
}

var context = typeof module != 'undefined' ? module.exports : (window.sgf = {})
var alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

context.meta = {
    name: 'Smart Game Format',
    extensions: ['sgf']
}

context.tokenize = function(input) {
    input = input.replace(/(\r\n|\n\r|\r)/g, '\n')

    var tokens = []
    var rules = {
        ignore: /^\s+/,
        parenthesis: /^(\(|\))/,
        semicolon: /^;/,
        prop_ident: /^[A-Za-z]+/,
        c_value_type: /^\[([^\\\]]|\\[^])*\]/
    }

    while (input.length > 0) {
        var token = null
        var length = 1

        for (var type in rules) {
            var matches = rules[type].exec(input)
            if (!matches) continue

            var value = matches[0]
            length = value.length
            token = [type, value]

            break
        }

        if (token && token[0] != 'ignore') tokens.push(token)
        input = input.substr(length)
    }

    return tokens
}

context.parse = function(tokens, callback, start, depth) {
    if (!callback) callback = function(progress) {}
    if (!start) start = [0]
    if (isNaN(depth)) depth = 0

    var i = start[0]
    var node, property, tree = gametree.new()
    tree.collapsed = tokens.length >= setting.get('graph.collapse_tokens_count')
        && depth >= setting.get('graph.collapse_min_depth')

    while (i < tokens.length) {
        if (tokens[i][0] == 'parenthesis' && tokens[i][1] == '(') break
        if (tokens[i][0] == 'parenthesis' && tokens[i][1] == ')') return tree

        var type = tokens[i][0], value = tokens[i][1]

        if (type == 'semicolon') {
            node = {}
            tree.nodes.push(node)
        } else if (type == 'prop_ident') {
            var id = value.split('').filter(function(x) {
                return x.toUpperCase() == x
            }).join('')

            if (id != '') {
                node[id] = []
                property = node[id]
            }
        } else if (type == 'c_value_type') {
            property.push(context.unescapeString(value.substr(1, value.length - 2)))
        }

        start[0] = ++i
    }

    while (i < tokens.length) {
        if (tokens[i][0] == 'parenthesis' && tokens[i][1] == '(') {
            start[0] = i + 1

            t = context.parse(tokens, callback, start, depth + Math.min(tree.subtrees.length, 1))
            t.parent = tree
            tree.subtrees.push(t)
            tree.current = 0

            i = start[0]
        } else if (tokens[i][0] == 'parenthesis' && tokens[i][1] == ')') {
            start[0] = i
            callback(i / tokens.length)
            break
        }

        i++
    }

    return tree
}

context.parseFile = function(filename, callback) {
    if (!fs) return null

    var input = fs.readFileSync(filename, { encoding: 'utf8' })
    var tokens = context.tokenize(input)

    return context.parse(tokens, callback)
}

context.point2vertex = function(point) {
    if (point.length != 2) return [-1, -1]
    return [alpha.indexOf(point[0]), alpha.indexOf(point[1])]
}

context.vertex2point = function(vertex) {
    var x = vertex[0], y = vertex[1]
    if (x < 0 || y < 0) return ''
    return alpha[x] + alpha[y]
}

context.compressed2list = function(compressed) {
    var colon = compressed.indexOf(':')
    if (colon < 0) return [context.point2vertex(compressed)]

    var v1 = context.point2vertex(compressed.slice(0, colon))
    var v2 = context.point2vertex(compressed.slice(colon + 1))
    var list = []

    for (var i = Math.min(v1[0], v2[0]); i <= Math.max(v1[0], v2[0]); i++) {
        for (var j = Math.min(v1[1], v2[1]); j <= Math.max(v1[1], v2[1]); j++) {
            list.push([i, j])
        }
    }

    return list
}

context.addBoard = function(tree, index, baseboard) {
    if (isNaN(index)) index = 0
    if (index >= tree.nodes.length) return tree

    var node = tree.nodes[index]
    var vertex = null
    var board = null

    if (!baseboard) {
        var prev = gametree.navigate(tree, index, -1)

        if (!prev) {
            var size = 'SZ' in node ? node.SZ[0].toInt() : 19
            baseboard = new Board(size)
        } else {
            var prevNode = prev[0].nodes[prev[1]]

            if (!prevNode.board) context.addBoard(prev[0], prev[1])
            baseboard = prevNode.board
        }
    }

    if ('B' in node) {
        vertex = context.point2vertex(node.B[0])
        board = baseboard.makeMove(1, vertex)
    } else if ('W' in node) {
        vertex = context.point2vertex(node.W[0])
        board = baseboard.makeMove(-1, vertex)
    }

    if (!board) board = baseboard.clone()

    var ids = ['AW', 'AE', 'AB']

    for (var i = 0; i < ids.length; i++) {
        if (!(ids[i] in node)) continue

        node[ids[i]].forEach(function(value) {
            context.compressed2list(value).forEach(function(vertex) {
                board.arrangement[vertex] = i - 1
            })
        })
    }

    if (vertex != null) {
        board.markups[vertex] = ['point', 0, '']
    }

    var ids = ['CR', 'MA', 'SQ', 'TR']
    var classes = ['circle', 'cross', 'square', 'triangle']

    for (var i = 0; i < ids.length; i++) {
        if (!(ids[i] in node)) continue

        node[ids[i]].forEach(function(value) {
            context.compressed2list(value).forEach(function(vertex) {
                board.markups[vertex] = [classes[i], 0, '']
            })
        })
    }

    if ('LB' in node) {
        node.LB.forEach(function(composed) {
            var sep = composed.indexOf(':')
            var point = composed.slice(0, sep)
            var label = composed.slice(sep + 1).replace(/\s+/, ' ')
            board.markups[context.point2vertex(point)] = ['label', 0, label]
        })
    }

    if ('LN' in node) {
        node.LN.forEach(function(composed) {
            var sep = composed.indexOf(':')
            var p1 = composed.slice(0, sep)
            var p2 = composed.slice(sep + 1)
            board.lines.push([context.point2vertex(p1), context.point2vertex(p2), false])
        })
    }

    if ('AR' in node) {
        node.AR.forEach(function(composed) {
            var sep = composed.indexOf(':')
            var p1 = composed.slice(0, sep)
            var p2 = composed.slice(sep + 1)
            board.lines.push([context.point2vertex(p1), context.point2vertex(p2), true])
        })
    }

    node.board = board

    // Add variation overlays

    var addOverlay = function(node) {
        var v, sign

        if ('B' in node) {
            v = sgf.point2vertex(node.B[0])
            sign = 1
        } else if ('W' in node) {
            v = sgf.point2vertex(node.W[0])
            sign = -1
        } else {
            return
        }

        if (v in board.markups) board.markups[v][1] = sign
        else board.markups[v] = ['', sign, '']
    }

    if (index == tree.nodes.length - 1 && tree.subtrees.length > 0) {
        tree.subtrees.forEach(function(subtree) {
            if (subtree.nodes.length == 0) return
            addOverlay(subtree.nodes[0])
        })
    } else if (index < tree.nodes.length - 1) {
        addOverlay(tree.nodes[index + 1])
    }

    return tree
}

context.stringify = function(tree) {
    var output = ''

    tree.nodes.forEach(function(node) {
        output += ';'

        for (var id in node) {
            if (id.toUpperCase() != id) continue
            output += id

            node[id].forEach(function(value) {
                output += '[' + context.escapeString(value.toString()) + ']'
            })

            if (node[id].length == 0) output += '[]'
        }

        output += '\n'
    })

    for (var i = 0; i < tree.subtrees.length; i++) {
        output += '(' + context.stringify(tree.subtrees[i]) + ')'
    }

    return output
}

context.escapeString = function(input) {
    return input.replace(/\\/g, '\\\\').replace(/\]/g, '\\]')
}

context.unescapeString = function(input) {
    var result = ''
    var inBackslash = false

    input = input.replace(/(\r\n|\n\r|\r)/g, '\n')

    for (var i = 0; i < input.length; i++) {
        if (!inBackslash) {
            if (input[i] != '\\')
                result += input[i]
            else if (input[i] == '\\')
                inBackslash = true
        } else {
            if (input[i] != '\n')
                result += input[i]

            inBackslash = false
        }
    }

    return result
}

}).call(null, typeof module != 'undefined' ? module : window)
<commit_msg>Refactor<commit_after>(function(root) {

var gametree = root.gametree
var setting = root.setting
var fs = null

if (typeof require != 'undefined') {
    gametree = require('./gametree')
    setting = require('./setting')
    fs = require('fs')
}

var context = typeof module != 'undefined' ? module.exports : (window.sgf = {})
var alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

context.meta = {
    name: 'Smart Game Format',
    extensions: ['sgf']
}

context.tokenize = function(input) {
    input = input.replace(/(\r\n|\n\r|\r)/g, '\n')

    var tokens = []
    var rules = {
        ignore: /^\s+/,
        parenthesis: /^(\(|\))/,
        semicolon: /^;/,
        prop_ident: /^[A-Za-z]+/,
        c_value_type: /^\[([^\\\]]|\\[^])*\]/
    }

    while (input.length > 0) {
        var token = null
        var length = 1

        for (var type in rules) {
            var matches = rules[type].exec(input)
            if (!matches) continue

            var value = matches[0]
            length = value.length
            token = [type, value]

            break
        }

        if (token && token[0] != 'ignore') tokens.push(token)
        input = input.substr(length)
    }

    return tokens
}

context.parse = function(tokens, callback, start, depth) {
    if (!callback) callback = function(progress) {}
    if (!start) start = [0]
    if (isNaN(depth)) depth = 0

    var i = start[0]
    var node, property, tree = gametree.new()
    tree.collapsed = tokens.length >= setting.get('graph.collapse_tokens_count')
        && depth >= setting.get('graph.collapse_min_depth')

    while (i < tokens.length) {
        if (tokens[i][0] == 'parenthesis' && tokens[i][1] == '(') break
        if (tokens[i][0] == 'parenthesis' && tokens[i][1] == ')') return tree

        var type = tokens[i][0], value = tokens[i][1]

        if (type == 'semicolon') {
            node = {}
            tree.nodes.push(node)
        } else if (type == 'prop_ident') {
            var id = value.split('').filter(function(x) {
                return x.toUpperCase() == x
            }).join('')

            if (id != '') {
                node[id] = []
                property = node[id]
            }
        } else if (type == 'c_value_type') {
            property.push(context.unescapeString(value.substr(1, value.length - 2)))
        }

        start[0] = ++i
    }

    while (i < tokens.length) {
        if (tokens[i][0] == 'parenthesis' && tokens[i][1] == '(') {
            start[0] = i + 1

            t = context.parse(tokens, callback, start, depth + Math.min(tree.subtrees.length, 1))
            t.parent = tree
            tree.subtrees.push(t)
            tree.current = 0

            i = start[0]
        } else if (tokens[i][0] == 'parenthesis' && tokens[i][1] == ')') {
            start[0] = i
            callback(i / tokens.length)
            break
        }

        i++
    }

    return tree
}

context.parseFile = function(filename, callback) {
    if (!fs) return null

    var input = fs.readFileSync(filename, { encoding: 'utf8' })
    var tokens = context.tokenize(input)

    return context.parse(tokens, callback)
}

context.point2vertex = function(point) {
    if (point.length != 2) return [-1, -1]
    return point.split('').map(function(x) { return alpha.indexOf(x) })
}

context.vertex2point = function(vertex) {
    var x = vertex[0], y = vertex[1]
    if (Math.min(x, y) < 0 || Math.max(x, y) >= alpha.length)
        return ''
    return alpha[x] + alpha[y]
}

context.compressed2list = function(compressed) {
    var colon = compressed.indexOf(':')
    if (colon < 0) return [context.point2vertex(compressed)]

    var v1 = context.point2vertex(compressed.slice(0, colon))
    var v2 = context.point2vertex(compressed.slice(colon + 1))
    var list = []

    for (var i = Math.min(v1[0], v2[0]); i <= Math.max(v1[0], v2[0]); i++) {
        for (var j = Math.min(v1[1], v2[1]); j <= Math.max(v1[1], v2[1]); j++) {
            list.push([i, j])
        }
    }

    return list
}

context.addBoard = function(tree, index, baseboard) {
    if (isNaN(index)) index = 0
    if (index >= tree.nodes.length) return tree

    var node = tree.nodes[index]
    var vertex = null
    var board = null

    if (!baseboard) {
        var prev = gametree.navigate(tree, index, -1)

        if (!prev) {
            var size = 'SZ' in node ? node.SZ[0].toInt() : 19
            baseboard = new Board(size)
        } else {
            var prevNode = prev[0].nodes[prev[1]]

            if (!prevNode.board) context.addBoard(prev[0], prev[1])
            baseboard = prevNode.board
        }
    }

    if ('B' in node) {
        vertex = context.point2vertex(node.B[0])
        board = baseboard.makeMove(1, vertex)
    } else if ('W' in node) {
        vertex = context.point2vertex(node.W[0])
        board = baseboard.makeMove(-1, vertex)
    }

    if (!board) board = baseboard.clone()

    var ids = ['AW', 'AE', 'AB']

    for (var i = 0; i < ids.length; i++) {
        if (!(ids[i] in node)) continue

        node[ids[i]].forEach(function(value) {
            context.compressed2list(value).forEach(function(vertex) {
                board.arrangement[vertex] = i - 1
            })
        })
    }

    if (vertex != null) {
        board.markups[vertex] = ['point', 0, '']
    }

    var ids = ['CR', 'MA', 'SQ', 'TR']
    var classes = ['circle', 'cross', 'square', 'triangle']

    for (var i = 0; i < ids.length; i++) {
        if (!(ids[i] in node)) continue

        node[ids[i]].forEach(function(value) {
            context.compressed2list(value).forEach(function(vertex) {
                board.markups[vertex] = [classes[i], 0, '']
            })
        })
    }

    if ('LB' in node) {
        node.LB.forEach(function(composed) {
            var sep = composed.indexOf(':')
            var point = composed.slice(0, sep)
            var label = composed.slice(sep + 1).replace(/\s+/, ' ')
            board.markups[context.point2vertex(point)] = ['label', 0, label]
        })
    }

    if ('LN' in node) {
        node.LN.forEach(function(composed) {
            var sep = composed.indexOf(':')
            var p1 = composed.slice(0, sep)
            var p2 = composed.slice(sep + 1)
            board.lines.push([context.point2vertex(p1), context.point2vertex(p2), false])
        })
    }

    if ('AR' in node) {
        node.AR.forEach(function(composed) {
            var sep = composed.indexOf(':')
            var p1 = composed.slice(0, sep)
            var p2 = composed.slice(sep + 1)
            board.lines.push([context.point2vertex(p1), context.point2vertex(p2), true])
        })
    }

    node.board = board

    // Add variation overlays

    var addOverlay = function(node) {
        var v, sign

        if ('B' in node) {
            v = sgf.point2vertex(node.B[0])
            sign = 1
        } else if ('W' in node) {
            v = sgf.point2vertex(node.W[0])
            sign = -1
        } else {
            return
        }

        if (v in board.markups) board.markups[v][1] = sign
        else board.markups[v] = ['', sign, '']
    }

    if (index == tree.nodes.length - 1 && tree.subtrees.length > 0) {
        tree.subtrees.forEach(function(subtree) {
            if (subtree.nodes.length == 0) return
            addOverlay(subtree.nodes[0])
        })
    } else if (index < tree.nodes.length - 1) {
        addOverlay(tree.nodes[index + 1])
    }

    return tree
}

context.stringify = function(tree) {
    var output = ''

    tree.nodes.forEach(function(node) {
        output += ';'

        for (var id in node) {
            if (id.toUpperCase() != id) continue
            output += id + '[' + node[id].map(context.escapeString).join('][') + ']'
        }

        output += '\n'
    })

    for (var i = 0; i < tree.subtrees.length; i++) {
        output += '(' + context.stringify(tree.subtrees[i]) + ')'
    }

    return output
}

context.escapeString = function(input) {
    return input.toString().replace(/\\/g, '\\\\').replace(/\]/g, '\\]')
}

context.unescapeString = function(input) {
    var result = ''
    var inBackslash = false

    input = input.replace(/(\r\n|\n\r|\r)/g, '\n')

    for (var i = 0; i < input.length; i++) {
        if (!inBackslash) {
            if (input[i] != '\\')
                result += input[i]
            else if (input[i] == '\\')
                inBackslash = true
        } else {
            if (input[i] != '\n')
                result += input[i]

            inBackslash = false
        }
    }

    return result
}

}).call(null, typeof module != 'undefined' ? module : window)
<|endoftext|>


<commit_before>'use strict';

// https://developer.chrome.com/extensions/omnibox

var omnibox = {
  setDefaultSuggestion: jest.fn(),
  onInputStarted: {
    addListener: jest.fn()
  },
  onInputChanged: {
    addListener: jest.fn()
  },
  onInputEntered: {
    addListener: jest.fn()
  },
  onInputCancelled: {
    addListener: jest.fn()
  }
};

// https://developer.chrome.com/extensions/tabs

var tabs = {
  get: jest.fn(function () {
    var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
    return cb({});
  }),
  getCurrent: jest.fn(function (cb) {
    return cb({});
  }),
  connect: jest.fn(function () {
    var info = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    // returns a Port
    return {
      name: info.name,
      disconnect: jest.fn(),
      onDisconnect: {
        addListener: jest.fn()
      },
      onMessage: {
        addListener: jest.fn()
      },
      postMessage: jest.fn()
      // TODO: add sender
    };
  }),
  create: jest.fn(function () {
    var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var cb = arguments[1];

    if (cb !== undefined) {
      return cb(props);
    }
    return Promise.resolve(props);
  }),
  duplicate: jest.fn(function () {
    var id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
    var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
    return cb(Object.assign({}, { id: id }));
  }),
  query: jest.fn(function () {
    var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
    return cb([{}]);
  }),
  highlight: jest.fn(function () {
    var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
    return cb();
  }),
  update: jest.fn(function () {
    var id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var cb = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
    return cb(Object.assign({}, props, { id: id }));
  }),
  move: jest.fn(function () {
    var ids = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var cb = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
    return cb(ids.map(function (id) {
      return Object.assign({}, props, { id: id });
    }));
  })
};

var runtime = {
  connect: jest.fn(function (_ref) {
    var name = _ref.name;

    var connection = {
      name: name,
      postMessage: jest.fn(),
      onDisconnect: {
        addListener: jest.fn()
      },
      onMessage: {
        addListener: jest.fn()
      }
    };
    return connection;
  }),
  sendMessage: jest.fn(function (message, cb) {
    if (cb !== undefined) {
      return cb();
    }
    return Promise.resolve();
  }),
  onMessage: {
    addListener: jest.fn(),
    removeListener: jest.fn(),
    hasListener: jest.fn()
  },
  onConnect: {
    addListener: jest.fn(),
    removeListener: jest.fn(),
    hasListener: jest.fn()
  }
};

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  return typeof obj;
} : function (obj) {
  return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};

var store = {};

function resolveKey(key) {
  if (typeof key === 'string') {
    var result = {};
    result[key] = store[key];
    return result;
  } else if (Array.isArray(key)) {
    return key.reduce(function (acc, curr) {
      acc[curr] = store[curr];
      return acc;
    }, {});
  } else if ((typeof key === 'undefined' ? 'undefined' : _typeof(key)) === 'object') {
    return Object.keys(key).reduce(function (acc, curr) {
      acc[curr] = store[curr] || key[curr];
      return acc;
    }, {});
  }
  throw new Error('Wrong key given');
}

var storage = {
  sync: {
    get: jest.fn(function (id, cb) {
      var result = id === null ? store : resolveKey(id);
      if (cb !== undefined) {
        return cb(result);
      }
      return Promise.resolve(result);
    }),
    getBytesInUse: jest.fn(function (id, cb) {
      if (cb !== undefined) {
        return cb(0);
      }
      return Promise.resolve(0);
    }),
    set: jest.fn(function (payload, cb) {
      Object.keys(payload).forEach(function (key) {
        return store[key] = payload[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    remove: jest.fn(function (id, cb) {
      var keys = typeof id === 'string' ? [id] : id;
      keys.forEach(function (key) {
        return delete store[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    clear: jest.fn(function (cb) {
      store = {};
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    })
  },
  local: {
    get: jest.fn(function (id, cb) {
      var result = id === null ? store : resolveKey(id);
      if (cb !== undefined) {
        return cb(result);
      }
      return Promise.resolve(result);
    }),
    getBytesInUse: jest.fn(function (id, cb) {
      if (cb !== undefined) {
        return cb(0);
      }
      return Promise.resolve(0);
    }),
    set: jest.fn(function (payload, cb) {
      Object.keys(payload).forEach(function (key) {
        return store[key] = payload[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    remove: jest.fn(function (id, cb) {
      var keys = typeof id === 'string' ? [id] : id;
      keys.forEach(function (key) {
        return delete store[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    clear: jest.fn(function (cb) {
      store = {};
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    })
  },
  managed: {
    get: jest.fn(function (id, cb) {
      var result = id === null ? store : resolveKey(id);
      if (cb !== undefined) {
        return cb(result);
      }
      return Promise.resolve(result);
    }),
    getBytesInUse: jest.fn(function (id, cb) {
      if (cb !== undefined) {
        return cb(0);
      }
      return Promise.resolve(0);
    }),
    set: jest.fn(function (payload, cb) {
      Object.keys(payload).forEach(function (key) {
        return store[key] = payload[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    remove: jest.fn(function (id, cb) {
      var keys = typeof id === 'string' ? [id] : id;
      keys.forEach(function (key) {
        return delete store[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    clear: jest.fn(function (cb) {
      store = {};
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    })
  },
  onChanged: {
    addListener: jest.fn(),
    removeListener: jest.fn(),
    hasListener: jest.fn()
  }
};

var getDetails = function getDetails(details, cb) {
  if (cb !== undefined) {
    return cb();
  }
  return Promise.resolve();
};
var browserAction = {
  setTitle: jest.fn(),
  getTitle: jest.fn(getDetails),
  setIcon: jest.fn(getDetails),
  setPopup: jest.fn(),
  getPopup: jest.fn(getDetails),
  setBadgeText: jest.fn(),
  getBadgeText: jest.fn(getDetails),
  setBadgeBackgroundColor: jest.fn(),
  getBadgeBackgroundColor: jest.fn(getDetails),
  enable: jest.fn(),
  disable: jest.fn(),
  onClicked: {
    addListener: jest.fn()
  }
};

// https://developer.chrome.com/extensions/commands

var commands = {
  getAll: jest.fn(function (cb) {
    if (cb !== undefined) {
      return cb();
    }
    return Promise.resolve();
  }),
  onCommand: {
    addListener: jest.fn()
  }
};

var cbOrPromise = function cbOrPromise(cb, value) {
  if (cb !== undefined) {
    return cb(value);
  }

  return Promise.resolve(value);
};

var create = function create(notificationId, options, cb) {
  if (typeof notificationId !== 'string') {
    notificationId = 'generated-id';
  }

  if (typeof options === 'function') {
    cb = options;
  }

  return cbOrPromise(cb, notificationId);
};

var notifications = {
  create: jest.fn(create),
  update: jest.fn(function (notificationId, options, cb) {
    return cbOrPromise(cb, true);
  }),
  clear: jest.fn(function (notificationId, cb) {
    return cbOrPromise(cb, true);
  }),
  getAll: jest.fn(function (cb) {
    return cbOrPromise(cb, []);
  }),
  getPermissionLevel: jest.fn(function (cb) {
    return cbOrPromise(cb, 'granted');
  }),
  onClosed: {
    addListener: jest.fn()
  },
  onClicked: {
    addListener: jest.fn()
  },
  onButtonClicked: {
    addListener: jest.fn()
  },
  onPermissionLevelChanged: {
    addListener: jest.fn()
  },
  onShowSettings: {
    addListener: jest.fn()
  }
};

var geckoProfiler = {
  stop: jest.fn(function () {
    return Promise.resolve();
  }),
  start: jest.fn(function () {
    return Promise.resolve();
  }),
  pause: jest.fn(function () {
    return Promise.resolve();
  }),
  resume: jest.fn(function () {
    return Promise.resolve();
  }),
  getProfile: jest.fn(function () {
    return Promise.resolve();
  }),
  getProfileAsArrayBuffer: jest.fn(function () {
    return Promise.resolve();
  }),
  getSymbols: jest.fn(function (debugName, breakpadId) {
    return Promise.resolve();
  }),
  onRunning: {
    addListener: jest.fn()
  }
};

var chrome = {
  omnibox: omnibox,
  tabs: tabs,
  runtime: runtime,
  storage: storage,
  browserAction: browserAction,
  commands: commands,
  geckoProfiler: geckoProfiler,
  notifications: notifications
};
 // Firefox uses 'browser' but aliases it to chrome

/**
 * This is a setup file we specify as our 'main' entry point
 * from the package.json file.  This allows developers to
 * directly call the module in their `setupFiles` property.
 */

global.chrome = chrome;
global.browser = chrome;

// Firefox specific globals
// if (navigator.userAgent.indexOf('Firefox') !== -1) {
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#exportFunction
global.exportFunction = jest.fn(function (func) {
  return func;
});
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#cloneInto
global.cloneInto = jest.fn(function (obj) {
  return obj;
});
// }
<commit_msg>Update release build<commit_after>'use strict';

// https://developer.chrome.com/extensions/omnibox

var omnibox = {
  setDefaultSuggestion: jest.fn(),
  onInputStarted: {
    addListener: jest.fn()
  },
  onInputChanged: {
    addListener: jest.fn()
  },
  onInputEntered: {
    addListener: jest.fn()
  },
  onInputCancelled: {
    addListener: jest.fn()
  }
};

// https://developer.chrome.com/extensions/tabs

var tabs = {
  get: jest.fn(function () {
    var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
    return cb({});
  }),
  getCurrent: jest.fn(function (cb) {
    return cb({});
  }),
  connect: jest.fn(function () {
    var info = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    // returns a Port
    return {
      name: info.name,
      disconnect: jest.fn(),
      onDisconnect: {
        addListener: jest.fn()
      },
      onMessage: {
        addListener: jest.fn()
      },
      postMessage: jest.fn()
      // TODO: add sender
    };
  }),
  create: jest.fn(function () {
    var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var cb = arguments[1];

    if (cb !== undefined) {
      return cb(props);
    }
    return Promise.resolve(props);
  }),
  duplicate: jest.fn(function () {
    var id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
    var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
    return cb(Object.assign({}, { id: id }));
  }),
  query: jest.fn(function () {
    var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
    return cb([{}]);
  }),
  highlight: jest.fn(function () {
    var cb = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
    return cb();
  }),
  update: jest.fn(function () {
    var id = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var cb = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
    return cb(Object.assign({}, props, { id: id }));
  }),
  move: jest.fn(function () {
    var ids = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    var cb = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
    return cb(ids.map(function (id) {
      return Object.assign({}, props, { id: id });
    }));
  })
};

var runtime = {
  connect: jest.fn(function (_ref) {
    var name = _ref.name;

    var connection = {
      name: name,
      postMessage: jest.fn(),
      onDisconnect: {
        addListener: jest.fn()
      },
      onMessage: {
        addListener: jest.fn()
      }
    };
    return connection;
  }),
  sendMessage: jest.fn(function (message, cb) {
    if (cb !== undefined) {
      return cb();
    }
    return Promise.resolve();
  }),
  onMessage: {
    addListener: jest.fn(),
    removeListener: jest.fn(),
    hasListener: jest.fn()
  },
  onConnect: {
    addListener: jest.fn(),
    removeListener: jest.fn(),
    hasListener: jest.fn()
  }
};

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
  return typeof obj;
} : function (obj) {
  return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};

var store = {};

function resolveKey(key) {
  if (typeof key === 'string') {
    var result = {};
    result[key] = store[key];
    return result;
  } else if (Array.isArray(key)) {
    return key.reduce(function (acc, curr) {
      acc[curr] = store[curr];
      return acc;
    }, {});
  } else if ((typeof key === 'undefined' ? 'undefined' : _typeof(key)) === 'object') {
    return Object.keys(key).reduce(function (acc, curr) {
      acc[curr] = store[curr] || key[curr];
      return acc;
    }, {});
  }
  throw new Error('Wrong key given');
}

var storage = {
  sync: {
    get: jest.fn(function (id, cb) {
      var result = id === null ? store : resolveKey(id);
      if (cb !== undefined) {
        return cb(result);
      }
      return Promise.resolve(result);
    }),
    getBytesInUse: jest.fn(function (id, cb) {
      if (cb !== undefined) {
        return cb(0);
      }
      return Promise.resolve(0);
    }),
    set: jest.fn(function (payload, cb) {
      Object.keys(payload).forEach(function (key) {
        return store[key] = payload[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    remove: jest.fn(function (id, cb) {
      var keys = typeof id === 'string' ? [id] : id;
      keys.forEach(function (key) {
        return delete store[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    clear: jest.fn(function (cb) {
      store = {};
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    })
  },
  local: {
    get: jest.fn(function (id, cb) {
      var result = id === null ? store : resolveKey(id);
      if (cb !== undefined) {
        return cb(result);
      }
      return Promise.resolve(result);
    }),
    getBytesInUse: jest.fn(function (id, cb) {
      if (cb !== undefined) {
        return cb(0);
      }
      return Promise.resolve(0);
    }),
    set: jest.fn(function (payload, cb) {
      Object.keys(payload).forEach(function (key) {
        return store[key] = payload[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    remove: jest.fn(function (id, cb) {
      var keys = typeof id === 'string' ? [id] : id;
      keys.forEach(function (key) {
        return delete store[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    clear: jest.fn(function (cb) {
      store = {};
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    })
  },
  managed: {
    get: jest.fn(function (id, cb) {
      var result = id === null ? store : resolveKey(id);
      if (cb !== undefined) {
        return cb(result);
      }
      return Promise.resolve(result);
    }),
    getBytesInUse: jest.fn(function (id, cb) {
      if (cb !== undefined) {
        return cb(0);
      }
      return Promise.resolve(0);
    }),
    set: jest.fn(function (payload, cb) {
      Object.keys(payload).forEach(function (key) {
        return store[key] = payload[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    remove: jest.fn(function (id, cb) {
      var keys = typeof id === 'string' ? [id] : id;
      keys.forEach(function (key) {
        return delete store[key];
      });
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    }),
    clear: jest.fn(function (cb) {
      store = {};
      if (cb !== undefined) {
        return cb();
      }
      return Promise.resolve();
    })
  },
  onChanged: {
    addListener: jest.fn(),
    removeListener: jest.fn(),
    hasListener: jest.fn()
  }
};

var getDetails = function getDetails(details, cb) {
  if (cb !== undefined) {
    return cb();
  }
  return Promise.resolve();
};
var browserAction = {
  setTitle: jest.fn(),
  getTitle: jest.fn(getDetails),
  setIcon: jest.fn(getDetails),
  setPopup: jest.fn(),
  getPopup: jest.fn(getDetails),
  setBadgeText: jest.fn(),
  getBadgeText: jest.fn(getDetails),
  setBadgeBackgroundColor: jest.fn(),
  getBadgeBackgroundColor: jest.fn(getDetails),
  enable: jest.fn(),
  disable: jest.fn(),
  onClicked: {
    addListener: jest.fn()
  }
};

// https://developer.chrome.com/extensions/commands

var commands = {
  getAll: jest.fn(function (cb) {
    if (cb !== undefined) {
      return cb();
    }
    return Promise.resolve();
  }),
  onCommand: {
    addListener: jest.fn()
  }
};

var cbOrPromise = function cbOrPromise(cb, value) {
  if (cb !== undefined) {
    return cb(value);
  }

  return Promise.resolve(value);
};

var create = function create(notificationId, options, cb) {
  if (typeof notificationId !== 'string') {
    notificationId = 'generated-id';
  }

  if (typeof options === 'function') {
    cb = options;
  }

  return cbOrPromise(cb, notificationId);
};

var notifications = {
  create: jest.fn(create),
  update: jest.fn(function (notificationId, options, cb) {
    return cbOrPromise(cb, true);
  }),
  clear: jest.fn(function (notificationId, cb) {
    return cbOrPromise(cb, true);
  }),
  getAll: jest.fn(function (cb) {
    return cbOrPromise(cb, []);
  }),
  getPermissionLevel: jest.fn(function (cb) {
    return cbOrPromise(cb, 'granted');
  }),
  onClosed: {
    addListener: jest.fn()
  },
  onClicked: {
    addListener: jest.fn()
  },
  onButtonClicked: {
    addListener: jest.fn()
  },
  onPermissionLevelChanged: {
    addListener: jest.fn()
  },
  onShowSettings: {
    addListener: jest.fn()
  }
};

var i18n = {
  getAcceptLanguages: jest.fn(),
  getMessage: jest.fn(function (key) {
    return 'Translated<' + key + '>';
  }),
  getUILanguage: jest.fn(function () {
    return 'en';
  }),
  detectLanguage: jest.fn()
};

var geckoProfiler = {
  stop: jest.fn(function () {
    return Promise.resolve();
  }),
  start: jest.fn(function () {
    return Promise.resolve();
  }),
  pause: jest.fn(function () {
    return Promise.resolve();
  }),
  resume: jest.fn(function () {
    return Promise.resolve();
  }),
  getProfile: jest.fn(function () {
    return Promise.resolve();
  }),
  getProfileAsArrayBuffer: jest.fn(function () {
    return Promise.resolve();
  }),
  getSymbols: jest.fn(function (debugName, breakpadId) {
    return Promise.resolve();
  }),
  onRunning: {
    addListener: jest.fn()
  }
};

var chrome = {
  omnibox: omnibox,
  tabs: tabs,
  runtime: runtime,
  storage: storage,
  browserAction: browserAction,
  commands: commands,
  geckoProfiler: geckoProfiler,
  notifications: notifications,
  i18n: i18n
};
 // Firefox uses 'browser' but aliases it to chrome

/**
 * This is a setup file we specify as our 'main' entry point
 * from the package.json file.  This allows developers to
 * directly call the module in their `setupFiles` property.
 */

global.chrome = chrome;
global.browser = chrome;

// Firefox specific globals
// if (navigator.userAgent.indexOf('Firefox') !== -1) {
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#exportFunction
global.exportFunction = jest.fn(function (func) {
  return func;
});
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#cloneInto
global.cloneInto = jest.fn(function (obj) {
  return obj;
});
// }
<|endoftext|>


<commit_before>'use strict';
angular.module('slick', []).directive('slick', [
  '$timeout',
  function ($timeout) {
    return {
      restrict: 'AEC',
      scope: {
        initOnload: '@',
        data: '=',
        currentIndex: '=',
        accessibility: '@',
        adaptiveHeight: '@',
        arrows: '@',
        asNavFor: '@',
        appendArrows: '@',
        appendDots: '@',
        autoplay: '@',
        autoplaySpeed: '@',
        centerMode: '@',
        centerPadding: '@',
        cssEase: '@',
        customPaging: '&',
        dots: '@',
        dotsClass: '@',
        draggable: '@',
        easing: '@',
        edgeFriction: '@',
        fade: '@',
        focusOnSelect: '@',
        infinite: '@',
        initialSlide: '@',
        lazyLoad: '@',
        mobileFirst: '@',
        onBeforeChange: '=',
        onAfterChange: '=',
        onInit: '=',
        onReInit: '=',
        onSetPosition: '=',
        pauseOnHover: '@',
        pauseOnDotsHover: '@',
        responsive: '=',
        respondTo: '@',
        rtl: '@',
        rows: '@',
        slidesPerRow: '@',
        slide: '@',
        slidesToShow: '@',
        slidesToScroll: '@',
        speed: '@',
        swipe: '@',
        swipeToSlide: '@',
        touchMove: '@',
        touchThreshold: '@',
        useCSS: '@',
        variableWidth: '@',
        vertical: '@',
        verticalSwiping: '@',
        waitForAnimate: '@',
        prevArrow: '@',
        nextArrow: '@',
        zIndex: '@'
      },
      link: function (scope, element, attrs) {
        var destroySlick, initializeSlick, isInitialized;
        destroySlick = function () {
          return $timeout(function () {
            var slider;
            slider = $(element);
            slider.slick('unslick');
            slider.find('.slick-list').remove();
            return slider;
          });
        };
        initializeSlick = function () {
          return $timeout(function () {
            var currentIndex, customPaging, slider;
            slider = $(element);
            if (scope.currentIndex != null) {
              currentIndex = scope.currentIndex;
            }
            customPaging = function (slick, index) {
              return scope.customPaging({
                slick: slick,
                index: index
              });
            };
            slider.on('init', function (event, slick) {
                if (attrs.onInit) {
                    scope.onInit();
                }
                if (currentIndex != null) {
                    return slick.slideHandler(currentIndex);
                }
            });
            slider.on('reInit', function (event, slick) {
                if (attrs.onReInit) {
                    return scope.onReInit();
                }
            });
            slider.on('setPosition', function (event, slick) {
                if (attrs.onSetPosition) {
                    return scope.onSetPosition();
                }
            });
            slider.on('swipe', function (event, slick, direction) {
                if (attrs.onSwipe) {
                    return scope.onSwipe(direction);
                }
            });
            slider.on('afterChange', function (event, slick, currentSlide) {
                if (scope.onAfterChange) {
                    scope.onAfterChange(currentSlide);
                }
                if (currentIndex != null) {
                    return scope.$apply(function () {
                      currentIndex = currentSlide;
                      return scope.currentIndex = currentSlide;
                    });
                }
            });
            slider.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
                if (attrs.onBeforeChange) {
                    return scope.onBeforeChange(currentSlide, nextSlide);
                }
            });
            slider.on('breakpoint', function (event, slick) {
                if (attrs.onBreakpoint) {
                    return scope.onBreakpoint();
                }
            });
            slider.on('destroy', function (event, slick) {
                if (attrs.onDestroy) {
                    return scope.onDestroy();
                }
            });
            slider.on('edge', function (event, slick, direction) {
                if (attrs.onEdge) {
                    return scope.onEdge(direction);
                }
            });
            slider.slick({
              accessibility: scope.accessibility !== 'false',
              adaptiveHeight: scope.adaptiveHeight === 'true',
              arrows: scope.arrows !== 'false',
              asNavFor: scope.asNavFor ? scope.asNavFor : void 0,
              appendArrows: scope.appendArrows ? $(scope.appendArrows) : $(element),
              appendDots: scope.appendDots ? $(scope.appendDots) : $(element),
              autoplay: scope.autoplay === 'true',
              autoplaySpeed: scope.autoplaySpeed != null ? parseInt(scope.autoplaySpeed, 10) : 3000,
              centerMode: scope.centerMode === 'true',
              centerPadding: scope.centerPadding || '50px',
              cssEase: scope.cssEase || 'ease',
              customPaging: attrs.customPaging ? customPaging : void 0,
              dots: scope.dots === 'true',
              dotsClass: scope.dotsClass || 'slick-dots',
              draggable: scope.draggable !== 'false',
              easing: scope.easing || 'linear',
              edgeFriction: scope.edgeFriction || 0.15,
              fade: scope.fade === 'true',
              focusOnSelect: scope.focusOnSelect === 'true',
              infinite: scope.infinite !== 'false',
              initialSlide: scope.initialSlide || 0,
              lazyLoad: scope.lazyLoad || 'ondemand',
              mobileFirst: scope.mobileFirst === 'true',
              pauseOnHover: scope.pauseOnHover !== 'false',
              pauseOnDotsHover: scope.pauseOnDotsHover === 'true',
              responsive: scope.responsive || void 0,
              rtl: scope.rtl === 'true',
              respondTo: scope.respondTo != null ? scope.respondTo : 'window',
              rows: scope.rows != null ? parseInt(scope.rows, 10) : 1,
              slidesPerRow: scope.slidesPerRow != null ? parseInt(scope.slidesPerRow, 10) : 1,
              slide: scope.slide || 'div',
              slidesToShow: scope.slidesToShow != null ? parseInt(scope.slidesToShow, 10) : 1,
              slidesToScroll: scope.slidesToScroll != null ? parseInt(scope.slidesToScroll, 10) : 1,
              speed: scope.speed != null ? parseInt(scope.speed, 10) : 300,
              swipe: scope.swipe !== 'false',
              swipeToSlide: scope.swipeToSlide === 'true',
              touchMove: scope.touchMove !== 'false',
              touchThreshold: scope.touchThreshold ? parseInt(scope.touchThreshold, 10) : 5,
              useCSS: scope.useCSS !== 'false',
              variableWidth: scope.variableWidth === 'true',
              vertical: scope.vertical === 'true',
              verticalSwiping: scope.verticalSwiping != null === 'true',
              waitForAnimate: scope.waitForAnimate != null !== 'true',
              zIndex: scope.zIndex != null ? parseInt(scope.zIndex, 10) : 1000,
              prevArrow: scope.prevArrow ? $(scope.prevArrow) : void 0,
              nextArrow: scope.nextArrow ? $(scope.nextArrow) : void 0
            });
            return scope.$watch('currentIndex', function (newVal, oldVal) {
              if (currentIndex != null && newVal != null && newVal !== currentIndex) {
                return slider.slick('slickGoTo', newVal);
              }
            });
          });
        };
        if (scope.initOnload) {
          isInitialized = false;
          return scope.$watch('data', function (newVal, oldVal) {
            if (newVal != null) {
              if (isInitialized) {
                destroySlick();
              }
              initializeSlick();
              return isInitialized = true;
            }
          });
        } else {
          return initializeSlick();
        }
      }
    };
  }
]);<commit_msg>Add Event/Slick parameter<commit_after>'use strict';
angular.module('slick', []).directive('slick', [
  '$timeout',
  function ($timeout) {
    return {
      restrict: 'AEC',
      scope: {
        initOnload: '@',
        data: '=',
        currentIndex: '=',
        accessibility: '@',
        adaptiveHeight: '@',
        arrows: '@',
        asNavFor: '@',
        appendArrows: '@',
        appendDots: '@',
        autoplay: '@',
        autoplaySpeed: '@',
        centerMode: '@',
        centerPadding: '@',
        cssEase: '@',
        customPaging: '&',
        dots: '@',
        dotsClass: '@',
        draggable: '@',
        easing: '@',
        edgeFriction: '@',
        fade: '@',
        focusOnSelect: '@',
        infinite: '@',
        initialSlide: '@',
        lazyLoad: '@',
        mobileFirst: '@',
        onBeforeChange: '=',
        onAfterChange: '=',
        onInit: '=',
        onReInit: '=',
        onSetPosition: '=',
        pauseOnHover: '@',
        pauseOnDotsHover: '@',
        responsive: '=',
        respondTo: '@',
        rtl: '@',
        rows: '@',
        slidesPerRow: '@',
        slide: '@',
        slidesToShow: '@',
        slidesToScroll: '@',
        speed: '@',
        swipe: '@',
        swipeToSlide: '@',
        touchMove: '@',
        touchThreshold: '@',
        useCSS: '@',
        variableWidth: '@',
        vertical: '@',
        verticalSwiping: '@',
        waitForAnimate: '@',
        prevArrow: '@',
        nextArrow: '@',
        zIndex: '@'
      },
      link: function (scope, element, attrs) {
        var destroySlick, initializeSlick, isInitialized;
        destroySlick = function () {
          return $timeout(function () {
            var slider;
            slider = $(element);
            slider.slick('unslick');
            slider.find('.slick-list').remove();
            return slider;
          });
        };
        initializeSlick = function () {
          return $timeout(function () {
            var currentIndex, customPaging, slider;
            slider = $(element);
            if (scope.currentIndex != null) {
              currentIndex = scope.currentIndex;
            }
            customPaging = function (slick, index) {
              return scope.customPaging({
                slick: slick,
                index: index
              });
            };
            slider.slick({
              accessibility: scope.accessibility !== 'false',
              adaptiveHeight: scope.adaptiveHeight === 'true',
              arrows: scope.arrows !== 'false',
              asNavFor: scope.asNavFor ? scope.asNavFor : void 0,
              appendArrows: scope.appendArrows ? $(scope.appendArrows) : $(element),
              appendDots: scope.appendDots ? $(scope.appendDots) : $(element),
              autoplay: scope.autoplay === 'true',
              autoplaySpeed: scope.autoplaySpeed != null ? parseInt(scope.autoplaySpeed, 10) : 3000,
              centerMode: scope.centerMode === 'true',
              centerPadding: scope.centerPadding || '50px',
              cssEase: scope.cssEase || 'ease',
              customPaging: attrs.customPaging ? customPaging : void 0,
              dots: scope.dots === 'true',
              dotsClass: scope.dotsClass || 'slick-dots',
              draggable: scope.draggable !== 'false',
              easing: scope.easing || 'linear',
              edgeFriction: scope.edgeFriction || 0.15,
              fade: scope.fade === 'true',
              focusOnSelect: scope.focusOnSelect === 'true',
              infinite: scope.infinite !== 'false',
              initialSlide: scope.initialSlide || 0,
              lazyLoad: scope.lazyLoad || 'ondemand',
              mobileFirst: scope.mobileFirst === 'true',
              pauseOnHover: scope.pauseOnHover !== 'false',
              pauseOnDotsHover: scope.pauseOnDotsHover === 'true',
              responsive: scope.responsive || void 0,
              rtl: scope.rtl === 'true',
              respondTo: scope.respondTo != null ? scope.respondTo : 'window',
              rows: scope.rows != null ? parseInt(scope.rows, 10) : 1,
              slidesPerRow: scope.slidesPerRow != null ? parseInt(scope.slidesPerRow, 10) : 1,
              slide: scope.slide || 'div',
              slidesToShow: scope.slidesToShow != null ? parseInt(scope.slidesToShow, 10) : 1,
              slidesToScroll: scope.slidesToScroll != null ? parseInt(scope.slidesToScroll, 10) : 1,
              speed: scope.speed != null ? parseInt(scope.speed, 10) : 300,
              swipe: scope.swipe !== 'false',
              swipeToSlide: scope.swipeToSlide === 'true',
              touchMove: scope.touchMove !== 'false',
              touchThreshold: scope.touchThreshold ? parseInt(scope.touchThreshold, 10) : 5,
              useCSS: scope.useCSS !== 'false',
              variableWidth: scope.variableWidth === 'true',
              vertical: scope.vertical === 'true',
              verticalSwiping: scope.verticalSwiping != null === 'true',
              waitForAnimate: scope.waitForAnimate != null !== 'true',
              zIndex: scope.zIndex != null ? parseInt(scope.zIndex, 10) : 1000,
              prevArrow: scope.prevArrow ? $(scope.prevArrow) : void 0,
              nextArrow: scope.nextArrow ? $(scope.nextArrow) : void 0
            });
            slider.on('init', function (event, slick) {
              if (attrs.onInit) {
                scope.onInit();
              }
              if (currentIndex != null) {
                return slick.slideHandler(currentIndex);
              }
            });
            slider.on('reInit', function (event, slick) {
              if (attrs.onReInit) {
                return scope.onReInit();
              }
            });
            slider.on('setPosition', function (event, slick) {
              if (attrs.onSetPosition) {
                return scope.onSetPosition();
              }
            });
            slider.on('swipe', function (event, slick, direction) {
              if (attrs.onSwipe) {
                return scope.onSwipe(direction);
              }
            });
            slider.on('afterChange', function (event, slick, currentSlide) {
              if (scope.onAfterChange) {
                scope.onAfterChange(currentSlide);
              }
              if (currentIndex != null) {
                return scope.$apply(function () {
                  currentIndex = currentSlide;
                  return scope.currentIndex = currentSlide;
                });
              }
            });
            slider.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
              if (attrs.onBeforeChange) {
                return scope.onBeforeChange(currentSlide, nextSlide);
              }
            });
            slider.on('breakpoint', function (event, slick) {
              if (attrs.onBreakpoint) {
                return scope.onBreakpoint();
              }
            });
            slider.on('destroy', function (event, slick) {
              if (attrs.onDestroy) {
                return scope.onDestroy();
              }
            });
            slider.on('edge', function (event, slick, direction) {
              if (attrs.onEdge) {
                return scope.onEdge(direction);
              }
            });
            return scope.$watch('currentIndex', function (newVal, oldVal) {
              if (currentIndex != null && newVal != null && newVal !== currentIndex) {
                return slider.slick('slickGoTo', newVal);
              }
            });
          });
        };
        if (scope.initOnload) {
          isInitialized = false;
          return scope.$watch('data', function (newVal, oldVal) {
            if (newVal != null) {
              if (isInitialized) {
                destroySlick();
              }
              initializeSlick();
              return isInitialized = true;
            }
          });
        } else {
          return initializeSlick();
        }
      }
    };
  }
]);<|endoftext|>


<commit_before>/*
Copyright (c) 2012 Petka Antonov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Based on http://cherne.net/brian/resources/jquery.hoverIntent.js
*/

(function (window, Math, $, undef) {

    $.MouseSettle = MouseSettle;

    MouseSettle.settlingTimeout = 650;
    MouseSettle.speedThreshold = 150;

    function MouseSettle( elem, event, handler ) {
        this.elem = elem;
        this.event = event;
        this.handler = handler;
        this.mousemove = $.proxy( this.mousemove, this );
        this.poller = $.proxy( this.poller, this );
        this.settled = $.proxy( this.settled, this );
        this.throttleId = window.setTimeout( this.settled, MouseSettle.settlingTimeout );
        this.pollerId = window.setInterval( this.poller, 20 );
        this.cur = {};
        this.prev = {};
        this.lastPoll = +new Date;
        this.isSettled = false;
    }

    MouseSettle.prototype = {

        pollerId: 0,

        speedId: 0,

        throttleId: 0,

        poller: function() {
            var cur = this.cur,
                prev = this.prev,
                now = +new Date,

                checkSpeedInterval = now - this.lastPoll;

            this.lastPoll = now;

            if (prev.x !== undef && prev.y !== undef) {
                var speed = (Math.sqrt(Math.pow(prev.x - cur.x, 2) + Math.pow(prev.y - cur.y, 2)) / checkSpeedInterval ) * 1000;
                if (speed <= MouseSettle.speedThreshold && !this.throttleId) {
                    this.throttleId = window.setTimeout( this.settled, MouseSettle.settlingTimeout );
                }
                if( speed > MouseSettle.speedThreshold ){
                    window.clearTimeout( this.throttleId );
                    this.throttleId = 0;
                }
            }
            prev.x = cur.x;
            prev.y = cur.y;

        },

        settled: function() {
            if( this.isSettled ) {
                return;
            }
            this.isSettled = true;
            var event = this.event;
            event.type = "mousesettle";
            this.handler.call( this.elem, event );

        },

        bind: function() {
            $( this.elem ).on( "mousemove.mousesettle", this.mousemove );
             return this;
        },

        mousemove: function(e) {
            this.cur.x = e.pageX;
            this.cur.y = e.pageY;
        },

        destroy: function() {
            window.clearInterval( this.pollerId );
            window.clearTimeout( this.throttleId );
            $( this.elem ).off( "mousemove.mousesettle" ).removeData( "mouseSettleInstance" );
        },

        constructor: MouseSettle
    };

    $.event.special.mousesettle = {
            setup: function( data ) {
                return true;
            },

            teardown: function() {
                return true;
            },

            remove: function( obj ) {
                if( !obj.mouseSettleHandler ) {
                    return;
                }
                $( this ).off( "mouseenter mouseleave", obj.selector || null,  obj.mouseSettleHandler );

            },

            add: function( obj ) {
                obj.mouseSettleHandler = makeMouseSettleHandler(obj.handler);
                $( this ).on( "mouseenter mouseleave", obj.selector || null,  obj.mouseSettleHandler );
    };

    function makeMouseSettleHandler( handler ) {
        var instance;
        return function( event ) {
            if( event.type === "mouseenter" ) {
                instance = new MouseSettle( this, event, handler );
                instance.bind();
            }
            else {
                if( instance ) {
                    instance.destroy();
                    instance = null;
                }
                $(this).trigger( "mouseunsettle" );
            }
        };
    }

}(this, this.Math, this.jQuery));<commit_msg>add shortcut methods<commit_after>/*
Copyright (c) 2012 Petka Antonov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Based on http://cherne.net/brian/resources/jquery.hoverIntent.js
*/

(function (window, Math, $, undef) {

    $.MouseSettle = MouseSettle;

    MouseSettle.settlingTimeout = 650;
    MouseSettle.speedThreshold = 150;

    function MouseSettle( elem, event, handler ) {
        this.elem = elem;
        this.event = event;
        this.handler = handler;
        this.mousemove = $.proxy( this.mousemove, this );
        this.poller = $.proxy( this.poller, this );
        this.settled = $.proxy( this.settled, this );
        this.throttleId = window.setTimeout( this.settled, MouseSettle.settlingTimeout );
        this.pollerId = window.setInterval( this.poller, 20 );
        this.cur = {};
        this.prev = {};
        this.lastPoll = +new Date;
        this.isSettled = false;
    }

    MouseSettle.prototype = {

        pollerId: 0,

        speedId: 0,

        throttleId: 0,

        poller: function() {
            var cur = this.cur,
                prev = this.prev,
                now = +new Date,

                checkSpeedInterval = now - this.lastPoll;

            this.lastPoll = now;

            if (prev.x !== undef && prev.y !== undef) {
                var speed = (Math.sqrt(Math.pow(prev.x - cur.x, 2) + Math.pow(prev.y - cur.y, 2)) / checkSpeedInterval ) * 1000;
                if (speed <= MouseSettle.speedThreshold && !this.throttleId) {
                    this.throttleId = window.setTimeout( this.settled, MouseSettle.settlingTimeout );
                }
                if( speed > MouseSettle.speedThreshold ){
                    window.clearTimeout( this.throttleId );
                    this.throttleId = 0;
                }
            }
            prev.x = cur.x;
            prev.y = cur.y;

        },

        settled: function() {
            if( this.isSettled ) {
                return;
            }
            this.isSettled = true;
            var event = this.event;
            event.type = "mousesettle";
            this.handler.call( this.elem, event );

        },

        bind: function() {
            $( this.elem ).on( "mousemove.mousesettle", this.mousemove );
             return this;
        },

        mousemove: function(e) {
            this.cur.x = e.pageX;
            this.cur.y = e.pageY;
        },

        destroy: function() {
            window.clearInterval( this.pollerId );
            window.clearTimeout( this.throttleId );
            $( this.elem ).off( "mousemove.mousesettle" ).removeData( "mouseSettleInstance" );
        },

        constructor: MouseSettle
    };

    $.event.special.mousesettle = {
            setup: function( data ) {
                return true;
            },

            teardown: function() {
                return true;
            },

            remove: function( obj ) {
                if( !obj.mouseSettleHandler ) {
                    return;
                }
                $( this ).off( "mouseenter mouseleave", obj.selector || null,  obj.mouseSettleHandler );

            },

            add: function( obj ) {
                obj.mouseSettleHandler = makeMouseSettleHandler(obj.handler);
                $( this ).on( "mouseenter mouseleave", obj.selector || null,  obj.mouseSettleHandler );
    };

    function makeMouseSettleHandler( handler ) {
        var instance;
        return function( event ) {
            if( event.type === "mouseenter" ) {
                instance = new MouseSettle( this, event, handler );
                instance.bind();
            }
            else {
                if( instance ) {
                    instance.destroy();
                    instance = null;
                }
                $(this).trigger( "mouseunsettle" );
            }
        };
    }

    $.each( ["mousesettle", "mouseunsettle"], function( i, name ) {

        $.fn[ name ] = function( data, fn ) {
            if ( fn == null ) {
                fn = data;
                data = null;
            }

            return arguments.length > 0 ?
                this.on( name, null, data, fn ) :
                this.trigger( name );
        };

    });

}(this, this.Math, this.jQuery));<|endoftext|>


<commit_before>var settings = new Store("settings");
var sesionId;
var loginInterval,homePageInterval,checkMinimumReachedInterval ;
var currentAulas;
var unReadMsg=0;
var personalMailbox = {};

function map2string(map){
	var str = "";
	for(var v in map){
		str += v+"="+map[v]+"&";
	}
	return str;
}

function nowToStr(){
	var time = /(..)(:..)/.exec(new Date());     // The prettyprinted time.
	var hour = time[1] % 12 || 12;               // The prettyprinted hour.
	var period = time[1] < 12 ? 'a.m.' : 'p.m.'; // The period of the day.
	return hour + time[2] + ' ' + period;
}
function getPicture(aula){
	var args = {
		s : sessionId,
		param : 'dCode%3D'+aula.code,
		up_xmlUrlServiceAPI : 'http%253A%252F%252Fcv.uoc.edu%252Fwebapps%252Fclassroom%252Fservlet%252FGroupServlet%253FdtId%253DDOMAIN',
		up_target:'aula.jsp',
		up_dCode: 'aula.code',
		fromCampus:'true',
		lang:'es',
		country:'ES',
		hp_theme:'false'
	}
	$.get('http://cv.uoc.edu/webapps/widgetsUOC/widgetsDominisServlet?'+map2string(args), function(resp) {
		var index = resp.indexOf('<div class="agora identifica');
		if (index != -1) {
			aula.mc_icon=resp.substring(index+31)
			var tag = aula.mc_icon[aula.mc_icon.indexOf('src')+4]
			aula.mc_icon=aula.mc_icon.substring(aula.mc_icon.indexOf('src')+5)
			aula.mc_icon=aula.mc_icon.substring(0,aula.mc_icon.indexOf(tag))
			//saveAula(aula)
		}
	});
}
function doLogin(){
	console.log("enter::doLogin");
	currentAulas=null;
	iconUnread(0);
	if( settings.get("username") == null ||  settings.get("username") == "" ){
		return;
	}
	if( settings.get("password") == null ||  settings.get("password") == "" ){
		return;
	}
	$.ajax({
		type:"POST",
		beforeSend: function (request){
			request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		},
		url: "http://cv.uoc.edu/cgi-bin/uoc",
		data: map2string({
			l:settings.get("username"),
			p:settings.get("password"),
			appid:"WUOC",
			nil:"XXXXXX",
			lb:"a",
			url:"http://cv.uoc.edu",
			x:"13",
			y:"2"
		}),
		processData: false,
		success: function(resp) {
			var iSs = resp.indexOf("?s=");
			if( iSs != -1 ){
				var	iSf = resp.indexOf("\";", iSs);
				sessionId = resp.substring(iSs + 3, iSf);
				onLogin();
			}else{
				onLoginError();
			}
		}
    });
	console.log("exit::doLogin");
}

function onLogin(){
	getHomePage();
	getPersonalMessages()
}

function getHomePage(){
	var args = {
		s : sessionId,
		newStartingPage:0,
		language:"b"
	}
	$.get('http://cv.uoc.edu/UOC2000/b/cgi-bin/hola?'+map2string(args), function(resp) {
		var index = resp.indexOf("aulas = ");
		if (index != -1) {
			lastPage = resp.substring(index + 8);
			var last = lastPage.indexOf(";");
			lastPage = lastPage.substring(0,last);
			var tmp = eval(lastPage);
			var resources = [];
			for(var i in tmp){
				if( tmp[i].title && tmp[i].resources && (tmp[i].domaintypeid=='AULA'||tmp[i].domaintypeid=='TUTORIA')){
					getPicture(tmp[i]);
					resources.push(tmp[i])
				}
			}
			console.log(resources);
			resourcesLoaded( resources )
		}
		homePageInterval = setTimeout(getHomePage,1000*60);
		checkMinimumReachedInterval = setTimeout(checkMinimumReached,5*1000*60);
	});
}

function onLoginError(){
	loginInterval = setTimeout(doLogin,1000*60*5);
	notifyLoginError();
}

function getPersonalMessages(){
	console.log("Entering getPersonalMessages()");

	personalMailbox = {};

	$.ajax({
		url: "http://cv.uoc.edu/WebMail/attach.do",
		type: 'get',
		async:'false',
		data: {s: sessionId},
		success: function(data){

			var search = 'totalNewMsgs';
			var index = data.indexOf(search);
			index = data.indexOf(search, index+1);
			var firstIndex = index+search.length;
			var lastIndex = data.indexOf(",", firstIndex);
			var newMsgs = data.substring(firstIndex, lastIndex).replace('\\":', '');

			search = 'totalMsgs';
			index = data.indexOf(search);
			index = data.indexOf(search, index+1);
			firstIndex = index+search.length;
			lastIndex = data.indexOf(",", firstIndex);

			var totalMsgs = data.substring(firstIndex, lastIndex).replace('\\":', '');

			search = 'mailS';
			index = data.indexOf(search);
			index = data.indexOf(search, index+1);
			firstIndex = index+search.length;
			lastIndex = data.indexOf("/>", firstIndex);

			var image = data.substring(firstIndex, lastIndex).replace("'", '');

			var parts = image.split('|');
			if(parts.length > 1){
				parts = parts[0].split('[');
				if(parts.length > 1){
					image = "http://cv.uoc.edu/UOC2000/mc-icons/fotos/##username##.jpg?s=##session##".replace("##username##", $.trim(parts[1])).replace("##session##", sessionId);

				} else {
					image = '';
				}
			} else {
				image = '';
			}

			personalMailbox.domaintypeid = 'BUZONPERSONAL';
			personalMailbox.resources = [];

			var res = {};
			res.title = 'Buzón Personal';
			res.unread = newMsgs;
			res.numMesPend = newMsgs;
			res.totals = totalMsgs;
			personalMailbox.resources.push(res);
			personalMailbox.mc_icon = image;

			personalBuzonInterval = setTimeout(getPersonalMessages,1000*60*10);
		},
		error: function(){
			console.log("Error obteniendo mensajes personales");
		}
	});

}

function resourcesLoaded( resources ){
	currentAulas = resources;
	iconUnread(0);
	unReadMsg=0;
	for(var a in resources){
		if( !settings.get(resources[a].code+"_notificar") && resources[a].domaintypeid != 'BUZONPERSONAL' ){
			console.log("resourceLoaded:notificar false "+resources[a].code);
			resources[a].notificar = false
			continue;
		}
		var tmpacum=0;
		for(var j in resources[a].resources){
			resources[a].resources[j].numMesPend |= 0;
			unReadMsg += resources[a].resources[j].numMesPend;
			if( resources[a].resources[j].numMesPend ){
				console.log(resources[a].resources[j]);
				tmpacum+=resources[a].resources[j].numMesPend
			}
		}
		resources[a].numMesPend=tmpacum;
	}
	iconUnread(unReadMsg);
}

function checkMinimumReached(){
	if( !settings.get("emergentes") ){
		console.log("end:resourcesLoaded no emergentes")
		return;
	}
	if( settings.get("minimo") >= unReadMsg ){
		notifyMinimumReached(unReadMsg);
	}
	console.log("end:resourcesLoaded")
}

function notifyLoginError(){
	console.log("Login error");
	var notification = window.webkitNotifications.createNotification(
		'/icons/logo_puravida_color.png',                      // The image.
		nowToStr(), // The title.
		i18n.get("login_error")      // The body.
	);
	notification.show();
	setTimeout( function(){
		notification.cancel();
		notification=null;
	},1000*3);
}

function iconUnread(unread){
	console.log("iconUnread:"+unread)
	if(unread){
		chrome.browserAction.setIcon({path:"/icons/logomsg.png"});
		chrome.browserAction.setBadgeText({text:""+unread});
	}else{
		chrome.browserAction.setIcon({path:"/icons/logo.png"});
		chrome.browserAction.setBadgeText({text:""});
	}
}

function notifyMinimumReached(acum){
	if(!acum) return;
	var notification = window.webkitNotifications.createNotification(
		'/icons/logo_puravida_color.png',                      // The image.
		nowToStr(), // The title.
		i18n.get("unread") + ":"+acum     // The body.
	);
	notification.show();
	setTimeout( function(){
		notification.cancel();
		notification=null;
	},1000*3);
}

function hasUnreadMessages(aula){
	var unread = 0;
	for(var r in aula.resources){
		if(parseInt(aula.resources[r].unread))
			unread = unread + parseInt(aula.resources[r].unread);
	}
	return unread;
}

chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
	if( request.uocrequest ){
		if( request.uocrequest == "refresh" ){
			doLogin();
		}

		if( request.uocrequest == "session" ){
			sendResponse({session:sessionId});
		}

		if( request.uocrequest == "aulas" ){
			console.log("uocrequest:aulas="+currentAulas);
			sendResponse({
				session:sessionId,
				unReadMsg : unReadMsg,
				aulas:currentAulas,
				personalMailbox:personalMailbox
			});
		}

		if(request.uocrequest == "openunread"){
			for(var r in currentAulas){
				if(hasUnreadMessages(currentAulas[r])){
						var newURL = '';
						if(currentAulas[r].domaintypeid == "BUZONPERSONAL"){
							newURL = "http://cv.uoc.edu/WebMail/attach.do?s="+sessionId;
						} else {
							newURL = "http://cv.uoc.edu/webapps/classroom/"+currentAulas[r].pt_template+"/frameset.jsp?domainCode="+currentAulas[r].code+"&s="+sessionId;
						}
						chrome.tabs.create({ url: newURL });
				}
			}
		}
	}
  });

// Por ultimo desencadenamos el proceso de login
loginInterval = setTimeout(doLogin,1000);<commit_msg>reintentar login transcurrido un tiempo si ha habido error de red<commit_after>var settings = new Store("settings");
var sesionId;
var loginInterval,homePageInterval,checkMinimumReachedInterval ;
var currentAulas;
var unReadMsg=0;
var personalMailbox = {};

function map2string(map){
	var str = "";
	for(var v in map){
		str += v+"="+map[v]+"&";
	}
	return str;
}

function nowToStr(){
	var time = /(..)(:..)/.exec(new Date());     // The prettyprinted time.
	var hour = time[1] % 12 || 12;               // The prettyprinted hour.
	var period = time[1] < 12 ? 'a.m.' : 'p.m.'; // The period of the day.
	return hour + time[2] + ' ' + period;
}
function getPicture(aula){
	var args = {
		s : sessionId,
		param : 'dCode%3D'+aula.code,
		up_xmlUrlServiceAPI : 'http%253A%252F%252Fcv.uoc.edu%252Fwebapps%252Fclassroom%252Fservlet%252FGroupServlet%253FdtId%253DDOMAIN',
		up_target:'aula.jsp',
		up_dCode: 'aula.code',
		fromCampus:'true',
		lang:'es',
		country:'ES',
		hp_theme:'false'
	}
	$.get('http://cv.uoc.edu/webapps/widgetsUOC/widgetsDominisServlet?'+map2string(args), function(resp) {
		var index = resp.indexOf('<div class="agora identifica');
		if (index != -1) {
			aula.mc_icon=resp.substring(index+31)
			var tag = aula.mc_icon[aula.mc_icon.indexOf('src')+4]
			aula.mc_icon=aula.mc_icon.substring(aula.mc_icon.indexOf('src')+5)
			aula.mc_icon=aula.mc_icon.substring(0,aula.mc_icon.indexOf(tag))
			//saveAula(aula)
		}
	});
}
function doLogin(){
	console.log("enter::doLogin");
	currentAulas=null;
	iconUnread(0);
	if( settings.get("username") == null ||  settings.get("username") == "" ){
		return;
	}
	if( settings.get("password") == null ||  settings.get("password") == "" ){
		return;
	}
	$.ajax({
		type:"POST",
		beforeSend: function (request){
			request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		},
		url: "http://cv.uoc.edu/cgi-bin/uoc",
		data: map2string({
			l:settings.get("username"),
			p:settings.get("password"),
			appid:"WUOC",
			nil:"XXXXXX",
			lb:"a",
			url:"http://cv.uoc.edu",
			x:"13",
			y:"2"
		}),
		processData: false,
		success: function(resp) {
			var iSs = resp.indexOf("?s=");
			if( iSs != -1 ){
				var	iSf = resp.indexOf("\";", iSs);
				sessionId = resp.substring(iSs + 3, iSf);
				onLogin();
			}else{
				onLoginError();
			}
		},
		error: function(){
			onLoginError();
		}
    });
	console.log("exit::doLogin");
}

function onLogin(){
	getHomePage();
	getPersonalMessages()
}

function getHomePage(){
	var args = {
		s : sessionId,
		newStartingPage:0,
		language:"b"
	}
	$.get('http://cv.uoc.edu/UOC2000/b/cgi-bin/hola?'+map2string(args), function(resp) {
		var index = resp.indexOf("aulas = ");
		if (index != -1) {
			lastPage = resp.substring(index + 8);
			var last = lastPage.indexOf(";");
			lastPage = lastPage.substring(0,last);
			var tmp = eval(lastPage);
			var resources = [];
			for(var i in tmp){
				if( tmp[i].title && tmp[i].resources && (tmp[i].domaintypeid=='AULA'||tmp[i].domaintypeid=='TUTORIA')){
					getPicture(tmp[i]);
					resources.push(tmp[i])
				}
			}
			console.log(resources);
			resourcesLoaded( resources )
		}
		homePageInterval = setTimeout(getHomePage,1000*60);
		checkMinimumReachedInterval = setTimeout(checkMinimumReached,5*1000*60);
	});
}

function onLoginError(){
	loginInterval = setTimeout(doLogin,1000*60*5);
	notifyLoginError();
}

function getPersonalMessages(){
	console.log("Entering getPersonalMessages()");

	personalMailbox = {};

	$.ajax({
		url: "http://cv.uoc.edu/WebMail/attach.do",
		type: 'get',
		async:'false',
		data: {s: sessionId},
		success: function(data){

			var search = 'totalNewMsgs';
			var index = data.indexOf(search);
			index = data.indexOf(search, index+1);
			var firstIndex = index+search.length;
			var lastIndex = data.indexOf(",", firstIndex);
			var newMsgs = data.substring(firstIndex, lastIndex).replace('\\":', '');

			search = 'totalMsgs';
			index = data.indexOf(search);
			index = data.indexOf(search, index+1);
			firstIndex = index+search.length;
			lastIndex = data.indexOf(",", firstIndex);

			var totalMsgs = data.substring(firstIndex, lastIndex).replace('\\":', '');

			search = 'mailS';
			index = data.indexOf(search);
			index = data.indexOf(search, index+1);
			firstIndex = index+search.length;
			lastIndex = data.indexOf("/>", firstIndex);

			var image = data.substring(firstIndex, lastIndex).replace("'", '');

			var parts = image.split('|');
			if(parts.length > 1){
				parts = parts[0].split('[');
				if(parts.length > 1){
					image = "http://cv.uoc.edu/UOC2000/mc-icons/fotos/##username##.jpg?s=##session##".replace("##username##", $.trim(parts[1])).replace("##session##", sessionId);

				} else {
					image = '';
				}
			} else {
				image = '';
			}

			personalMailbox.domaintypeid = 'BUZONPERSONAL';
			personalMailbox.resources = [];

			var res = {};
			res.title = 'Buzón Personal';
			res.unread = newMsgs;
			res.numMesPend = newMsgs;
			res.totals = totalMsgs;
			personalMailbox.resources.push(res);
			personalMailbox.mc_icon = image;

			personalBuzonInterval = setTimeout(getPersonalMessages,1000*60*10);
		},
		error: function(){
			console.log("Error obteniendo mensajes personales");
		}
	});

}

function resourcesLoaded( resources ){
	currentAulas = resources;
	iconUnread(0);
	unReadMsg=0;
	for(var a in resources){
		if( !settings.get(resources[a].code+"_notificar") && resources[a].domaintypeid != 'BUZONPERSONAL' ){
			console.log("resourceLoaded:notificar false "+resources[a].code);
			resources[a].notificar = false
			continue;
		}
		var tmpacum=0;
		for(var j in resources[a].resources){
			resources[a].resources[j].numMesPend |= 0;
			unReadMsg += resources[a].resources[j].numMesPend;
			if( resources[a].resources[j].numMesPend ){
				console.log(resources[a].resources[j]);
				tmpacum+=resources[a].resources[j].numMesPend
			}
		}
		resources[a].numMesPend=tmpacum;
	}
	iconUnread(unReadMsg);
}

function checkMinimumReached(){
	if( !settings.get("emergentes") ){
		console.log("end:resourcesLoaded no emergentes")
		return;
	}
	if( settings.get("minimo") >= unReadMsg ){
		notifyMinimumReached(unReadMsg);
	}
	console.log("end:resourcesLoaded")
}

function notifyLoginError(){
	console.log("Login error");
	var notification = window.webkitNotifications.createNotification(
		'/icons/logo_puravida_color.png',                      // The image.
		nowToStr(), // The title.
		i18n.get("login_error")      // The body.
	);
	notification.show();
	setTimeout( function(){
		notification.cancel();
		notification=null;
	},1000*3);
}

function iconUnread(unread){
	console.log("iconUnread:"+unread)
	if(unread){
		chrome.browserAction.setIcon({path:"/icons/logomsg.png"});
		chrome.browserAction.setBadgeText({text:""+unread});
	}else{
		chrome.browserAction.setIcon({path:"/icons/logo.png"});
		chrome.browserAction.setBadgeText({text:""});
	}
}

function notifyMinimumReached(acum){
	if(!acum) return;
	var notification = window.webkitNotifications.createNotification(
		'/icons/logo_puravida_color.png',                      // The image.
		nowToStr(), // The title.
		i18n.get("unread") + ":"+acum     // The body.
	);
	notification.show();
	setTimeout( function(){
		notification.cancel();
		notification=null;
	},1000*3);
}

function hasUnreadMessages(aula){
	var unread = 0;
	for(var r in aula.resources){
		if(parseInt(aula.resources[r].unread))
			unread = unread + parseInt(aula.resources[r].unread);
	}
	return unread;
}

chrome.extension.onMessage.addListener(
  function(request, sender, sendResponse) {
	if( request.uocrequest ){
		if( request.uocrequest == "refresh" ){
			doLogin();
		}

		if( request.uocrequest == "session" ){
			sendResponse({session:sessionId});
		}

		if( request.uocrequest == "aulas" ){
			console.log("uocrequest:aulas="+currentAulas);
			sendResponse({
				session:sessionId,
				unReadMsg : unReadMsg,
				aulas:currentAulas,
				personalMailbox:personalMailbox
			});
		}

		if(request.uocrequest == "openunread"){
			for(var r in currentAulas){
				if(hasUnreadMessages(currentAulas[r])){
						var newURL = '';
						if(currentAulas[r].domaintypeid == "BUZONPERSONAL"){
							newURL = "http://cv.uoc.edu/WebMail/attach.do?s="+sessionId;
						} else {
							newURL = "http://cv.uoc.edu/webapps/classroom/"+currentAulas[r].pt_template+"/frameset.jsp?domainCode="+currentAulas[r].code+"&s="+sessionId;
						}
						chrome.tabs.create({ url: newURL });
				}
			}
		}
	}
  });

// Por ultimo desencadenamos el proceso de login
loginInterval = setTimeout(doLogin,1000);<|endoftext|>