<commit_before>// eslint-disable-next-line no-unused-vars
const store = {
  _websites: null,

  async init() {
    if (!this._websites) {
      const data = await browser.storage.local.get('websites');

      if (data.websites) {
        this._websites = clone(data.websites);
      }
    }
    browser.runtime.onMessage.addListener((m) => store.messageHandler(m));
  },

  // send message to storeChild when data in store is changed
  updateChild(...args) {
    return browser.runtime.sendMessage({
      type: 'storeChildCall',
      args
    });
  },

  messageHandler(m) {
    if (m.type !== 'storeCall') {
      return;
    }

    const publicMethods = [
      'getAll',
      'reset',
    ];

    if (publicMethods.includes(m['method'])) {
      const args = m.args;
      return this[m['method']](...args);
    } else {
      return new Error(`Unsupported method ${m.method}`);
    }
  },

  async _write(websites) {
    this._websites = clone(websites);

    return await browser.storage.local.set({ websites });
  },

  outputWebsite(hostname, website) {
    const output = {
      hostname: hostname,
      favicon: website.faviconUrl || '',
      firstPartyHostnames: website.firstPartyHostnames || false,
      firstParty: false,
      thirdParties: []
    };
    if (website.firstPartyHostnames === undefined) {
      output.firstParty = true;
      if ('thirdPartyHostnames' in website) {
        output.thirdParties = website.thirdPartyHostnames;
      } else {
        output.thirdParties = [];
      }
    }
    return output;
  },

  getAll() {
    const output = {};
    for (const hostname in this._websites) {
      const website = this._websites[hostname];
      output[hostname] = this.outputWebsite(hostname, website);
    }
    return Promise.resolve(output);
  },

  getWebsite(hostname) {
    if (!hostname) {
      throw new Error('getWebsite requires a valid hostname argument');
    }

    return this._websites[hostname];
  },

  getThirdParties(hostname) {
    if (!hostname) {
      throw new Error('getThirdParties requires a valid hostname argument');
    }

    const firstParty = this.getWebsite(hostname);
    if ('thirdPartyHostnames' in firstParty) {
      return firstParty.thirdPartyHostnames;
    }

    return null;
  },

  setWebsite(hostname, data) {
    let newSite = false;

    const websites = clone(this._websites);

    if (!websites[hostname]) {
      newSite = true;
      websites[hostname] = {};
    }

    for (const key in data) {
      websites[hostname][key] = data[key];
    }

    this._write(websites);

    if (newSite) {
      this.updateChild(this.outputWebsite(hostname, websites[hostname]));
    }
  },

  setFirstParty(hostname, data) {
    if (!hostname) {
      throw new Error('setFirstParty requires a valid hostname argument');
    }
    this.setWebsite(hostname, data);
  },

  setThirdParty(origin, target, data) {
    let newThirdParty = false;
    if (!origin) {
      throw new Error('setThirdParty requires a valid origin argument');
    }

    const firstParty = this.getWebsite(origin) || {};
    const thirdParty = this.getWebsite(target) || {};
    if (!('thirdPartyHostnames' in firstParty)) {
      firstParty['thirdPartyHostnames'] = [];
    }
    if (!firstParty['thirdPartyHostnames'].includes(target)) {
      firstParty['thirdPartyHostnames'].push(target);
      newThirdParty = true;
    }
    if (!('firstPartyHostnames' in firstParty)) {
      thirdParty['firstPartyHostnames'] = [];
    }
    if (!thirdParty['firstPartyHostnames'].includes(origin)) {
      thirdParty['firstPartyHostnames'].push(origin);
      newThirdParty = true;
    }

    this.setWebsite(origin, firstParty);
    this.setWebsite(target, thirdParty);

    if (newThirdParty) {
      this.updateChild(this.outputWebsite(target, data, origin));
    }
  },

  async reset() {
    this._websites = null;

    return await browser.storage.local.remove('websites');
  }
};

// @todo move this function to utils
function clone(obj) {
  return Object.assign({}, obj);
}
// @todo end

store.init();
<commit_msg>Fix store.getWebsite method<commit_after>// eslint-disable-next-line no-unused-vars
const store = {
  _websites: null,

  async init() {
    if (!this._websites) {
      const data = await browser.storage.local.get('websites');

      if (data.websites) {
        this._websites = clone(data.websites);
      }
    }
    browser.runtime.onMessage.addListener((m) => store.messageHandler(m));
  },

  // send message to storeChild when data in store is changed
  updateChild(...args) {
    return browser.runtime.sendMessage({
      type: 'storeChildCall',
      args
    });
  },

  messageHandler(m) {
    if (m.type !== 'storeCall') {
      return;
    }

    const publicMethods = [
      'getAll',
      'reset',
    ];

    if (publicMethods.includes(m['method'])) {
      const args = m.args;
      return this[m['method']](...args);
    } else {
      return new Error(`Unsupported method ${m.method}`);
    }
  },

  async _write(websites) {
    this._websites = clone(websites);

    return await browser.storage.local.set({ websites });
  },

  outputWebsite(hostname, website) {
    const output = {
      hostname: hostname,
      favicon: website.faviconUrl || '',
      firstPartyHostnames: website.firstPartyHostnames || false,
      firstParty: false,
      thirdParties: []
    };
    if (website.firstPartyHostnames === undefined) {
      output.firstParty = true;
      if ('thirdPartyHostnames' in website) {
        output.thirdParties = website.thirdPartyHostnames;
      } else {
        output.thirdParties = [];
      }
    }
    return output;
  },

  getAll() {
    const output = {};
    for (const hostname in this._websites) {
      const website = this._websites[hostname];
      output[hostname] = this.outputWebsite(hostname, website);
    }
    return Promise.resolve(output);
  },

  getWebsite(hostname) {
    if (!hostname) {
      throw new Error('getWebsite requires a valid hostname argument');
    }
    if (this._websites && this._websites[hostname]) {
      return this._websites[hostname];
    } else {
      return {};
    }
  },

  getThirdParties(hostname) {
    if (!hostname) {
      throw new Error('getThirdParties requires a valid hostname argument');
    }

    const firstParty = this.getWebsite(hostname);
    if ('thirdPartyHostnames' in firstParty) {
      return firstParty.thirdPartyHostnames;
    }

    return null;
  },

  setWebsite(hostname, data) {
    let newSite = false;

    const websites = clone(this._websites);

    if (!websites[hostname]) {
      newSite = true;
      websites[hostname] = {};
    }

    for (const key in data) {
      websites[hostname][key] = data[key];
    }

    this._write(websites);

    if (newSite) {
      this.updateChild(this.outputWebsite(hostname, websites[hostname]));
    }
  },

  setFirstParty(hostname, data) {
    if (!hostname) {
      throw new Error('setFirstParty requires a valid hostname argument');
    }
    this.setWebsite(hostname, data);
  },

  setThirdParty(origin, target, data) {
    let newThirdParty = false;
    if (!origin) {
      throw new Error('setThirdParty requires a valid origin argument');
    }

    const firstParty = this.getWebsite(origin);
    const thirdParty = this.getWebsite(target);

    if (!('thirdPartyHostnames' in firstParty)) {
      firstParty['thirdPartyHostnames'] = [];
    }
    if (!firstParty['thirdPartyHostnames'].includes(target)) {
      firstParty['thirdPartyHostnames'].push(target);
      newThirdParty = true;
    }
    if (!('firstPartyHostnames' in firstParty)) {
      thirdParty['firstPartyHostnames'] = [];
    }
    if (!thirdParty['firstPartyHostnames'].includes(origin)) {
      thirdParty['firstPartyHostnames'].push(origin);
      newThirdParty = true;
    }

    this.setWebsite(origin, firstParty);
    this.setWebsite(target, thirdParty);

    if (newThirdParty) {
      this.updateChild(this.outputWebsite(target, data, origin));
    }
  },

  async reset() {
    this._websites = null;

    return await browser.storage.local.remove('websites');
  }
};

// @todo move this function to utils
function clone(obj) {
  return Object.assign({}, obj);
}

store.init();
<|endoftext|>


<commit_before>App = {
    debug: true,
    R: null,
    init: function() {
        this.bind();
    },
    bind: function() {
        var that = this;
        $('#parse').click(function(e) {
            var s = $('#stage').val()
            if (s == '')
                return;
            $('#log').empty();
            var tree = syntax_tree(s);
            1+1==2;
        });
    },
    log: function(msg) {
        msg = msg.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
        $('#log').append(msg + '
');
    },
};

Tree = {
    h_space: 50, /* Horizontal space between sibling nodes */
    v_space: 60, /* Vertical space between levels */
    padding_bottom: 5, /* Space below the text for the lines */
    padding_top: 5,
};

function Node() {
    this.parent = null;

    this.has_children = null;
    this.children = new Array();
    this.first = null;
    this.last = null;
    /* Siblings */
    this.previous = null;
    this.next = null;

    /* Coordinates for the center of the node's text element */
    this.x = null;
    this.y = null;

    this.child_step = null;
    this.left_width = null;
    this.right_width = null;

    this.caret = null; /* true if the element has a caret indicating a triangle */
    this.draw_triangle = null; /* true if this is the child of a caret node */
    this.tail = null;

    this.text = null; /* Raphael text element */
    this.value = null;
    this.features = null;
};

function syntax_tree(s) {
    var t = parse(s);
    t.relate(null);
    t.check_triangles();

    if (App.R)
        App.R.clear();
    else
        App.R = new Raphael('canvas-container', 500, 500);
    var R = App.R;
    R.setStart();

    t.set_width();
    t.assign_location(0, 0);
    t.draw_tree_lines();

    /* Move the entire tree */
    var set = R.setFinish();
    set.translate(t.left_width + Tree.h_space, Tree.v_space);

    /* Resize the paper so it can show the entire tree */
    R.setSize(t.left_width + (2*Tree.h_space) + t.right_width, 500);
    return t;
};

function text_element(n) {
    var text = App.R.text(0, 0, n.value);
    text.attr({
        'font-size': 16,
    });
    return text;
};

/* Get the y coordinate over this node */
Node.prototype.top_y = function() {
    return Math.floor(this.y - (this.text.getBBox().height / 2) - Tree.padding_top) + 0.5;
};

/* Get the y coordinate under this node */
Node.prototype.bottom_y = function() {
    return Math.floor(this.y + (this.text.getBBox().height / 2) + Tree.padding_bottom) + 0.5;
};

/* Mark nodes under a triangle */
Node.prototype.check_triangles = function() {
    this.draw_triangle = false;
    if ((!this.has_children) && (this.parent.caret))
        this.draw_triangle = true;

    for (var child = this.first; child != null; child = child.next)
        child.check_triangles();
};

/* Traverse the tree post-order and draw the lines connecting each node with
 * its parent */
Node.prototype.draw_tree_lines = function() {
    for (var child = this.first; child != null; child = child.next)
        child.draw_tree_lines();

    /* Do nothing for the root node */
    if (!this.parent) return;

    if (this.draw_triangle) {
        var from = 'M' + this.parent.x + ',' + this.parent.bottom_y();
        var to1 = 'L' + (this.x - this.left_width) + ',' + this.top_y();
        var to2 = 'L' + (this.x + this.right_width) + ',' + this.top_y();
        var to3 = from.replace(/M/, 'L');
        App.R.path(from + to1 + to2 + to3);
        return;
    }

    /* Regular line to the parent */
    var from = 'M' + this.parent.x + ',' + this.parent.bottom_y();
    var to = 'L' + this.x + ',' + this.top_y();
    App.R.path(from + to);
};

/* Traverse the tree post-order, set the location of each children according to
 * the step value found in set_width */
Node.prototype.assign_location = function(x, y) {
    this.x = Math.floor(x) + 0.5;
    this.y = Math.floor(y) + 0.5;

    this.text.transform(['T' + x + ',' + y]);

    /* Treat x = 0 as the center of the canvas because we'll transpose it later */
    if (this.has_children) {
        var left_start = x - (this.step * (this.children.length-1) / 2);
        for (var i = 0; i < this.children.length; i++)
            this.children[i].assign_location(left_start + i*(this.step), y + Tree.v_space);
    }
};

/* Traverse the tree post-order, set the space on each side of a node */
Node.prototype.set_width = function() {
    this.text = text_element(this);
    var text_width = this.text.getBBox().width;

    for (var child = this.first; child != null; child = child.next)
        child.set_width();

    /* As leaf nodes are not affected by children, their width is just
     * that of its text (TODO: Measure features, get max) */
    if (!this.has_children) {
        this.left_width = text_width / 2;
        this.right_width = text_width / 2;
        return;
    }

    /* Space between children's centers is the max one so they're all
     * equally separated. */
    this.step = 0;
    for (var child = this.first; (child != null) && (child.next != null); child = child.next) {
        var space = child.right_width + Tree.h_space + child.next.left_width;
        this.step = Math.max(this.step, space);
    }

    /* Parent width itself is defined by the widths of all its children */
    this.left_width = 0.0;
    this.right_width = 0.0;

    /* childs - 1 because we need the sections, not the fence posts.
     * We get the distance from the first-center to the last-center, so
     * we need to add the left and right widths respectively. */
    var children_width = ((this.children.length - 1) * this.step) / 2;
    this.left_width = children_width + this.first.left_width;
    this.right_width = children_width + this.last.right_width;

    /* Check if this node isn't wider than all of its children */
    this.left_width = Math.max(this.left_width, text_width / 2);
    this.right_width = Math.max(this.right_width, text_width / 2);
};

/* Sets parent and sibling nodes for a given (sub)tree */
Node.prototype.relate = function(parent) {
    this.parent = parent;
    this.has_children = (this.children.length > 0);

    if (this.has_children) {
        this.first = this.children[0];
        this.last = this.children[this.children.length - 1];
    }

    for (var i = 0; i < this.children.length; i++)
        this.children[i].relate(this);

    for (var i = 0; i < this.children.length - 1; i++)
        this.children[i].next = this.children[i+1];

    for (var i = 1; i < this.children.length; i++)
        this.children[i].previous = this.children[i-1];
};

function subscript(s) {
    var out = '';
    for (var i = 0; i < s.length; i++) {
        switch (s[i]) {
            case '0': out = out + '₀'; break;
            case '1': out = out + '₁'; break;
            case '2': out = out + '₂'; break;
            case '3': out = out + '₃'; break;
            case '4': out = out + '₄'; break;
            case '5': out = out + '₅'; break;
            case '6': out = out + '₆'; break;
            case '7': out = out + '₇'; break;
            case '8': out = out + '₈'; break;
            case '9': out = out + '₉'; break;
        }
    }
    return out;
};

function parse(s) {
    App.log('Parsing ' + s);
    var n = new Node();

    if (s[0] != '[') {
        /* Search for movement information */
        s = s.replace(/\s*<(\w+)>\s*/, function(match, tail) {
            n.tail = tail;
            App.log('Found tail: ' + tail);
            return ' ';
        });
        s = s.replace(/^\s+|\s+$/g, '');
        /* Search for features on this text node */
        var i = 0;
        while ((i < s.length) && (s[i] != '(')) i++;
        n.value = s.substring(0, i); /* Save the text node */

        if (s[i] == '(') {
            var start = i+1;
            while ((s[i] != ')')) i++;
            n.features = s.substring(start, i);
            App.log('Parsed features: ' + n.features);
        }
        return n;
    }

    /* Parse the category label */
    var i = 1;
    while ((s[i] != ' ') && (s[i] != '[') && (s[i] != ']')) i++;
    n.value = s.substring(1, i);
    /* Triangle-parent node */
    n.value = n.value.replace(/\^/, function() {
        n.caret = true;
        return '';
    });
    /* Label */
    n.value = n.value.replace(/_(\w+)$/, function(match, label) {
        App.log('Parsed label: ' + label);
        n.label = label;
        if (n.label.search(/^\d+$/) != -1)
            return subscript(n.label);
        return '';
    });
    App.log('Parsed first token: ' + n.value);

    while (s[i] == ' ') i++;
    var level = 1,
        start = i;
    for (; i < s.length; i++) {
        var outer_level = level;
        if (s[i] == '[') level++;
        if (s[i] == ']') level--;

        if (((outer_level == 1) && (level == 2)) || ((outer_level == 1) && (level == 0))) {
            /* Handle word token */
            if (s.substring(start, i).search(/\w+/) > -1)
               n.children.push(parse(s.substring(start, i)));
            start = i;
        }
        /* Parse an inside bracket group */
        if ((outer_level == 2) && (level == 1)) {
            n.children.push(parse(s.substring(start, i+1)));
            /* Otherwise we get the closing ] again and an extra level-- */
            start = i+1;
        }
    }
    return n;
};

$(function() {
    App.init();
});
<commit_msg>Find tree height and use it to adjust the height of the canvas.<commit_after>App = {
    debug: true,
    R: null,
    init: function() {
        this.bind();
    },
    bind: function() {
        var that = this;
        $('#parse').click(function(e) {
            var s = $('#stage').val()
            if (s == '')
                return;
            $('#log').empty();
            var tree = syntax_tree(s);
            1+1==2;
        });
    },
    log: function(msg) {
        msg = msg.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
        $('#log').append(msg + '
');
    },
};

Tree = {
    h_space: 50, /* Horizontal space between sibling nodes */
    v_space: 60, /* Vertical space between levels */
    padding_bottom: 5, /* Space below the text for the lines */
    padding_top: 5,
};

function Node() {
    this.parent = null;

    this.has_children = null;
    this.children = new Array();
    this.first = null;
    this.last = null;
    /* Siblings */
    this.previous = null;
    this.next = null;

    /* Coordinates for the center of the node's text element */
    this.x = null;
    this.y = null;

    this.max_y = null;
    this.child_step = null;
    this.left_width = null;
    this.right_width = null;

    this.caret = null; /* true if the element has a caret indicating a triangle */
    this.draw_triangle = null; /* true if this is the child of a caret node */
    this.tail = null;
    this.label = null;

    this.text = null; /* Raphael text element */
    this.value = null;
    this.features = null;
};

/* Get the y coordinate over this node */
Node.prototype.top_y = function() {
    return Math.floor(this.y - (this.text.getBBox().height / 2) - Tree.padding_top) + 0.5;
};

/* Get the y coordinate under this node */
Node.prototype.bottom_y = function() {
    return Math.floor(this.y + (this.text.getBBox().height / 2) + Tree.padding_bottom) + 0.5;
};

/* Mark nodes under a triangle */
Node.prototype.check_triangles = function() {
    this.draw_triangle = false;
    if ((!this.has_children) && (this.parent.caret))
        this.draw_triangle = true;

    for (var child = this.first; child != null; child = child.next)
        child.check_triangles();
};

/* Traverse the tree post-order and draw the lines connecting each node with
 * its parent */
Node.prototype.draw_tree_lines = function() {
    for (var child = this.first; child != null; child = child.next)
        child.draw_tree_lines();

    /* Do nothing for the root node */
    if (!this.parent) return;

    if (this.draw_triangle) {
        var from = 'M' + this.parent.x + ',' + this.parent.bottom_y();
        var to1 = 'L' + (this.x - this.left_width) + ',' + this.top_y();
        var to2 = 'L' + (this.x + this.right_width) + ',' + this.top_y();
        var to3 = from.replace(/M/, 'L');
        App.R.path(from + to1 + to2 + to3);
        return;
    }

    /* Regular line to the parent */
    var from = 'M' + this.parent.x + ',' + this.parent.bottom_y();
    var to = 'L' + this.x + ',' + this.top_y();
    App.R.path(from + to);
};

/* Traverse the tree post-order, set the location of each children according to
 * the step value found in set_width */
Node.prototype.assign_location = function(x, y) {
    this.x = Math.floor(x) + 0.5;
    this.y = Math.floor(y) + 0.5;

    this.text.transform(['T' + x + ',' + y]);

    /* Treat x = 0 as the center of the canvas because we'll transpose it later */
    if (this.has_children) {
        var left_start = x - (this.step * (this.children.length-1) / 2);
        for (var i = 0; i < this.children.length; i++)
            this.children[i].assign_location(left_start + i*(this.step), y + Tree.v_space);
    }
};

/* Find the greatest y-position in the tree, to measure its entire height */
Node.prototype.find_height = function() {
    this.max_y = this.y;
    for (var child = this.first; child != null; child = child.next)
        this.max_y = Math.max(this.max_y, child.find_height());
    return this.max_y;
};

/* Traverse the tree post-order, set the space on each side of a node */
Node.prototype.set_width = function() {
    this.text = text_element(this);
    var text_width = this.text.getBBox().width;

    for (var child = this.first; child != null; child = child.next)
        child.set_width();

    /* As leaf nodes are not affected by children, their width is just
     * that of its text (TODO: Measure features, get max) */
    if (!this.has_children) {
        this.left_width = text_width / 2;
        this.right_width = text_width / 2;
        return;
    }

    /* Space between children's centers is the max one so they're all
     * equally separated. */
    this.step = 0;
    for (var child = this.first; (child != null) && (child.next != null); child = child.next) {
        var space = child.right_width + Tree.h_space + child.next.left_width;
        this.step = Math.max(this.step, space);
    }

    /* Parent width itself is defined by the widths of all its children */
    this.left_width = 0.0;
    this.right_width = 0.0;

    /* childs - 1 because we need the sections, not the fence posts.
     * We get the distance from the first-center to the last-center, so
     * we need to add the left and right widths respectively. */
    var children_width = ((this.children.length - 1) * this.step) / 2;
    this.left_width = children_width + this.first.left_width;
    this.right_width = children_width + this.last.right_width;

    /* Check if this node isn't wider than all of its children */
    this.left_width = Math.max(this.left_width, text_width / 2);
    this.right_width = Math.max(this.right_width, text_width / 2);
};

/* Sets parent and sibling nodes for a given (sub)tree */
Node.prototype.relate = function(parent) {
    this.parent = parent;
    this.has_children = (this.children.length > 0);

    if (this.has_children) {
        this.first = this.children[0];
        this.last = this.children[this.children.length - 1];
    }

    for (var i = 0; i < this.children.length; i++)
        this.children[i].relate(this);

    for (var i = 0; i < this.children.length - 1; i++)
        this.children[i].next = this.children[i+1];

    for (var i = 1; i < this.children.length; i++)
        this.children[i].previous = this.children[i-1];
};

function syntax_tree(s) {
    var t = parse(s);
    t.relate(null);
    t.check_triangles();

    if (App.R)
        App.R.clear();
    else
        App.R = new Raphael('canvas-container', 500, 500);
    var R = App.R;
    R.setStart();

    t.set_width();
    t.assign_location(0, 0);
    t.find_height();
    t.draw_tree_lines();

    /* Move the entire tree */
    var set = R.setFinish();
    set.translate(t.left_width + Tree.h_space, Tree.v_space);

    /* Resize the paper so it can show the entire tree */
    R.setSize(t.left_width + (2*Tree.h_space) + t.right_width, t.max_y + (2*Tree.v_space));
    return t;
};

function text_element(n) {
    var text = App.R.text(0, 0, n.value);
    text.attr({
        'font-size': 16,
    });
    return text;
};

function subscript(s) {
    var out = '';
    for (var i = 0; i < s.length; i++) {
        switch (s[i]) {
            case '0': out = out + '₀'; break;
            case '1': out = out + '₁'; break;
            case '2': out = out + '₂'; break;
            case '3': out = out + '₃'; break;
            case '4': out = out + '₄'; break;
            case '5': out = out + '₅'; break;
            case '6': out = out + '₆'; break;
            case '7': out = out + '₇'; break;
            case '8': out = out + '₈'; break;
            case '9': out = out + '₉'; break;
        }
    }
    return out;
};

function parse(s) {
    App.log('Parsing ' + s);
    var n = new Node();

    if (s[0] != '[') {
        /* Search for movement information */
        s = s.replace(/\s*<(\w+)>\s*/, function(match, tail) {
            n.tail = tail;
            App.log('Found tail: ' + tail);
            return ' ';
        });
        s = s.replace(/^\s+|\s+$/g, '');
        /* Search for features on this text node */
        var i = 0;
        while ((i < s.length) && (s[i] != '(')) i++;
        n.value = s.substring(0, i); /* Save the text node */

        if (s[i] == '(') {
            var start = i+1;
            while ((s[i] != ')')) i++;
            n.features = s.substring(start, i);
            App.log('Parsed features: ' + n.features);
        }
        return n;
    }

    /* Parse the category label */
    var i = 1;
    while ((s[i] != ' ') && (s[i] != '[') && (s[i] != ']')) i++;
    n.value = s.substring(1, i);
    /* Triangle-parent node */
    n.value = n.value.replace(/\^/, function() {
        n.caret = true;
        return '';
    });
    /* Label */
    n.value = n.value.replace(/_(\w+)$/, function(match, label) {
        App.log('Parsed label: ' + label);
        n.label = label;
        if (n.label.search(/^\d+$/) != -1)
            return subscript(n.label);
        return '';
    });
    App.log('Parsed first token: ' + n.value);

    while (s[i] == ' ') i++;
    var level = 1,
        start = i;
    for (; i < s.length; i++) {
        var outer_level = level;
        if (s[i] == '[') level++;
        if (s[i] == ']') level--;

        if (((outer_level == 1) && (level == 2)) || ((outer_level == 1) && (level == 0))) {
            /* Handle word token */
            if (s.substring(start, i).search(/\w+/) > -1)
               n.children.push(parse(s.substring(start, i)));
            start = i;
        }
        /* Parse an inside bracket group */
        if ((outer_level == 2) && (level == 1)) {
            n.children.push(parse(s.substring(start, i+1)));
            /* Otherwise we get the closing ] again and an extra level-- */
            start = i+1;
        }
    }
    return n;
};

$(function() {
    App.init();
});
<|endoftext|>


<commit_before>var sides = ["N", "E", "S", "W"];
var suit_image_template = "";
var big_suit_image_template = "";
var pass_dbl_rdbl = ["pass", "dbl", "rdbl"];

var lead_count;
var my_side;
var tid;
var ind_int = window.setInterval(function(){}, 9999);

var update_handlers = new Array();
update_handlers["move"] = process_move;
update_handlers["bid"] = process_bid;
update_handlers["hand"] = process_hand;
update_handlers["user.sit"] = user_sit;
update_handlers["user.leave"] = user_leave;
update_handlers["tricks"] = show_tricks;
update_handlers["start.bidding"] = kick_bidding;
update_handlers["start.play"] = kick_play;
update_handlers["end.play"] = end_play;
update_handlers["chat.add"] = handle_chat_add;
update_handlers["chat.message"] = handle_table_chat_message;

function on_body_load() {
    $("body").ajaxError(ajaxErrorHandler);
    parse_params();
    start_updator(update_handlers);
    init_chat();
    add_chat("table_" + tid, "Table", false);
    $("#alert_text").width($("#bidbox").width());
}

function parse_params() {
    params = location.search.split("/");
    tid = params[0].substr(1);
    if (params.length > 1) {
	my_side = $.inArray(params[1], sides);
    }
}

function ajaxErrorHandler(event, xhr, opts, error) {
    // retry should be here for some requests
    window.alert("request failed");
}

function process_hand(v) {
    var side = v.side;
    var cards = v.cards;
    cards.sort(card_sort);
    var h = $("#" + side + "_hand");
    h.children().remove();
    $.each(cards,
	   function(idx, value) {
	       h.append(create_card(side, value).css({"z-index": idx + 1, "left": idx * 9 + "%"}));
	   });
}

function card_sort(c1, c2) {
    if (Math.floor(c1/13) + Math.floor(c2/13) == 1) { /* show clubs before diamonds */
	return c1 - c2;
    } else {
	return c2 - c1;
    }
}

function create_card(side, card) {
    var s = document.createElement("span");
    $(s).addClass("card card_" + side + " suit_" + Math.floor(card/13));
    $(s).attr("id", "card_" + card);
    var bg = "url(images/cards.png) " + (card * -71) +  "px 0";
    return $(s).css("background", bg);
}

function indicator(selector, interval) {
    $(selector).toggleClass("indicator");
    window.setTimeout(function(){$(selector).toggleClass("indicator");}, interval);
}

function indicate_turn(side, my_turn) {
    window.clearInterval(ind_int)
    if (my_turn) {
	window.focus();
    }
    ind_int = window.setInterval(function(){indicator("." + side + "_user", 500)}, 1000);
}

function process_bid(v) {
    var side = v.side;
    var bid = v.bid;
    var alert = v.alert;
    var dbl_rdbl_allowed = v.dbl_mode;
    var bid_html;
    var idx = $.inArray(bid, pass_dbl_rdbl);
    if (idx == -1) {
	var r = bid[0];
	var s = bid[1];
	if (s != 'Z') {
	    var img = suit_image_template.replace("{suit}", s.toLowerCase()).replace("{alt_suit}", s);
	    bid_html = r + img;
	} else {
	    bid_html = r + "NT";
	}

	disallow_lower_bids(parseInt(r), s);
    } else {
	bid_html = bid;
    }
    var bid_cell = $("#bidding_area tr:last td:eq(" + side + ")");
    bid_cell.html(bid_html);
    if (alert != null) {
	bid_cell.CreateBubblePopup({innerHtml: decodeURIComponent(alert), themePath: "images/popup-themes"})
	    .addClass("alert_bid");
    }
    if (side == 3) {
	$("#bidding_area").append("

");
    }
    ns = (side + 1) % 4;
    var my_turn = ns == my_side;
    indicate_turn(sides[ns], my_turn);
    if (my_turn) {
	if (dbl_rdbl_allowed == "dbl") {
	    allow_bid("#bid_dbl");
	} else if (dbl_rdbl_allowed == "rdbl") {
	    allow_bid("#bid_rdbl");
	}
	allow_bid(".bidbox_pass");
	$(".bidbox_bid:not(.prohibited_bid)").bind("click", do_bid).addClass("clickable");
    }
}

function prohibit_bid(bid_selector) {
    $(bid_selector).unbind("click").removeClass("clickable").addClass("prohibited_bid");
}

function allow_bid(bid_selector) {
    $(bid_selector).bind("click", do_bid).addClass("clickable").removeClass("prohibited_bid");
}

function disallow_lower_bids(r, s) {
    var bid_id = "bid_" + r + s;
    var allowed_bids = $(".bidbox_bid:not(.prohibited_bid)");
    var filtered = allowed_bids.filter(function(index){return this.id <= bid_id});
    filtered.addClass("prohibited_bid");
}

function process_move(v) {
    if (lead_count % 4 == 0) {
	for (var i = 0; i < 4; i += 1) {
	    $("#" + sides[i] + "_last span").remove();
	    $("#" + sides[i] + "_last")
		.append($("#" + sides[i] + "_lead span").detach());
   	}
	lead_count = 0;
    }

    var side = v.side;
    var card = v.card;
    var allowed = v.allowed;
    var trick = v.trick;
    var card_div_id = "#card_" + card;
    var lead_div_id = "#" + side + "_lead";
    if (trick != null) {
	$("#" + trick + "_tricks").text(trick_inc);
    }

    $(card_div_id).remove();
    $(lead_div_id).append(create_card(side, card).css({"z-index": lead_count, "left": 0}));
    lead_count += 1;
    var np;
    if (v.next != null) {
	ns = v.next;
    } else {
	ns = next_side(side);
    }
    var my_turn = allowed != null;
    indicate_turn(ns, my_turn);
    if (!my_turn) {
	prohibit_cards(".card");
	return;
    }
    prohibit_cards(".card");
    if (allowed == "any") {
	allow_cards(".card_" + ns, ns);
    } else {
	var np_suit_class = ".card_" + ns + ".suit_" + allowed;
	allow_cards(np_suit_class, ns);
    }
}

function prohibit_cards(selector) {
    return $(selector).unbind("click dblclick").removeClass("clickable");
}

function allow_cards(selector, side) {
    return $(selector).bind("click", side, highlight_for_move)
	.bind("dblclick", side, do_move).addClass("clickable");
}

function next_side(side) {
    var idx = $.inArray(side, sides);
    return sides[(idx + 1) % 4]
}

function do_move(event) {
    var side = event.data;
    var splitted_id = event.target.id.split("_");
    var number = splitted_id[1];
    var url = "action.json?move/" + tid + "/" + side + "/" + number;
    $.post(url);
    prohibit_cards(".card");
    $(event.target).remove();
}

function img_by_suit(suit) {
    var c = suit.charAt(0);
    return suit_image_template.replace("{suit}", c.toLowerCase()).replace("{alt_suit}", c.toUpperCase());
}

function kick_bidding(v) {
    prohibit_bid(".bidbox_pass,.bidbox_dbl,.bidbox_rdbl");
    if (v.vuln & 1) {
	$(".vuln_NS").addClass("vulnerable");
    }

    if (v.vuln & 2) {
	$(".vuln_EW").addClass("vulnerable");
    }

    side = sides[v.dealer];
    indicate_turn(side);
    $("#dealer_" + side).addClass("dealer");
    if (my_side == v.dealer) {
    	$(".bidbox_bid").bind("click", do_bid).addClass("clickable");
	allow_bid(".bidbox_pass");
    }
}

function kick_play(v) {
    var contract = v.contract;
    var lead_maker = v.lead;
    lead_count = 0;
    $("#bidbox").css("display", "none").after($("#bidding_area").detach());
    $("#alert_text").addClass("hidden");
    $("#bidbox_cell").css("text-align", "center");
    $("#lead_area").removeClass("hidden");
    indicate_turn(sides[lead_maker]);
    if (lead_maker == my_side) {
	s = sides[my_side];
	allow_cards(".card_" + s, s);
    }
    var csuit = contract[1];
    var cntrct_html;
    if (csuit != "Z") {
	cntrct_html = contract[0] +
	    big_suit_image_template.replace("{suit}", csuit.toLowerCase())
	    .replace("{alt_suit}", csuit.toUpperCase());
    } else {
	cntrct_html = contract[0] + "NT";
    }
    $("#contract").html(cntrct_html);
    $("#contract_by").text(" by " + contract.substr(contract.length - 1))
}

function highlight_for_move(event) {
    var splitted_id = event.target.id.split("_");
    var number = splitted_id[1];
    allow_cards(".highlighted", event.data).removeClass("highlighted");
    $("#card_" + number).addClass("highlighted").bind("click", event.data, do_move);
}

function do_bid(event) {
    var splitted_id = event.currentTarget.id.split("_");
    var bid = splitted_id[1];
    $(".bidbox_bid:not(.prohibited_bid)").unbind("click").removeClass("clickable");
    prohibit_bid(".bidbox_pass,.bidbox_dbl,.bidbox_rdbl");
    var url = "action.json?bid/" + tid + "/" + my_side + "/" + bid;
    var alert = $("#alert_text").val();
    if (alert != "" && alert != "Alert") {
	url += "/" + alert;
    }
    $.post(url);
}

function trick_inc(i, s) {
    if (s.length == 0) {
	return 1;
    } else {
	return parseInt(s) + 1;
    }
}

function show_tricks(v) {
    if (v.NS > 0) {
	$("#NS_tricks").text(v.NS);
    }
    if (v.EW > 0) {
	$("#EW_tricks").text(v.EW);
    }
}

function end_play(v) {
    $(".vuln_NS,.vuln_EW").removeClass("vulnerable");
    $("#dealer_N,#dealer_E,#dealer_S,#dealer_W").removeClass("dealer");
    $("#bidding_area").removeClass("hidden");
    $("#bidbox").css("display", "inline-block");
    $("#bidbox_cell").css("text-align", "right");
    $("#lead_area").addClass("hidden");
    $("#contract,.tricks").html("");
    $("#bidding_area tr:gt(1)").remove();
    $("#bidding_area tr td").text("").RemoveBubblePopup();
    $("#alert_text").removeClass("hidden");
    $(".hand_container").children().remove().append("");
    $(".bidbox_bid,.bidbox_pass,.bidbox_dbl,.bidbox_rdbl")
	.unbind("click").removeClass("prohibited_bid clickable");
    $(".lead").text("");
    $("#lead_area").before($("#bidding_area").detach());
    var contract = v.contract;
    var decl = v.declearer;
    var points = v.points;
    var tricks = v.tricks;
    var url = v.protocol_url;
    var sign = "";
    if (points > 0) {
	sign = "+";
    }
    var contract_html;
    if (contract == "pass"){
	contract_html = "pass";
    } else {
	var r = contract[0];
	var s = contract[1];
	if (s != "Z") {
	    var img = suit_image_template.replace("{suit}", s.toLowerCase()).replace("{alt_suit}", s);
	    contract_html = r + img;
	} else {
	    contract_html = r + "NT";
	}
    }
    contract_html += contract.substr(2, 2);
    $("#popup_res").html("" +  tricks
			 + " tricks, " + sign + points + "");
    $("#popup_contract").html(contract_html + " by " + decl);
    $(".popup").bPopup();

}

function user_sit(v) {
    var pos = v.position;
    var name = v.name;
    $("." + pos + "_user").text(name);
}

function user_leave(v) {
    var pos = v.position;
    $("." + pos + "_user").text("");
}

function handle_table_chat_message(v) {
    var wid = v.wid;
    var idx = wid.indexOf("@");
    if (idx >= 0) {
	wid = wid.substr(0, idx);
    }
    if (wid != $("." + sides[(my_side + 2) % 4] + "_user").text()) {
	handle_chat_message(v);
    }
}
<commit_msg>show mock images for non-seen cards when second and sequential dials played<commit_after>var sides = ["N", "E", "S", "W"];
var suit_image_template = "";
var big_suit_image_template = "";
var pass_dbl_rdbl = ["pass", "dbl", "rdbl"];

var lead_count;
var my_side;
var tid;
var ind_int = window.setInterval(function(){}, 9999);

var update_handlers = new Array();
update_handlers["move"] = process_move;
update_handlers["bid"] = process_bid;
update_handlers["hand"] = process_hand;
update_handlers["user.sit"] = user_sit;
update_handlers["user.leave"] = user_leave;
update_handlers["tricks"] = show_tricks;
update_handlers["start.bidding"] = kick_bidding;
update_handlers["start.play"] = kick_play;
update_handlers["end.play"] = end_play;
update_handlers["chat.add"] = handle_chat_add;
update_handlers["chat.message"] = handle_table_chat_message;

function on_body_load() {
    $("body").ajaxError(ajaxErrorHandler);
    parse_params();
    start_updator(update_handlers);
    init_chat();
    add_chat("table_" + tid, "Table", false);
    $("#alert_text").width($("#bidbox").width());
}

function parse_params() {
    params = location.search.split("/");
    tid = params[0].substr(1);
    if (params.length > 1) {
	my_side = $.inArray(params[1], sides);
    }
}

function ajaxErrorHandler(event, xhr, opts, error) {
    // retry should be here for some requests
    window.alert("operation failed");
}

function process_hand(v) {
    var side = v.side;
    var cards = v.cards;
    cards.sort(card_sort);
    var h = $("#" + side + "_hand");
    h.children().remove();
    $.each(cards,
	   function(idx, value) {
	       h.append(create_card(side, value).css({"z-index": idx + 1, "left": idx * 9 + "%"}));
	   });
}

function card_sort(c1, c2) {
    if (Math.floor(c1/13) + Math.floor(c2/13) == 1) { /* show clubs before diamonds */
	return c1 - c2;
    } else {
	return c2 - c1;
    }
}

function create_card(side, card) {
    var s = document.createElement("span");
    $(s).addClass("card card_" + side + " suit_" + Math.floor(card/13));
    $(s).attr("id", "card_" + card);
    var bg = "url(images/cards.png) " + (card * -71) +  "px 0";
    return $(s).css("background", bg);
}

function indicator(selector, interval) {
    $(selector).toggleClass("indicator");
    window.setTimeout(function(){$(selector).toggleClass("indicator");}, interval);
}

function indicate_turn(side, my_turn) {
    window.clearInterval(ind_int)
    if (my_turn) {
	window.focus();
    }
    ind_int = window.setInterval(function(){indicator("." + side + "_user", 500)}, 1000);
}

function process_bid(v) {
    var side = v.side;
    var bid = v.bid;
    var alert = v.alert;
    var dbl_rdbl_allowed = v.dbl_mode;
    var bid_html;
    var idx = $.inArray(bid, pass_dbl_rdbl);
    if (idx == -1) {
	var r = bid[0];
	var s = bid[1];
	if (s != 'Z') {
	    var img = suit_image_template.replace("{suit}", s.toLowerCase()).replace("{alt_suit}", s);
	    bid_html = r + img;
	} else {
	    bid_html = r + "NT";
	}

	disallow_lower_bids(parseInt(r), s);
    } else {
	bid_html = bid;
    }
    var bid_cell = $("#bidding_area tr:last td:eq(" + side + ")");
    bid_cell.html(bid_html);
    if (alert != null) {
	bid_cell.CreateBubblePopup({innerHtml: decodeURIComponent(alert), themePath: "images/popup-themes"})
	    .addClass("alert_bid");
    }
    if (side == 3) {
	$("#bidding_area").append("

");
    }
    ns = (side + 1) % 4;
    var my_turn = ns == my_side;
    indicate_turn(sides[ns], my_turn);
    if (my_turn) {
	if (dbl_rdbl_allowed == "dbl") {
	    allow_bid("#bid_dbl");
	} else if (dbl_rdbl_allowed == "rdbl") {
	    allow_bid("#bid_rdbl");
	}
	allow_bid(".bidbox_pass");
	$(".bidbox_bid:not(.prohibited_bid)").bind("click", do_bid).addClass("clickable");
    }
}

function prohibit_bid(bid_selector) {
    $(bid_selector).unbind("click").removeClass("clickable").addClass("prohibited_bid");
}

function allow_bid(bid_selector) {
    $(bid_selector).bind("click", do_bid).addClass("clickable").removeClass("prohibited_bid");
}

function disallow_lower_bids(r, s) {
    var bid_id = "bid_" + r + s;
    var allowed_bids = $(".bidbox_bid:not(.prohibited_bid)");
    var filtered = allowed_bids.filter(function(index){return this.id <= bid_id});
    filtered.addClass("prohibited_bid");
}

function process_move(v) {
    if (lead_count % 4 == 0) {
	for (var i = 0; i < 4; i += 1) {
	    $("#" + sides[i] + "_last span").remove();
	    $("#" + sides[i] + "_last")
		.append($("#" + sides[i] + "_lead span").detach());
   	}
	lead_count = 0;
    }

    var side = v.side;
    var card = v.card;
    var allowed = v.allowed;
    var trick = v.trick;
    var card_div_id = "#card_" + card;
    var lead_div_id = "#" + side + "_lead";
    if (trick != null) {
	$("#" + trick + "_tricks").text(trick_inc);
    }

    $(card_div_id).remove();
    $(lead_div_id).append(create_card(side, card).css({"z-index": lead_count, "left": 0}));
    lead_count += 1;
    var np;
    if (v.next != null) {
	ns = v.next;
    } else {
	ns = next_side(side);
    }
    var my_turn = allowed != null;
    indicate_turn(ns, my_turn);
    if (!my_turn) {
	prohibit_cards(".card");
	return;
    }
    prohibit_cards(".card");
    if (allowed == "any") {
	allow_cards(".card_" + ns, ns);
    } else {
	var np_suit_class = ".card_" + ns + ".suit_" + allowed;
	allow_cards(np_suit_class, ns);
    }
}

function prohibit_cards(selector) {
    return $(selector).unbind("click dblclick").removeClass("clickable");
}

function allow_cards(selector, side) {
    return $(selector).bind("click", side, highlight_for_move)
	.bind("dblclick", side, do_move).addClass("clickable");
}

function next_side(side) {
    var idx = $.inArray(side, sides);
    return sides[(idx + 1) % 4]
}

function do_move(event) {
    var side = event.data;
    var splitted_id = event.target.id.split("_");
    var number = splitted_id[1];
    var url = "action.json?move/" + tid + "/" + side + "/" + number;
    $.post(url);
    prohibit_cards(".card");
    $(event.target).remove();
}

function img_by_suit(suit) {
    var c = suit.charAt(0);
    return suit_image_template.replace("{suit}", c.toLowerCase()).replace("{alt_suit}", c.toUpperCase());
}

function kick_bidding(v) {
    prohibit_bid(".bidbox_pass,.bidbox_dbl,.bidbox_rdbl");
    if (v.vuln & 1) {
	$(".vuln_NS").addClass("vulnerable");
    }

    if (v.vuln & 2) {
	$(".vuln_EW").addClass("vulnerable");
    }

    side = sides[v.dealer];
    indicate_turn(side);
    $("#dealer_" + side).addClass("dealer");
    if (my_side == v.dealer) {
    	$(".bidbox_bid").bind("click", do_bid).addClass("clickable");
	allow_bid(".bidbox_pass");
    }
}

function kick_play(v) {
    var contract = v.contract;
    var lead_maker = v.lead;
    lead_count = 0;
    $("#bidbox").css("display", "none").after($("#bidding_area").detach());
    $("#alert_text").addClass("hidden");
    $("#bidbox_cell").css("text-align", "center");
    $("#lead_area").removeClass("hidden");
    indicate_turn(sides[lead_maker]);
    if (lead_maker == my_side) {
	s = sides[my_side];
	allow_cards(".card_" + s, s);
    }
    var csuit = contract[1];
    var cntrct_html;
    if (csuit != "Z") {
	cntrct_html = contract[0] +
	    big_suit_image_template.replace("{suit}", csuit.toLowerCase())
	    .replace("{alt_suit}", csuit.toUpperCase());
    } else {
	cntrct_html = contract[0] + "NT";
    }
    $("#contract").html(cntrct_html);
    $("#contract_by").text(" by " + contract.substr(contract.length - 1))
}

function highlight_for_move(event) {
    var splitted_id = event.target.id.split("_");
    var number = splitted_id[1];
    allow_cards(".highlighted", event.data).removeClass("highlighted");
    $("#card_" + number).addClass("highlighted").bind("click", event.data, do_move);
}

function do_bid(event) {
    var splitted_id = event.currentTarget.id.split("_");
    var bid = splitted_id[1];
    $(".bidbox_bid:not(.prohibited_bid)").unbind("click").removeClass("clickable");
    prohibit_bid(".bidbox_pass,.bidbox_dbl,.bidbox_rdbl");
    var url = "action.json?bid/" + tid + "/" + my_side + "/" + bid;
    var alert = $("#alert_text").val();
    if (alert != "" && alert != "Alert") {
	url += "/" + alert;
    }
    $.post(url);
}

function trick_inc(i, s) {
    if (s.length == 0) {
	return 1;
    } else {
	return parseInt(s) + 1;
    }
}

function show_tricks(v) {
    if (v.NS > 0) {
	$("#NS_tricks").text(v.NS);
    }
    if (v.EW > 0) {
	$("#EW_tricks").text(v.EW);
    }
}

function end_play(v) {
    $(".vuln_NS,.vuln_EW").removeClass("vulnerable");
    $("#dealer_N,#dealer_E,#dealer_S,#dealer_W").removeClass("dealer");
    $("#bidding_area").removeClass("hidden");
    $("#bidbox").css("display", "inline-block");
    $("#bidbox_cell").css("text-align", "right");
    $("#lead_area").addClass("hidden");
    $("#contract,.tricks").html("");
    $("#bidding_area tr:gt(1)").remove();
    $("#bidding_area tr td").text("").RemoveBubblePopup();
    $("#alert_text").removeClass("hidden");
    $(".hand_container").children().remove();
    $(".hand_container").append($(""));
    $(".bidbox_bid,.bidbox_pass,.bidbox_dbl,.bidbox_rdbl")
	.unbind("click").removeClass("prohibited_bid clickable");
    $(".lead").text("");
    $("#lead_area").before($("#bidding_area").detach());
    var contract = v.contract;
    var decl = v.declearer;
    var points = v.points;
    var tricks = v.tricks;
    var url = v.protocol_url;
    var sign = "";
    if (points > 0) {
	sign = "+";
    }
    var contract_html;
    if (contract == "pass"){
	contract_html = "pass";
    } else {
	var r = contract[0];
	var s = contract[1];
	if (s != "Z") {
	    var img = suit_image_template.replace("{suit}", s.toLowerCase()).replace("{alt_suit}", s);
	    contract_html = r + img;
	} else {
	    contract_html = r + "NT";
	}
    }
    contract_html += contract.substr(2, 2);
    $("#popup_res").html("" +  tricks
			 + " tricks, " + sign + points + "");
    $("#popup_contract").html(contract_html + " by " + decl);
    $(".popup").bPopup();

}

function user_sit(v) {
    var pos = v.position;
    var name = v.name;
    $("." + pos + "_user").text(name);
}

function user_leave(v) {
    var pos = v.position;
    $("." + pos + "_user").text("");
}

function handle_table_chat_message(v) {
    var wid = v.wid;
    var idx = wid.indexOf("@");
    if (idx >= 0) {
	wid = wid.substr(0, idx);
    }
    if (wid != $("." + sides[(my_side + 2) % 4] + "_user").text()) {
	handle_chat_message(v);
    }
}
<|endoftext|>


<commit_before>(function(globals){ // IIFE
// Not this again...

  // it('should totally fail', function(){
  //   chai.expect(false).equals(true);
  // })

  it('should have a `game` in the `window`', function(){
    chai.expect(window.game).to.be.equal(game);
    chai.expect(game).to.be.an('object');
    chai.expect(game.board).to.a('function'); // ???
  });

  it('should give me a big array as the board', function(){
    var board = game.board();

    chai.expect(board).to.be.an('array');
    // chai.expect(game.board().length).to.be.equal(8);
    chai.expect(board).to.have.length(8);

    chai.expect(board[0]).to.be.a('array');
    chai.expect(board[0]).to.have.length(8);

    chai.expect(board[0][0]).to.be.a('string');
    chai.expect(board[0][0]).to.equal('R');

  }); // END it should be a big Array

  it('should be able to move pieces', function(){
    var board = game.board();
    //Pre conditions...
    expect(board[6][3]).to.equal('p');
    expect(board[4][3]).to.be.null;

    // Action to change the world...
    expect(game.applyMove(
      { rank: 6, file: 3 }, // from
      { rank: 4, file: 3 } // to
    ));.to.equal(undefined);

    // Post conditions...
    var board = game.board();

    chai.expect(board[6][3]).to.be.null;
    chai.expect(board[4][3]).to.be.equal('p');

  });

  it.skip('should be able to advance to the next move', function(){
    // TODO: Maybe I should write some tests for this?
  });

// There's that crazy line again...
})(window || module && module.exports || this);
<commit_msg>updates<commit_after>(function(globals){ // IIFE
// Not this again...

  // it('should totally fail', function(){
  //   chai.expect(false).equals(true);
  // })
  var expect = chai.expect;

  it('should have a `game` in the `window`', function(){
    chai.expect(window.game).to.be.equal(game);
    chai.expect(game).to.be.an('object');
    chai.expect(game.board).to.a('function'); // ???
  });

  it('should give me a big array as the board', function(){
    var board = game.board();

    chai.expect(board).to.be.an('array');
    // chai.expect(game.board().length).to.be.equal(8);
    chai.expect(board).to.have.length(8);

    chai.expect(board[0]).to.be.a('array');
    chai.expect(board[0]).to.have.length(8);

    chai.expect(board[0][0]).to.be.a('string');
    chai.expect(board[0][0]).to.equal('R');

  }); // END it should be a big Array

  // it('should be able to move pieces', function(){
  //   //Pre conditions...
  //   game.reset(); //Re-initialize the board...
  //   var board = game.board();
  //   expect(board[6][3]).to.equal('p');
  //   expect(board[4][3]).to.be.null;
  //
  //   // Action to change the world...
  //   expect(game.applyMove(
  //     { rank: 6, file: 3 }, // from
  //     { rank: 4, file: 3 } // to
  //   ));.to.equal(undefined);
  //
  //   // Post conditions...
  //   var board = game.board();
  //
  //   chai.expect(board[6][3]).to.be.null;
  //   chai.expect(board[4][3]).to.be.equal('p');
  //
  //
  // });
  it('should be able to move pieces', function () {
    // won't pass yet until you update main.js acordingly
    // Pre conditions...
    game.reset(); // Re-initialize the board...
    var board = game.board();
    expect(board[6][3]).to.equal('p');
    expect(board[4][3]).to.be.null;

    // Action to change the world...
    expect(game.applyMove(
      { rank: 6, file: 3 }, // from
      { rank: 4, file: 3 }  // to
    )).to.equal(undefined);

    // Post conditions...
    var board = game.board();

    chai.expect(board[6][3]).to.be.null;
    chai.expect(board[4][3]).to.be.equal('p');
  });

  it.skip('should be able to assign the from piece to null', function() {
    chai.expect(game.applyMove()).to.deep.equal(null);
  });

  it.skip('should be able to advance to the next move', function(){
    // TODO: Maybe I should write some tests for this?
  });

// There's that crazy line again...
})(window || module && module.exports || this);
<|endoftext|>


<commit_before>// var myTime = new Date();
// console.log(myTime);
// var startDate = new Date(2015, 6, 13);
// console.log(startDate);
// var timeleft = myTime - startDate;
// var countdown = new Date(timeleft)
// console.log(countdown.getUTCHours(), countdown.getMinutes(), countdown.getSeconds());

function countdown(){
  var myTime = new Date();
  var end = new Date(2015, 7, 3);
  console.log(end);
  var count = end - myTime;
  console.log(count);
  var timeleft = new Date(count);
  console.log(timeleft.getDate());

  document.getElementById('timer').innerHTML = timeleft.getDate(), ":", timeleft.getUTCHours(), ":", timeleft.getMinutes(),":", timeleft.getSeconds();
  console.log(timeleft.getDate(), ":", timeleft.getUTCHours(), ":", timeleft.getMinutes(),":", timeleft.getSeconds());

};
<commit_msg>Add timer2<commit_after>function countdown(){
  var myTime = new Date();
  var end = new Date(2015, 7, 3);
  console.log(end);
  var count = end - myTime;
  console.log(count);
  var timeleft = new Date(count);
  console.log(timeleft.getDate());

  document.getElementById('timer').innerHTML = (timeleft.getDate(), ":", timeleft.getUTCHours(), ":", timeleft.getMinutes(),":", timeleft.getSeconds());
  console.log(timeleft.getDate(), ":", timeleft.getUTCHours(), ":", timeleft.getMinutes(),":", timeleft.getSeconds());

};
<|endoftext|>


<commit_before>// Copyright (c) 2014 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

// The trashcan is an area at the bottom of the screen where stacks of
// blocks can be dragged. Once in the trash area, they are marked as
// trash and hidden. There is a menu button that can be used to
// restore trash.
require(['activity/utils']);

var TRASHWIDTH = 120;
var TRASHHEIGHT = 120;

function Trashcan (canvas, stage, size, refreshCanvas) {
    this.canvas = canvas;
    this.stage = stage;
    this.refreshCanvas = refreshCanvas;
    this.size = size;
    this.isVisible = false;
    this.timeout = null;
    this.timeoutSet = false;

    this.iconsize = 55;  // default value
    this.container = new createjs.Container();

    this._makeBorderHighlight = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            bitmap = new createjs.Bitmap(img);
            bitmap.scaleX = size / trash.iconsize;
            bitmap.scaleY = size / trash.iconsize;
            trash.container.addChild(bitmap);
            bitmap.visible = false;
            bounds = trash.container.getBounds();
            trash.container.cache(bounds.x, bounds.y, bounds.width, bounds.height);
            // Hide the trash until a block is moved.
            trash.container.visible = false;
        };

        img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(BORDER.replace('stroke_color', '#000000'))));
    };

    this._makeBorder = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            border = new createjs.Bitmap(img);
            bitmap.scaleX = trash.size / trash.iconsize;
            bitmap.scaleY = trash.size / trash.iconsize;
            trash.container.addChild(border);
            trash._makeBorderHighlight();
        };

        img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(BORDER.replace('stroke_color', '#e0e0e0'))));
    };

    this._makeTrash = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            bitmap = new createjs.Bitmap(img);
            trash.container.addChild(bitmap);
            trash.iconsize = bitmap.getBounds().width;
            bitmap.scaleX = trash.size / trash.iconsize;
            bitmap.scaleY = trash.size / trash.iconsize;
            bitmap.x = ((TRASHWIDTH - size) / 2) * bitmap.scaleX;
            bitmap.y = ((TRASHHEIGHT - size) / 2) * bitmap.scaleY;
            trash._makeBorder();
        };

        img.src = 'images/trash.svg';
    };

    this.resizeEvent = function(scale) {
        this.container.x = (this.canvas.width * 1 / scale / 2) - ((TRASHWIDTH / 2) * (this.size / this.iconsize));
        this.container.y = (this.canvas.height * 1 / scale) - (TRASHHEIGHT * (this.size / this.iconsize));
    };

    this.stage.addChild(this.container);
    this.stage.setChildIndex(this.container, 0);
    this.resizeEvent(1);
    this._makeTrash();

    this.hide = function() {
        createjs.Tween.get(this.container).to({alpha: 0}, 200).set({visible: false});
    };

    this.show = function() {
        createjs.Tween.get(this.container).to({alpha: 0.0, visible: true}).to({alpha: 1.0}, 200);
    };

    this.highlight = function() {
        this.isVisible = true;
        if (!last(this.container.children).visible) {
            last(this.container.children).visible = true;
            this.container.children[1].visible = false;
            this.container.visible = true;
            this.container.updateCache();
            this.refreshCanvas();
        }
    };

    this.unhighlight = function() {
        this.isVisible = false;
        if (last(this.container.children).visible) {
            last(this.container.children).visible = false;
            this.container.children[1].visible = true;
            this.container.visible = true;
            this.container.updateCache();
            this.refreshCanvas();
        }
    };

    this.overTrashcan = function(x, y) {
        var tx = this.container.x;
        var ty = this.container.y;

        if (x < tx) {
            return false;
        } else if (x > tx + (TRASHWIDTH * this.size / this.iconsize)) {
            return false;
        }

        if (y < ty) {
            return false;
        }

        return true;
    };
};
<commit_msg>rename isVisible to more appropriate isReady<commit_after>// Copyright (c) 2014 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

// The trashcan is an area at the bottom of the screen where stacks of
// blocks can be dragged. Once in the trash area, they are marked as
// trash and hidden. There is a menu button that can be used to
// restore trash.
require(['activity/utils']);

var TRASHWIDTH = 120;
var TRASHHEIGHT = 120;

function Trashcan (canvas, stage, size, refreshCanvas) {
    this.canvas = canvas;
    this.stage = stage;
    this.refreshCanvas = refreshCanvas;
    this.size = size;
    this.isReady = false;
    this.timeout = null;
    this.timeoutSet = false;

    this.iconsize = 55;  // default value
    this.container = new createjs.Container();

    this._makeBorderHighlight = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            bitmap = new createjs.Bitmap(img);
            bitmap.scaleX = size / trash.iconsize;
            bitmap.scaleY = size / trash.iconsize;
            trash.container.addChild(bitmap);
            bitmap.visible = false;
            bounds = trash.container.getBounds();
            trash.container.cache(bounds.x, bounds.y, bounds.width, bounds.height);
            // Hide the trash until a block is moved.
            trash.container.visible = false;
        };

        img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(BORDER.replace('stroke_color', '#000000'))));
    };

    this._makeBorder = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            border = new createjs.Bitmap(img);
            bitmap.scaleX = trash.size / trash.iconsize;
            bitmap.scaleY = trash.size / trash.iconsize;
            trash.container.addChild(border);
            trash._makeBorderHighlight();
        };

        img.src = 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(BORDER.replace('stroke_color', '#e0e0e0'))));
    };

    this._makeTrash = function() {
        var img = new Image();
        var trash = this;

        img.onload = function () {
            bitmap = new createjs.Bitmap(img);
            trash.container.addChild(bitmap);
            trash.iconsize = bitmap.getBounds().width;
            bitmap.scaleX = trash.size / trash.iconsize;
            bitmap.scaleY = trash.size / trash.iconsize;
            bitmap.x = ((TRASHWIDTH - size) / 2) * bitmap.scaleX;
            bitmap.y = ((TRASHHEIGHT - size) / 2) * bitmap.scaleY;
            trash._makeBorder();
        };

        img.src = 'images/trash.svg';
    };

    this.resizeEvent = function(scale) {
        this.container.x = (this.canvas.width * 1 / scale / 2) - ((TRASHWIDTH / 2) * (this.size / this.iconsize));
        this.container.y = (this.canvas.height * 1 / scale) - (TRASHHEIGHT * (this.size / this.iconsize));
    };

    this.stage.addChild(this.container);
    this.stage.setChildIndex(this.container, 0);
    this.resizeEvent(1);
    this._makeTrash();

    this.hide = function() {
        createjs.Tween.get(this.container).to({alpha: 0}, 200).set({visible: false});
    };

    this.show = function() {
        createjs.Tween.get(this.container).to({alpha: 0.0, visible: true}).to({alpha: 1.0}, 200);
    };

    this.highlight = function() {
        this.isReady = true;
        if (!last(this.container.children).visible) {
            last(this.container.children).visible = true;
            this.container.children[1].visible = false;
            this.container.visible = true;
            this.container.updateCache();
            this.refreshCanvas();
        }
    };

    this.unhighlight = function() {
        this.isReady = false;
        if (last(this.container.children).visible) {
            last(this.container.children).visible = false;
            this.container.children[1].visible = true;
            this.container.visible = true;
            this.container.updateCache();
            this.refreshCanvas();
        }
    };

    this.overTrashcan = function(x, y) {
        var tx = this.container.x;
        var ty = this.container.y;

        if (x < tx) {
            return false;
        } else if (x > tx + (TRASHWIDTH * this.size / this.iconsize)) {
            return false;
        }

        if (y < ty) {
            return false;
        }

        return true;
    };
};
<|endoftext|>


<commit_before>$(function(){
    $(".name").typed({
        strings: ["Ken Luy"],
        startDelay: 0,
        showCursor: true,
        typeSpeed: 100,
        onStringTyped: function() {document.getElementsByClassName("typed-cursor")[0].className="empty";}
    });
    $(".skills").typed({
        strings: ["Hacker. Developer. Learner"],
        startDelay: 2800,
        showCursor: true,
        typeSpeed: 100,
        onStringTyped: function() {document.getElementsByClassName("typed-cursor")[0].className="empty";}
    });
});
<commit_msg>added period<commit_after>$(function(){
    $(".name").typed({
        strings: ["Ken Luy"],
        startDelay: 0,
        showCursor: true,
        typeSpeed: 100,
        onStringTyped: function() {document.getElementsByClassName("typed-cursor")[0].className="empty";}
    });
    $(".skills").typed({
        strings: ["Hacker. Developer. Learner."],
        startDelay: 2800,
        showCursor: true,
        typeSpeed: 100,
        onStringTyped: function() {document.getElementsByClassName("typed-cursor")[0].className="empty";}
    });
});
<|endoftext|>


<commit_before>/*globals define, WebGMEGlobal, _, $*/
/*jshint browser: true*/

/**
 * @author rkereskenyi / https://github.com/rkereskenyi
 */

define(['js/PanelBase/PanelBase', 'css!./styles/SplitPanel.css'], function (PanelBase) {

    'use strict';

    var SplitPanel,
        SPLIT_PANEL_CLASS = 'split-panel',
        PANEL1_CLASS = 'p1',
        PANEL2_CLASS = 'p2',
        SPLITTER_CLASS = 'splitter',
        SPLITTER_SIZE = 4,
        VERTICAL_CLASS = 'vertical',
        HORIZONTAL_CLASS = 'horizontal',
        SPLITTER_RESIZE_CLASS = 'resize',
        MINIMUM_PANEL_SIZE = 50,
        SPLITTER_SNAP_FROM_DISTANCE = 25,
        SPLITTER_RESIZE_PADDING = 2;

    SplitPanel = function (/*layoutManager, params*/) {
        var options = {};
        //set properties from options
        options[PanelBase.OPTIONS.LOGGER_INSTANCE_NAME] = 'SplitPanel';

        //call parent's constructor
        PanelBase.apply(this, [options]);

        this._panel1 = undefined;
        this._panel2 = undefined;

        this._readOnly = false;

        this._splitterPos = 0.5;

        //initialize UI
        this._initialize();

        this.logger.debug('SplitPanel ctor finished');
    };

    //inherit from PanelBaseWithHeader
    _.extend(SplitPanel.prototype, PanelBase.prototype);

    SplitPanel.prototype.onResize = function (width, height) {
        this.logger.debug('onResize --> width: ' + width + ', height: ' + height);

        this._width = width;
        this._height = height;

        this.$el.width(this._width);
        this.$el.height(this._height);

        this._updateUI();
    };

    SplitPanel.prototype._initialize = function () {
        var self = this;

        this.$el.addClass(SPLIT_PANEL_CLASS);

        this._panel1Container = $('<div/>', {class: PANEL1_CLASS});
        this.$el.append(this._panel1Container);

        this._splitter = $('<div/>', {class: SPLITTER_CLASS});
        this.$el.append(this._splitter);

        this._panel2Container = $('<div/>', {class: PANEL2_CLASS});
        this.$el.append(this._panel2Container);

        this._panel1Container.on('mousedown', function (event) {
            self._setActivePanel(0);
            event.stopPropagation();
        });

        this._panel2Container.on('mousedown', function (event) {
            self._setActivePanel(1);
            event.stopPropagation();
        });

        this._splitter.on('mousedown', function (event) {
            self._startPanelResize(event);
            event.stopPropagation();
            event.preventDefault();
        });

        this._updateUI();
    };

    SplitPanel.prototype._updateUI = function () {
        var verticalSplit = this._width > this._height,
            w1 = this._width,
            h1 = this._height,
            w2 = this._width,
            h2 = this._height,
            sw = SPLITTER_SIZE,
            sh = SPLITTER_SIZE,
            p1Top = 0,
            p1Left = 0,
            splitterTop = 0,
            splitterLeft = 0,
            p2Top = 0,
            p2Left = 0,
            has2Panels = this._panel2 !== undefined;

        if (has2Panels) {
            this._splitter.show();
            this._panel2Container.show();
            this._splitter.removeClass([VERTICAL_CLASS, HORIZONTAL_CLASS].join(' '));
        } else {
            this._splitter.hide();
            this._panel2Container.hide();
        }

        if (has2Panels) {
            if (verticalSplit) {
                sh = this._height;
                w1 = Math.floor((this._width - sw) * this._splitterPos);
                w2 = this._width - w1 - sw;
                this._splitter.addClass(VERTICAL_CLASS);
                p1Left = 0;
                splitterLeft = w1;
                p2Left = w1 + sw;
            } else {
                sw = this._width;
                h1 = Math.floor((this._height - sh) * this._splitterPos);
                h2 = this._height - h1 - sh;
                this._splitter.addClass(HORIZONTAL_CLASS);
                p1Top = 0;
                splitterTop = h1;
                p2Top = h1 + sh;
            }

            this._splitter.css({
                width: sw,
                height: sh,
                top: splitterTop,
                left: splitterLeft
            });

            this._panel1Container.css({
                width: w1,
                height: h1,
                top: p1Top,
                left: p1Left
            });

            this._panel2Container.css({
                width: w2,
                height: h2,
                top: p2Top,
                left: p2Left
            });

            if (this._panel1) {
                this._panel1.setSize(w1, h1);
            }

            if (this._panel2) {
                this._panel2.setSize(w2, h2);
            }
        } else {
            this._panel1Container.css({
                width: w1,
                height: h1,
                top: p1Top,
                left: p1Left
            });

            if (this._panel1) {
                this._panel1.setSize(w1, h1);
            }

            this._splitterPos = 0.5;
        }
    };

    SplitPanel.prototype.setPanel = function (panel, container) {
        if (container === 'p1') {
            this._panel1Container.empty();
            this._panel1 = panel;
            this._panel1Container.append(this._panel1.$pEl);
            this._panel1.afterAppend();
            this._setActivePanel(0);
        } else {
            this._panel2Container.empty();
            this._panel2 = panel;
            this._panel2Container.append(this._panel2.$pEl);
            this._panel2.afterAppend();
            this._setActivePanel(1);
        }

        //make sure that read-only info is passed down to the actual panels
        this.onReadOnlyChanged(this._readOnly);

        this._updateUI();
    };

    SplitPanel.prototype.deletePanel = function (container) {
        if (container === 'p1') {
            this._panel1Container.empty();
            this._panel1 = undefined;
            this._setActivePanel(1);
        } else {
            this._panel2Container.empty();
            this._panel2 = undefined;
            this._setActivePanel(0);
        }

        this._updateUI();
    };

    /* OVERRIDE FROM WIDGET-WITH-HEADER */
    /* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
    SplitPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
        //apply parent's onReadOnlyChanged
        PanelBase.prototype.onReadOnlyChanged.call(this, isReadOnly);

        this._readOnly = isReadOnly;

        if (this._panel1) {
            this._panel1.onReadOnlyChanged(isReadOnly);
        }

        if (this._panel2) {
            this._panel2.onReadOnlyChanged(isReadOnly);
        }
    };

    SplitPanel.prototype._setActivePanel = function (p) {
        //if (this._panel1 && this._panel2) {
        WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
        if (p === 0) {
            WebGMEGlobal.PanelManager.setActivePanel(this._panel1);
        }

        if (p === 1) {
            WebGMEGlobal.PanelManager.setActivePanel(this._panel2);
        }
        WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
        //}
    };

    SplitPanel.prototype._startPanelResize = function (event) {
        var self = this,
            verticalSplit = this._width > this._height;

        this._splitterResize = this._splitter.clone().addClass(SPLITTER_RESIZE_CLASS);
        this.$el.append(this._splitterResize);

        this._splitterResizePos = this._splitterPos;
        this._splitStartMousePos = verticalSplit ? event.pageX : event.pageY;

        $(document).on('mousemove.SplitPanel', function (event) {
            self._onMouseMove(event);
        });
        $(document).on('mouseup.SplitPanel', function (event) {
            self._onMouseUp(event);
        });
    };

    SplitPanel.prototype._onMouseMove = function (event) {
        var verticalSplit = this._width > this._height,
            mousePos = verticalSplit ? event.pageX : event.pageY,
            mouseDelta = mousePos - this._splitStartMousePos,
            maxVal = verticalSplit ? this._width : this._height,
            resizeDelta = mouseDelta / maxVal,
            snapDistance = SPLITTER_SNAP_FROM_DISTANCE / maxVal,
            minPanelSize = MINIMUM_PANEL_SIZE / maxVal;

        this._splitterResizePos = this._splitterPos + resizeDelta;

        if (this._splitterResizePos >= 0.5 - snapDistance &&
            this._splitterResizePos <= 0.5 + snapDistance) {
            this._splitterResizePos = 0.5;
        }

        if (this._splitterResizePos < minPanelSize) {
            this._splitterResizePos = minPanelSize;
        }

        if (this._splitterResizePos > 1 - minPanelSize) {
            this._splitterResizePos = 1 - minPanelSize;
        }

        this._updateSplitterResize();
    };

    SplitPanel.prototype._updateSplitterResize = function () {
        var verticalSplit = this._width > this._height,
            sw = SPLITTER_SIZE + 2 * SPLITTER_RESIZE_PADDING,
            sh = SPLITTER_SIZE + 2 * SPLITTER_RESIZE_PADDING,
            splitterLeft,
            splitterTop;

        if (verticalSplit) {
            sh = this._height;
            splitterLeft = Math.floor((this._width - sw) * this._splitterResizePos);
        } else {
            sw = this._width;
            splitterTop = Math.floor((this._height - sh) * this._splitterResizePos);
        }

        this._splitterResize.css({
            width: sw,
            height: sh,
            top: splitterTop,
            left: splitterLeft
        });
    };

    SplitPanel.prototype._onMouseUp = function (event) {
        $(document).off('mousemove.SplitPanel');
        $(document).off('mouseup.SplitPanel');

        this._splitterPos = this._splitterResizePos;

        this._splitterResize.remove();
        this._splitterResize = undefined;
        this._splitterResizePos = undefined;

        this._updateUI();
    };

    return SplitPanel;
});

<commit_msg>#1151 Allow the mousedown event to propagate. (#1156)<commit_after>/*globals define, WebGMEGlobal, _, $*/
/*jshint browser: true*/

/**
 * @author rkereskenyi / https://github.com/rkereskenyi
 */

define(['js/PanelBase/PanelBase', 'css!./styles/SplitPanel.css'], function (PanelBase) {

    'use strict';

    var SplitPanel,
        SPLIT_PANEL_CLASS = 'split-panel',
        PANEL1_CLASS = 'p1',
        PANEL2_CLASS = 'p2',
        SPLITTER_CLASS = 'splitter',
        SPLITTER_SIZE = 4,
        VERTICAL_CLASS = 'vertical',
        HORIZONTAL_CLASS = 'horizontal',
        SPLITTER_RESIZE_CLASS = 'resize',
        MINIMUM_PANEL_SIZE = 50,
        SPLITTER_SNAP_FROM_DISTANCE = 25,
        SPLITTER_RESIZE_PADDING = 2;

    SplitPanel = function (/*layoutManager, params*/) {
        var options = {};
        //set properties from options
        options[PanelBase.OPTIONS.LOGGER_INSTANCE_NAME] = 'SplitPanel';

        //call parent's constructor
        PanelBase.apply(this, [options]);

        this._panel1 = undefined;
        this._panel2 = undefined;

        this._readOnly = false;

        this._splitterPos = 0.5;

        //initialize UI
        this._initialize();

        this.logger.debug('SplitPanel ctor finished');
    };

    //inherit from PanelBaseWithHeader
    _.extend(SplitPanel.prototype, PanelBase.prototype);

    SplitPanel.prototype.onResize = function (width, height) {
        this.logger.debug('onResize --> width: ' + width + ', height: ' + height);

        this._width = width;
        this._height = height;

        this.$el.width(this._width);
        this.$el.height(this._height);

        this._updateUI();
    };

    SplitPanel.prototype._initialize = function () {
        var self = this;

        this.$el.addClass(SPLIT_PANEL_CLASS);

        this._panel1Container = $('<div/>', {class: PANEL1_CLASS});
        this.$el.append(this._panel1Container);

        this._splitter = $('<div/>', {class: SPLITTER_CLASS});
        this.$el.append(this._splitter);

        this._panel2Container = $('<div/>', {class: PANEL2_CLASS});
        this.$el.append(this._panel2Container);

        this._panel1Container.on('mousedown', function (event) {
            self._setActivePanel(0);
            //#1151 event.stopPropagation();
        });

        this._panel2Container.on('mousedown', function (event) {
            self._setActivePanel(1);
            //#1151 event.stopPropagation();
        });

        this._splitter.on('mousedown', function (event) {
            self._startPanelResize(event);
            event.stopPropagation();
            event.preventDefault();
        });

        this._updateUI();
    };

    SplitPanel.prototype._updateUI = function () {
        var verticalSplit = this._width > this._height,
            w1 = this._width,
            h1 = this._height,
            w2 = this._width,
            h2 = this._height,
            sw = SPLITTER_SIZE,
            sh = SPLITTER_SIZE,
            p1Top = 0,
            p1Left = 0,
            splitterTop = 0,
            splitterLeft = 0,
            p2Top = 0,
            p2Left = 0,
            has2Panels = this._panel2 !== undefined;

        if (has2Panels) {
            this._splitter.show();
            this._panel2Container.show();
            this._splitter.removeClass([VERTICAL_CLASS, HORIZONTAL_CLASS].join(' '));
        } else {
            this._splitter.hide();
            this._panel2Container.hide();
        }

        if (has2Panels) {
            if (verticalSplit) {
                sh = this._height;
                w1 = Math.floor((this._width - sw) * this._splitterPos);
                w2 = this._width - w1 - sw;
                this._splitter.addClass(VERTICAL_CLASS);
                p1Left = 0;
                splitterLeft = w1;
                p2Left = w1 + sw;
            } else {
                sw = this._width;
                h1 = Math.floor((this._height - sh) * this._splitterPos);
                h2 = this._height - h1 - sh;
                this._splitter.addClass(HORIZONTAL_CLASS);
                p1Top = 0;
                splitterTop = h1;
                p2Top = h1 + sh;
            }

            this._splitter.css({
                width: sw,
                height: sh,
                top: splitterTop,
                left: splitterLeft
            });

            this._panel1Container.css({
                width: w1,
                height: h1,
                top: p1Top,
                left: p1Left
            });

            this._panel2Container.css({
                width: w2,
                height: h2,
                top: p2Top,
                left: p2Left
            });

            if (this._panel1) {
                this._panel1.setSize(w1, h1);
            }

            if (this._panel2) {
                this._panel2.setSize(w2, h2);
            }
        } else {
            this._panel1Container.css({
                width: w1,
                height: h1,
                top: p1Top,
                left: p1Left
            });

            if (this._panel1) {
                this._panel1.setSize(w1, h1);
            }

            this._splitterPos = 0.5;
        }
    };

    SplitPanel.prototype.setPanel = function (panel, container) {
        if (container === 'p1') {
            this._panel1Container.empty();
            this._panel1 = panel;
            this._panel1Container.append(this._panel1.$pEl);
            this._panel1.afterAppend();
            this._setActivePanel(0);
        } else {
            this._panel2Container.empty();
            this._panel2 = panel;
            this._panel2Container.append(this._panel2.$pEl);
            this._panel2.afterAppend();
            this._setActivePanel(1);
        }

        //make sure that read-only info is passed down to the actual panels
        this.onReadOnlyChanged(this._readOnly);

        this._updateUI();
    };

    SplitPanel.prototype.deletePanel = function (container) {
        if (container === 'p1') {
            this._panel1Container.empty();
            this._panel1 = undefined;
            this._setActivePanel(1);
        } else {
            this._panel2Container.empty();
            this._panel2 = undefined;
            this._setActivePanel(0);
        }

        this._updateUI();
    };

    /* OVERRIDE FROM WIDGET-WITH-HEADER */
    /* METHOD CALLED WHEN THE WIDGET'S READ-ONLY PROPERTY CHANGES */
    SplitPanel.prototype.onReadOnlyChanged = function (isReadOnly) {
        //apply parent's onReadOnlyChanged
        PanelBase.prototype.onReadOnlyChanged.call(this, isReadOnly);

        this._readOnly = isReadOnly;

        if (this._panel1) {
            this._panel1.onReadOnlyChanged(isReadOnly);
        }

        if (this._panel2) {
            this._panel2.onReadOnlyChanged(isReadOnly);
        }
    };

    SplitPanel.prototype._setActivePanel = function (p) {
        //if (this._panel1 && this._panel2) {
        WebGMEGlobal.State.registerSuppressVisualizerFromNode(true);
        if (p === 0) {
            WebGMEGlobal.PanelManager.setActivePanel(this._panel1);
        }

        if (p === 1) {
            WebGMEGlobal.PanelManager.setActivePanel(this._panel2);
        }
        WebGMEGlobal.State.registerSuppressVisualizerFromNode(false);
        //}
    };

    SplitPanel.prototype._startPanelResize = function (event) {
        var self = this,
            verticalSplit = this._width > this._height;

        this._splitterResize = this._splitter.clone().addClass(SPLITTER_RESIZE_CLASS);
        this.$el.append(this._splitterResize);

        this._splitterResizePos = this._splitterPos;
        this._splitStartMousePos = verticalSplit ? event.pageX : event.pageY;

        $(document).on('mousemove.SplitPanel', function (event) {
            self._onMouseMove(event);
        });
        $(document).on('mouseup.SplitPanel', function (event) {
            self._onMouseUp(event);
        });
    };

    SplitPanel.prototype._onMouseMove = function (event) {
        var verticalSplit = this._width > this._height,
            mousePos = verticalSplit ? event.pageX : event.pageY,
            mouseDelta = mousePos - this._splitStartMousePos,
            maxVal = verticalSplit ? this._width : this._height,
            resizeDelta = mouseDelta / maxVal,
            snapDistance = SPLITTER_SNAP_FROM_DISTANCE / maxVal,
            minPanelSize = MINIMUM_PANEL_SIZE / maxVal;

        this._splitterResizePos = this._splitterPos + resizeDelta;

        if (this._splitterResizePos >= 0.5 - snapDistance &&
            this._splitterResizePos <= 0.5 + snapDistance) {
            this._splitterResizePos = 0.5;
        }

        if (this._splitterResizePos < minPanelSize) {
            this._splitterResizePos = minPanelSize;
        }

        if (this._splitterResizePos > 1 - minPanelSize) {
            this._splitterResizePos = 1 - minPanelSize;
        }

        this._updateSplitterResize();
    };

    SplitPanel.prototype._updateSplitterResize = function () {
        var verticalSplit = this._width > this._height,
            sw = SPLITTER_SIZE + 2 * SPLITTER_RESIZE_PADDING,
            sh = SPLITTER_SIZE + 2 * SPLITTER_RESIZE_PADDING,
            splitterLeft,
            splitterTop;

        if (verticalSplit) {
            sh = this._height;
            splitterLeft = Math.floor((this._width - sw) * this._splitterResizePos);
        } else {
            sw = this._width;
            splitterTop = Math.floor((this._height - sh) * this._splitterResizePos);
        }

        this._splitterResize.css({
            width: sw,
            height: sh,
            top: splitterTop,
            left: splitterLeft
        });
    };

    SplitPanel.prototype._onMouseUp = function (event) {
        $(document).off('mousemove.SplitPanel');
        $(document).off('mouseup.SplitPanel');

        this._splitterPos = this._splitterResizePos;

        this._splitterResize.remove();
        this._splitterResize = undefined;
        this._splitterResizePos = undefined;

        this._updateUI();
    };

    return SplitPanel;
});

<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import autobind from 'core-decorators/es/autobind';
import { gql, graphql } from 'react-apollo';
import { connect } from 'react-redux';
import { Intent } from '@blueprintjs/core';
import { refresh, logout } from '../../actions/authActions';
import NotificationToaster from './NotificationToaster';

const MutationAccessRefresh = gql`
mutation GetRefresh($refreshToken: String!){
	refresh(refreshToken:$refreshToken) {
		ok message access_token
  }
}`;

const MutationAccessRefreshOptions = {
	name: 'MutationAccessRefresh'
};

const mapStateToProps = (state, ownProps) => {
	return { authenticated: state.auth.login.authenticated };
}

@connect()
@graphql(MutationAccessRefresh, MutationAccessRefreshOptions)
@autobind
class LoginRefresh extends React.Component {
	static propTypes = {
		interval: PropTypes.number,
		refreshToken: PropTypes.string,
		setRefreshing: PropTypes.func
	}

	static defaultProps = {
		interval: 10 * 60 * 1000	// default interval of 10 minutes
	}

	componentWillUnmount() {
		// Stop timer
		if (this.interval) {
			clearInterval(this.interval);
		}
	}

	componentDidMount() {
		// Start timer
		this.refreshAccessToken();
		this.interval = setInterval(this.refresh, this.props.interval);
	}

	async refreshAccessToken() {
		if (!this.props.authenticated) {
			// Don't need to do anything if not authenticated
			return;
		}

		if (!this.props.refreshToken) {
			// Don't try to refresh if there is no refresh token
			this._dispatchLogout();
			return;
		}

		if (this.props.setRefreshing) this.props.setRefreshing(true);

		// Send refresh request
		try {
			const result = await this.props.MutationAccessRefresh({
				variables: { refreshToken: this.props.refreshToken }
			});

			if (result.data.refresh.ok) {
				// Refresh successful
				if (this.props.setRefreshing) this.props.setRefreshing(false);
				this._dispatchRefresh(result.data.refresh.access_token);
			}
			else {
				// Refresh failed
				if (this.props.setRefreshing) this.props.setRefreshing(false, result.data.refresh.message);
				this._dispatchLogout();
			}
		}
		catch (err) {
			if (this.props.setRefreshing) this.props.setRefreshing(false, err.toString());
			this._dispatchLogout();
		}
	}

	_dispatchRefresh(accessToken) {
		this.props.dispatch(refresh(accessToken), new Date());
	}

	_dispatchLogout() {
		this.props.dispatch(logout(new Date()));
	}

	render() {
		return null;
	}
}

export default LoginRefresh;
<commit_msg>[FIX] Fix LoginRefresher wrongly named interval function<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import autobind from 'core-decorators/es/autobind';
import { gql, graphql } from 'react-apollo';
import { connect } from 'react-redux';
import { Intent } from '@blueprintjs/core';
import { refresh, logout } from '../../actions/authActions';
import NotificationToaster from './NotificationToaster';

const MutationAccessRefresh = gql`
mutation GetRefresh($refreshToken: String!){
	refresh(refreshToken:$refreshToken) {
		ok message access_token
  }
}`;

const MutationAccessRefreshOptions = {
	name: 'MutationAccessRefresh'
};

const mapStateToProps = (state, ownProps) => {
	return { authenticated: state.auth.login.authenticated };
}

@connect()
@graphql(MutationAccessRefresh, MutationAccessRefreshOptions)
@autobind
class LoginRefresh extends React.Component {
	static propTypes = {
		interval: PropTypes.number,
		refreshToken: PropTypes.string,
		setRefreshing: PropTypes.func
	}

	static defaultProps = {
		interval: 10 * 60 * 1000	// default interval of 10 minutes
	}

	componentWillUnmount() {
		// Stop timer
		if (this.refreshInterval) {
			clearInterval(this.refreshInterval);
		}
	}

	componentDidMount() {
		// Start timer
		this.refreshAccessToken();
		this.refreshInterval = setInterval(this.refreshAccessToken, this.props.interval);
	}

	async refreshAccessToken() {
		if (!this.props.authenticated) {
			// Don't need to do anything if not authenticated
			return;
		}

		if (!this.props.refreshToken) {
			// Don't try to refresh if there is no refresh token
			this._dispatchLogout();
			return;
		}

		if (this.props.setRefreshing) this.props.setRefreshing(true);

		// Send refresh request
		try {
			const result = await this.props.MutationAccessRefresh({
				variables: { refreshToken: this.props.refreshToken }
			});

			if (result.data.refresh.ok) {
				// Refresh successful
				if (this.props.setRefreshing) this.props.setRefreshing(false);
				this._dispatchRefresh(result.data.refresh.access_token);
			}
			else {
				// Refresh failed
				if (this.props.setRefreshing) this.props.setRefreshing(false, result.data.refresh.message);
				this._dispatchLogout();
			}
		}
		catch (err) {
			if (this.props.setRefreshing) this.props.setRefreshing(false, err.toString());
			this._dispatchLogout();
		}
	}

	_dispatchRefresh(accessToken) {
		this.props.dispatch(refresh(accessToken), new Date());
	}

	_dispatchLogout() {
		this.props.dispatch(logout(new Date()));
	}

	render() {
		return null;
	}
}

export default LoginRefresh;
<|endoftext|>


<commit_before>const hasOwnProperty = Object.prototype.hasOwnProperty;

export function assert(condition, message) {
  if(!condition) {
    throw Error(message);
  }
}

export function forKeys(obj, callback) {
  if(typeof obj === 'object') {
    for(let key in obj) {
      if(hasOwnProperty.call(obj, key)) {
        callback(key, obj[key]);
      }
    }
  }
}

export function splitOn(str, delimiter) {
  const index = str.indexOf(delimiter);
  assert(index >= 0, `"${str}" does not contain "${delimiter}"!`);
  return { start: str.substr(0, index), end: str.substr(index + 1) };
}
<commit_msg>Change typeof check to != null check<commit_after>const hasOwnProperty = Object.prototype.hasOwnProperty;

export function assert(condition, message) {
  if(!condition) {
    throw Error(message);
  }
}

export function forKeys(obj, callback) {
  if(obj != null) {
    for(let key in obj) {
      if(hasOwnProperty.call(obj, key)) {
        callback(key, obj[key]);
      }
    }
  }
}

export function splitOn(str, delimiter) {
  const index = str.indexOf(delimiter);
  assert(index >= 0, `"${str}" does not contain "${delimiter}"!`);
  return { start: str.substr(0, index), end: str.substr(index + 1) };
}
<|endoftext|>