<commit_before>(function (root, factory) {
  if(typeof define === "function" && define.amd) {
    define(["openlayers"], factory);
  } else if(typeof module === "object" && module.exports) {
    module.exports = factory(require("openlayers"));
  } else {
    root.LayerSwitcher = factory(root.ol);
  }
}(this, function(ol) {
  /**
   * OpenLayers v3/v4 Layer Switcher Control.
   * See [the examples](./examples) for usage.
   * @constructor
   * @extends {ol.control.Control}
   * @param {Object} opt_options Control options, extends olx.control.ControlOptions adding:
   *                              **`tipLabel`** `String` - the button tooltip.
   */
  ol.control.LayerSwitcher = function(opt_options) {

    var options = opt_options || {};

    var tipLabel = options.tipLabel ?
      options.tipLabel : 'Legend';

    this.mapListeners = [];

    this.hiddenClassName = 'ol-unselectable ol-control layer-switcher';
    if (ol.control.LayerSwitcher.isTouchDevice_()) {
      this.hiddenClassName += ' touch';
    }
    this.shownClassName = 'shown';

    var element = document.createElement('div');
    element.className = this.hiddenClassName;

    var button = document.createElement('button');
    button.setAttribute('title', tipLabel);
    element.appendChild(button);

    this.panel = document.createElement('div');
    this.panel.className = 'panel';
    element.appendChild(this.panel);
    ol.control.LayerSwitcher.enableTouchScroll_(this.panel);

    var this_ = this;

    button.onmouseover = function(e) {
      this_.showPanel();
    };

    button.onclick = function(e) {
      e = e || window.event;
      this_.showPanel();
      e.preventDefault();
    };

    this_.panel.onmouseout = function(e) {
      e = e || window.event;
      if (!this_.panel.contains(e.toElement || e.relatedTarget)) {
        this_.hidePanel();
      }
    };

    ol.control.Control.call(this, {
      element: element,
      target: options.target
    });

  };

  ol.inherits(ol.control.LayerSwitcher, ol.control.Control);

  /**
   * Show the layer panel.
   */
  ol.control.LayerSwitcher.prototype.showPanel = function() {
    if (!this.element.classList.contains(this.shownClassName)) {
      this.element.classList.add(this.shownClassName);
      this.renderPanel();
    }
  };

  /**
   * Hide the layer panel.
   */
  ol.control.LayerSwitcher.prototype.hidePanel = function() {
    if (this.element.classList.contains(this.shownClassName)) {
      this.element.classList.remove(this.shownClassName);
    }
  };

  /**
   * Re-draw the layer panel to represent the current state of the layers.
   */
  ol.control.LayerSwitcher.prototype.renderPanel = function() {

    this.ensureTopVisibleBaseLayerShown_();

    while(this.panel.firstChild) {
      this.panel.removeChild(this.panel.firstChild);
    }

    var ul = document.createElement('ul');
    this.panel.appendChild(ul);
    this.renderLayers_(this.getMap(), ul);

  };

  /**
   * Set the map instance the control is associated with.
   * @param {ol.Map} map The map instance.
   */
  ol.control.LayerSwitcher.prototype.setMap = function(map) {
    // Clean up listeners associated with the previous map
    for (var i = 0, key; i < this.mapListeners.length; i++) {
      ol.Observable.unByKey(this.mapListeners[i]);
    }
    this.mapListeners.length = 0;
    // Wire up listeners etc. and store reference to new map
    ol.control.Control.prototype.setMap.call(this, map);
    if (map) {
      var this_ = this;
      this.mapListeners.push(map.on('pointerdown', function() {
        this_.hidePanel();
      }));
      this.renderPanel();
    }
  };

  /**
   * Ensure only the top-most base layer is visible if more than one is visible.
   * @private
   */
  ol.control.LayerSwitcher.prototype.ensureTopVisibleBaseLayerShown_ = function() {
    var lastVisibleBaseLyr;
    ol.control.LayerSwitcher.forEachRecursive(this.getMap(), function(l, idx, a) {
      if (l.get('type') === 'base' && l.getVisible()) {
        lastVisibleBaseLyr = l;
      }
    });
    if (lastVisibleBaseLyr) this.setVisible_(lastVisibleBaseLyr, true);
  };

  /**
   * Toggle the visible state of a layer.
   * Takes care of hiding other layers in the same exclusive group if the layer
   * is toggle to visible.
   * @private
   * @param {ol.layer.Base} The layer whos visibility will be toggled.
   */
  ol.control.LayerSwitcher.prototype.setVisible_ = function(lyr, visible) {
    var map = this.getMap();
    lyr.setVisible(visible);
    if (visible && lyr.get('type') === 'base') {
      // Hide all other base layers regardless of grouping
      ol.control.LayerSwitcher.forEachRecursive(map, function(l, idx, a) {
        if (l != lyr && l.get('type') === 'base') {
          l.setVisible(false);
        }
      });
    }
    if (lyr.getLayers && !lyr.get('combine')){
      var lyrs = lyr.getLayers().getArray().slice().reverse();
      for (var i = 0; i < lyrs.length; i++) {
        var lyr = lyrs[i];
        var lyrId = lyr.get('id');
        var subLyr = document.getElementById(lyrId);
        subLyr.disabled = !visible;
      }
    }
  };

  /**
   * Render all layers that are children of a group.
   * @private
   * @param {ol.layer.Base} lyr Layer to be rendered (should have a title property).
   * @param {Number} idx Position in parent group list.
   */
  ol.control.LayerSwitcher.prototype.renderLayer_ = function(lyr, idx) {

    var this_ = this;

    var li = document.createElement('li');

    var lyrTitle = lyr.get('title');
    var lyrId = ol.control.LayerSwitcher.uuid();
    lyr.set('id', lyrId);

    var label = document.createElement('label');

    if (lyr.getLayers && !lyr.get('combine')) {

      var input = document.createElement('input');
      input.type = 'checkbox';
      input.id = lyrId;
      input.checked = lyr.get('visible');
      input.onchange = function(e) {
        this_.setVisible_(lyr, e.target.checked);
      };
      li.appendChild(input);

      li.className = 'group';
      label.innerHTML = lyrTitle;
      label.htmlFor = lyrId;
      li.appendChild(label);
      var ul = document.createElement('ul');
      li.appendChild(ul);

      this.renderLayers_(lyr, ul);

    } else {

      li.className = 'layer';
      var input = document.createElement('input');
      if (lyr.get('type') === 'base') {
        input.type = 'radio';
        input.name = 'base';
      } else {
        input.type = 'checkbox';
      }
      input.id = lyrId;
      input.checked = lyr.get('visible');
      input.onchange = function(e) {
        this_.setVisible_(lyr, e.target.checked);
      };
      li.appendChild(input);

      label.htmlFor = lyrId;
      label.innerHTML = lyrTitle;

      var rsl = this.getMap().getView().getResolution();
      if (rsl > lyr.getMaxResolution() || rsl < lyr.getMinResolution()){
        label.className += ' disabled';
      }

      li.appendChild(label);

    }

    return li;

  };

  /**
   * Render all layers that are children of a group.
   * @private
   * @param {ol.layer.Group} lyr Group layer whos children will be rendered.
   * @param {Element} elm DOM element that children will be appended to.
   */
  ol.control.LayerSwitcher.prototype.renderLayers_ = function(lyr, elm) {
    var lyrs = lyr.getLayers().getArray().slice().reverse();
    for (var i = 0, l; i < lyrs.length; i++) {
      l = lyrs[i];
      if (l.get('title')) {
        elm.appendChild(this.renderLayer_(l, i));
      }
    }
  };

  /**
   * **Static** Call the supplied function for each layer in the passed layer group
   * recursing nested groups.
   * @param {ol.layer.Group} lyr The layer group to start iterating from.
   * @param {Function} fn Callback which will be called for each `ol.layer.Base`
   * found under `lyr`. The signature for `fn` is the same as `ol.Collection#forEach`
   */
  ol.control.LayerSwitcher.forEachRecursive = function(lyr, fn) {
    lyr.getLayers().forEach(function(lyr, idx, a) {
      fn(lyr, idx, a);
      if (lyr.getLayers) {
        ol.control.LayerSwitcher.forEachRecursive(lyr, fn);
      }
    });
  };

  /**
   * Generate a UUID
   * @returns {String} UUID
   *
   * Adapted from http://stackoverflow.com/a/2117523/526860
   */
  ol.control.LayerSwitcher.uuid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
      return v.toString(16);
    });
  }

  /**
   * @private
   * @desc Apply workaround to enable scrolling of overflowing content within an
   * element. Adapted from https://gist.github.com/chrismbarr/4107472
   */
  ol.control.LayerSwitcher.enableTouchScroll_ = function(elm) {
    if(ol.control.LayerSwitcher.isTouchDevice_()){
      var scrollStartPos = 0;
      elm.addEventListener("touchstart", function(event) {
        scrollStartPos = this.scrollTop + event.touches[0].pageY;
      }, false);
      elm.addEventListener("touchmove", function(event) {
        this.scrollTop = scrollStartPos - event.touches[0].pageY;
      }, false);
    }
  };

  /**
   * @private
   * @desc Determine if the current browser supports touch events. Adapted from
   * https://gist.github.com/chrismbarr/4107472
   */
  ol.control.LayerSwitcher.isTouchDevice_ = function() {
    try {
      document.createEvent("TouchEvent");
      return true;
    } catch(e) {
      return false;
    }
  };
  var LayerSwitcher = ol.control.LayerSwitcher;
  return LayerSwitcher;
}));<commit_msg>layerswitcher expand and collapse groups<commit_after>(function (root, factory) {
  if(typeof define === "function" && define.amd) {
    define(["openlayers"], factory);
  } else if(typeof module === "object" && module.exports) {
    module.exports = factory(require("openlayers"));
  } else {
    root.LayerSwitcher = factory(root.ol);
  }
}(this, function(ol) {
  /**
   * OpenLayers v3/v4 Layer Switcher Control.
   * See [the examples](./examples) for usage.
   * @constructor
   * @extends {ol.control.Control}
   * @param {Object} opt_options Control options, extends olx.control.ControlOptions adding:
   *                              **`tipLabel`** `String` - the button tooltip.
   */
  ol.control.LayerSwitcher = function(opt_options) {

    var options = opt_options || {};

    var tipLabel = options.tipLabel ?
      options.tipLabel : 'Legend';

    this.mapListeners = [];

    this.hiddenClassName = 'ol-unselectable ol-control layer-switcher';
    if (ol.control.LayerSwitcher.isTouchDevice_()) {
      this.hiddenClassName += ' touch';
    }
    this.shownClassName = 'shown';

    var element = document.createElement('div');
    element.className = this.hiddenClassName;

    var button = document.createElement('button');
    button.setAttribute('title', tipLabel);
    element.appendChild(button);

    this.panel = document.createElement('div');
    this.panel.className = 'panel';
    element.appendChild(this.panel);
    ol.control.LayerSwitcher.enableTouchScroll_(this.panel);

    var this_ = this;

    button.onmouseover = function(e) {
      this_.showPanel();
    };

    button.onclick = function(e) {
      e = e || window.event;
      this_.showPanel();
      e.preventDefault();
    };

    this_.panel.onmouseout = function(e) {
      e = e || window.event;
      if (!this_.panel.contains(e.toElement || e.relatedTarget)) {
        this_.hidePanel();
      }
    };

    ol.control.Control.call(this, {
      element: element,
      target: options.target
    });

  };

  ol.inherits(ol.control.LayerSwitcher, ol.control.Control);

  /**
   * Show the layer panel.
   */
  ol.control.LayerSwitcher.prototype.showPanel = function() {
    if (!this.element.classList.contains(this.shownClassName)) {
      this.element.classList.add(this.shownClassName);
      this.renderPanel();
    }
  };

  /**
   * Hide the layer panel.
   */
  ol.control.LayerSwitcher.prototype.hidePanel = function() {
    if (this.element.classList.contains(this.shownClassName)) {
      this.element.classList.remove(this.shownClassName);
    }
  };

  /**
   * Re-draw the layer panel to represent the current state of the layers.
   */
  ol.control.LayerSwitcher.prototype.renderPanel = function() {

    this.ensureTopVisibleBaseLayerShown_();

    while(this.panel.firstChild) {
      this.panel.removeChild(this.panel.firstChild);
    }

    var ul = document.createElement('ul');
    this.panel.appendChild(ul);
    this.renderLayers_(this.getMap(), ul);

  };

  /**
   * Set the map instance the control is associated with.
   * @param {ol.Map} map The map instance.
   */
  ol.control.LayerSwitcher.prototype.setMap = function(map) {
    // Clean up listeners associated with the previous map
    for (var i = 0, key; i < this.mapListeners.length; i++) {
      ol.Observable.unByKey(this.mapListeners[i]);
    }
    this.mapListeners.length = 0;
    // Wire up listeners etc. and store reference to new map
    ol.control.Control.prototype.setMap.call(this, map);
    if (map) {
      var this_ = this;
      this.mapListeners.push(map.on('pointerdown', function() {
        this_.hidePanel();
      }));
      this.renderPanel();
    }
  };

  /**
   * Ensure only the top-most base layer is visible if more than one is visible.
   * @private
   */
  ol.control.LayerSwitcher.prototype.ensureTopVisibleBaseLayerShown_ = function() {
    var lastVisibleBaseLyr;
    ol.control.LayerSwitcher.forEachRecursive(this.getMap(), function(l, idx, a) {
      if (l.get('type') === 'base' && l.getVisible()) {
        lastVisibleBaseLyr = l;
      }
    });
    if (lastVisibleBaseLyr) this.setVisible_(lastVisibleBaseLyr, true);
  };

  /**
   * Toggle the visible state of a layer.
   * Takes care of hiding other layers in the same exclusive group if the layer
   * is toggle to visible.
   * @private
   * @param {ol.layer.Base} The layer whos visibility will be toggled.
   */
  ol.control.LayerSwitcher.prototype.setVisible_ = function(lyr, visible) {
    var map = this.getMap();
    lyr.setVisible(visible);
    if (visible && lyr.get('type') === 'base') {
      // Hide all other base layers regardless of grouping
      ol.control.LayerSwitcher.forEachRecursive(map, function(l, idx, a) {
        if (l != lyr && l.get('type') === 'base') {
          l.setVisible(false);
        }
      });
    }
    if (lyr.getLayers && !lyr.get('combine')){
      var lyrs = lyr.getLayers().getArray().slice().reverse();
      for (var i = 0; i < lyrs.length; i++) {
        var lyr = lyrs[i];
        var lyrId = lyr.get('id');
        var subLyr = document.getElementById(lyrId);
        subLyr.disabled = !visible;
      }
    }
  };

  /**
   * Render all layers that are children of a group.
   * @private
   * @param {ol.layer.Base} lyr Layer to be rendered (should have a title property).
   * @param {Number} idx Position in parent group list.
   */
  ol.control.LayerSwitcher.prototype.renderLayer_ = function(lyr, idx) {

    var this_ = this;

    var li = document.createElement('li');

    var lyrTitle = lyr.get('title');
    var lyrId = ol.control.LayerSwitcher.uuid();
    lyr.set('id', lyrId);

    var label = document.createElement('label');

    if (lyr.getLayers && !lyr.get('combine')) {

      // This section addded by Jessica to expand and collapse groups
      var toggleBtn = document.createElement('i');
      toggleBtn.className = 'icon ion-minus-round';
      toggleBtn.id = 'toggleButton';
      li.appendChild(toggleBtn);
      toggleBtn.addEventListener ('click', function() {
        toggleGroup(lyr);
        if (toggleBtn.className === 'icon ion-minus-round') toggleBtn.className = 'icon ion-plus-round';
        else toggleBtn.className = 'icon ion-minus-round';
      });
      // End this section added by Jessica

      var input = document.createElement('input');
      input.type = 'checkbox';
      input.id = lyrId;
      input.checked = lyr.get('visible');
      input.onchange = function(e) {
        this_.setVisible_(lyr, e.target.checked);
      };
      li.appendChild(input);

      li.className = 'group';
      label.innerHTML = lyrTitle;
      label.htmlFor = lyrId;
      li.appendChild(label);
      var ul = document.createElement('ul');
      li.appendChild(ul);

      this.renderLayers_(lyr, ul);

    } else {

      li.className = 'layer';
      li.id = 'layer' + lyrId;    // This addded by Jessica to expand and collapse groups
      var input = document.createElement('input');
      if (lyr.get('type') === 'base') {
        input.type = 'radio';
        input.name = 'base';
      } else {
        input.type = 'checkbox';
      }
      input.id = lyrId;
      input.checked = lyr.get('visible');
      input.onchange = function(e) {
        this_.setVisible_(lyr, e.target.checked);
      };
      li.appendChild(input);

      label.htmlFor = lyrId;
      label.innerHTML = lyrTitle;

      var rsl = this.getMap().getView().getResolution();
      if (rsl > lyr.getMaxResolution() || rsl < lyr.getMinResolution()){
        label.className += ' disabled';
      }

      li.appendChild(label);

    }

    return li;

  };

  /**
   * Render all layers that are children of a group.
   * @private
   * @param {ol.layer.Group} lyr Group layer whos children will be rendered.
   * @param {Element} elm DOM element that children will be appended to.
   */
  ol.control.LayerSwitcher.prototype.renderLayers_ = function(lyr, elm) {
    var lyrs = lyr.getLayers().getArray().slice().reverse();
    for (var i = 0, l; i < lyrs.length; i++) {
      l = lyrs[i];
      if (l.get('title')) {
        elm.appendChild(this.renderLayer_(l, i));
      }
    }
  };

  /**
   * **Static** Call the supplied function for each layer in the passed layer group
   * recursing nested groups.
   * @param {ol.layer.Group} lyr The layer group to start iterating from.
   * @param {Function} fn Callback which will be called for each `ol.layer.Base`
   * found under `lyr`. The signature for `fn` is the same as `ol.Collection#forEach`
   */
  ol.control.LayerSwitcher.forEachRecursive = function(lyr, fn) {
    lyr.getLayers().forEach(function(lyr, idx, a) {
      fn(lyr, idx, a);
      if (lyr.getLayers) {
        ol.control.LayerSwitcher.forEachRecursive(lyr, fn);
      }
    });
  };

  /**
   * Generate a UUID
   * @returns {String} UUID
   *
   * Adapted from http://stackoverflow.com/a/2117523/526860
   */
  ol.control.LayerSwitcher.uuid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
      var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
      return v.toString(16);
    });
  }

  /**
   * @private
   * @desc Apply workaround to enable scrolling of overflowing content within an
   * element. Adapted from https://gist.github.com/chrismbarr/4107472
   */
  ol.control.LayerSwitcher.enableTouchScroll_ = function(elm) {
    if(ol.control.LayerSwitcher.isTouchDevice_()){
      var scrollStartPos = 0;
      elm.addEventListener("touchstart", function(event) {
        scrollStartPos = this.scrollTop + event.touches[0].pageY;
      }, false);
      elm.addEventListener("touchmove", function(event) {
        this.scrollTop = scrollStartPos - event.touches[0].pageY;
      }, false);
    }
  };

  /**
   * @private
   * @desc Determine if the current browser supports touch events. Adapted from
   * https://gist.github.com/chrismbarr/4107472
   */
  ol.control.LayerSwitcher.isTouchDevice_ = function() {
    try {
      document.createEvent("TouchEvent");
      return true;
    } catch(e) {
      return false;
    }
  };

  // This section addded by Jessica to expand and collapse groups
  function toggleGroup(lyr, toggleBtn) {
    lyr.getLayersArray().forEach(function (layer) {
      var layerEle = document.getElementById('layer' + layer.get('id'));
      if (layerEle.style.display === '' || layerEle.style.display === 'table') layerEle.style.display = 'none';
      else layerEle.style.display = 'table';
    });
  }
  // End this section addded by Jessica

  var LayerSwitcher = ol.control.LayerSwitcher;
  return LayerSwitcher;
}));<|endoftext|>


<commit_before>document.documentElement.style.height = '100%';
document.body.style.height = '100%';
document.documentElement.style.width = '100%';
document.body.style.width = '100%';

var div = document.createElement('div');
div.style.height = '100%';
div.style.float = 'right';
div.style.width = '30%';
div.style.backgroundColor = 'snow';
div.style.position = 'relative';
div.style.zIndex = '1000';
var ul = document.createElement('ul');
document.body.appendChild(div);
div.appendChild(ul);

function startQuery(quer){
  var searchUrl = 'https://api.wolframalpha.com/v2/query' + '?appid=' + encodeURIComponent(appID) +
  '&input=' + quer + '&format=plaintext&output=JSON';
  var x = new XMLHttpRequest();
//  x.responseType = 'json';
  x.onload = function() {
    var response = JSON.parse(x.response);
    console.log(response);
    if (!response || !response["queryresult"]["success"] || response["queryresult"]["error"] ){
      console.log('Invalid search to Wolfram');
      return;
    }
    var pods = response["queryresult"]["pods"];
    console.log(pods);
    for(i = 0; i < pods.length; i++) {
      var li = document.createElement('li');
      var tex = document.createTextNode(pods[i].subpods[0].plaintext);
//      var descrip = document.createTextNode(pod[i].childNodes[3]]);
      li.appendChild(tex);
//      li2.appendChild(descrip);
      ul.appendChild(li);
//      ul.appendChild(li2);
    };
  };
  x.onerror = function(err) {
    console.log(err);
  };
  x.open('GET', searchUrl, true);
  x.send();
}

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  console.log("Message recieved");
  if(request.message === "open_sidebar"){
    console.log("Selection event. Looking up: " + request.content);
    startQuery(request.content);
    return true;
  }});

/*
var isSidebarOpen = false;
function openInfo(lookup){

return true;
}

var firstChild = document.body.childNodes[0];
var toInsert = document.createElement("div");
toInsert.className = "ui right vertical sidebar";
toInsert.innerHTML = "123"
document.body.insertBefore(toInsert, firstChild);
*/
<commit_msg>Added function to get link from Dictionary.com<commit_after>document.documentElement.style.height = '100%';
document.body.style.height = '100%';
document.documentElement.style.width = '100%';
document.body.style.width = '100%';

var div = document.createElement('div');
div.style.height = '100%';
div.style.float = 'right';
div.style.width = '30%';
div.style.backgroundColor = 'snow';
div.style.position = 'relative';
div.style.zIndex = '1000';
var ul = document.createElement('ul');
document.body.appendChild(div);
div.appendChild(ul);
var a = document.createElement('a');
div.appendChild(a);

function getDictLink(quer){
            var linkText = document.createTextNode("Dictionary reference for " + quer);
            a.appendChild(linkText);
            a.title = "Dictionary.com entry for " + quer;
            a.href = "http://www.dictionary.com/browse/" + quer + "?s=t";
            a.appendChild(a);
}

function startQuery(quer){
  var searchUrl = 'https://api.wolframalpha.com/v2/query' + '?appid=' + encodeURIComponent(appID) +
  '&input=' + quer + '&format=plaintext&output=JSON';
  var x = new XMLHttpRequest();
//  x.responseType = 'json';
  x.onload = function() {
    var response = JSON.parse(x.response);
    console.log(response);
    if (!response || !response["queryresult"]["success"] || response["queryresult"]["error"] ){
      console.log('Invalid search to Wolfram');
      return;
    }
    var pods = response["queryresult"]["pods"];
    console.log(pods);
    for(i = 0; i < pods.length; i++) {
      var li = document.createElement('li');
      var tex = document.createTextNode(pods[i].subpods[0].plaintext);
//      var descrip = document.createTextNode(pod[i].childNodes[3]]);
      li.appendChild(tex);
//      li2.appendChild(descrip);
      ul.appendChild(li);
//      ul.appendChild(li2);
    };
    getDictLink(quer);
  };
  x.onerror = function(err) {
    console.log(err);
  };
  x.open('GET', searchUrl, true);
  x.send();
}

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  console.log("Message recieved");
  if(request.message === "open_sidebar"){
    console.log("Selection event. Looking up: " + request.content);
    startQuery(request.content);
    return true;
  }});

/*
var isSidebarOpen = false;
function openInfo(lookup){

return true;
}

var firstChild = document.body.childNodes[0];
var toInsert = document.createElement("div");
toInsert.className = "ui right vertical sidebar";
toInsert.innerHTML = "123"
document.body.insertBefore(toInsert, firstChild);
*/
<|endoftext|>


<commit_before><commit_msg>Fixes rootEndPoint<commit_after><|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Question1',
  properties: [
    {
      name: 'question',
      label: 'Who was the best Star Wars robot?',
      view: {
        class: 'foam.u2.view.RadioView',
        placeholder: 'Please select',
        choices: [
          'C3-PO',
          'R2-D2',
          'BB-8',
          'K-2SO'
        ]
      }
    },
    {
      name: 'answer',
      hidden: true,
      value: 'R2-D2'
    }
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Question2',
  properties: [
    {
      name: 'question',
      label: 'Which of the following do robots make',
      view: {
        class: 'foam.u2.view.RadioView',
        placeholder: 'Please select',
        choices: [
          'Cars',
          'Washing Machines',
          'Computers',
          'Robots',
          'All of the Above'

        ]
      }
    },
    {
      name: 'answer',
      hidden: true,
      value: 'All of the Above'
    }
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Door',
  extends: 'foam.graphics.Box',
  properties: [
    [ 'color', 'red' ],
    [ 'isClosed', true ]
  ],
  methods: [
    function open() {
      this.isClosed = false;
      this.rotation = Math.PI / 4;
//      this.width = this.height = 0;
    }
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Wall',
  extends: 'foam.graphics.Box',
  properties: [
    [ 'color', 'gray' ]
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Exit',
  extends: 'foam.graphics.Box',
  properties: [
    [ 'color', 'blue' ]
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Laser',
  extends: 'foam.graphics.Circle',

  requires: [ 'foam.animation.Animation' ],
  imports: [ 'game'],

  properties: [
    [ 'color', 'yellow' ],
    [ 'radius', 12 ],
    'vx',
    'vy'
  ],

  methods: [
    function init() {
      this.SUPER();

      this.game.addChild(this);
      this.Animation.create({
        duration: 5000,
        f: () => {
          this.x += 2000 * this.vx;
          this.y += 2000 * this.vy;
        },
        onEnd: () => this.game.removeChild(this),
        objs: [ this ]
      }).start();
    }
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Game',
  extends: 'foam.u2.Element',

  requires: [
    'com.foamdev.demos.maze.Door',
    'com.foamdev.demos.maze.Exit',
    'com.foamdev.demos.maze.Laser',
    'com.foamdev.demos.maze.Question1',
    'com.foamdev.demos.maze.Question2',
    'com.foamdev.demos.maze.Wall',
    'com.google.foam.demos.robot.Robot',
    'foam.animation.Animation',
    'foam.audio.Speak',
    'foam.graphics.Box as Rectangle',
    'foam.graphics.CView',
    'foam.graphics.Label',
    'foam.input.Gamepad',
    'foam.physics.Collider',
    'foam.util.Timer'
  ],

  exports: [
    'timer',
    'as game'
  ],

  constants: {
    BRICK_SIZE: 40,
    MAZE_HORIZ: [
      ['Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall'],
      ['Wall', null, null, 'Wall', null, 'Wall', null, null, 'Wall'],
      [null, 'Door', null, null, null, null, null, 'Wall', null, 'Wall', 'Wall'],
      [null, 'Wall', 'Wall', null, 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall', null],
      [null, null, 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall', null, 'Wall', 'Wall'],
      [null, null, 'Door', 'Wall', null, 'Door', null, null, null, 'Wall'],
      ['Wall', 'Door', null, 'Wall', null, null, null, null, 'Wall', null, 'Wall'],
      ['Wall', 'Wall', null, 'Wall', 'Wall', null, null, 'Door', null, 'Wall'],
      ['Wall', null, 'Wall', 'Wall', null, 'Wall', null, null, 'Wall', null, 'Wall'],
      [null, null, 'Wall', null, 'Wall', null, 'Wall', null, null, 'Wall', 'Wall'],
      [null, 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', null, 'Wall', null, 'Wall'],
      ['Door', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall']
    ],
    MAZE_VERT: [
      ['Wall', null, 'Wall', null, null, 'Wall', 'Wall', 'Wall', null, null, 'Wall', 'Exit'],
      ['Wall', 'Wall', 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall', null, 'Wall', null, 'Wall'],
      ['Wall', null, null, 'Wall', null, 'Wall', null, null, 'Wall', null, null, 'Wall'],
      ['Wall', 'Wall', null, null, null, null, null, 'Wall', null, null, null, 'Wall'],
      ['Wall', 'Wall', 'Wall', null, null, 'Wall', null, null, 'Wall', 'Wall', null, 'Wall'],
      ['Wall', 'Wall', null, null, 'Wall', null, 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall'],
      ['Wall', null, null, 'Wall', null, 'Door', 'Wall', 'Wall', null, 'Wall', null, 'Wall'],
      ['Wall', null, 'Wall', null, null, null, 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall'],
      ['Wall', 'Wall', null, null, 'Wall', 'Wall', null, 'Wall', 'Wall', null, null, 'Wall'],
      ['Wall', 'Wall', null, 'Wall', null, null, null, 'Wall', null, 'Wall', null, 'Wall'],
      ['Wall', null, null, null, null, null, null, null, 'Wall', null, false, 'Wall']
    ]
   },

  properties: [
    [ 'isGameOver', false ],
    [ 'width', 1600 ],
    [ 'height', 800 ],
    {
      name: 'gamepad',
      factory: function() { return this.Gamepad.create(); }
    },
    {
      name: 'timer',
      factory: function() { return this.Timer.create(); }
    },
    {
      name: 'table',
      factory: function() {
        return this.Rectangle.create({
          color: 'black',
          width: 500, // window.innerWidth,
          height: 500 // window.innerHeight
        });
      }
    },
    {
      name: 'robot',
      factory: function() {
        return this.Robot.create({x:37.5, y:435, scaleX: 0.5, scaleY: 0.5, width: 3, height: 3});
      }
    },
    {
      name: 'collider',
      factory: function() { return this.Collider.create(); }
    },
    'lastX', 'lastY', 'hittingWall',
    'questionArea'
  ],

  methods: [
    function init() {
      this.SUPER();

      this.buildMaze();
      this.addChild(this.robot);

      this.gamepad.pressed.sub('button4', () => this.fire());
      this.gamepad.pressed.sub('button5', () => this.fire());

      // Setup Physics
      this.collider.collide = function(o1, o2) {
        if ( o2 == this.robot ) {
          o2 = o1;
          o1 = this.robot;
        }
        if ( o1 == this.robot ) {
          if ( this.Door.isInstance(o2) ) {
            if ( ! o2.isClosed ) return;
            console.log('*************************** Door');
            o2.open();
            this.hittingWall = true;
            this.questionArea.removeAllChildren();
            this.questionArea.add(this.Question1.create());
          } else if ( this.Wall.isInstance(o2) ) {
            console.log('*************************** Wall');
            this.hittingWall = true;
          } else if ( this.Exit.isInstance(o2) ) {
            this.gameOver();
          }
        }
      }.bind(this);
      this.collider.start();
      this.timer.i$.sub(this.tick);
      this.timer.start();
    },

    function buildMaze() {
      var m = this.MAZE_HORIZ;

      // draw horizontal lines
      for ( var row = 0 ; row < m.length ; row++ ) {
        var rowdata = m[row];
        for ( var col = 0 ; col < rowdata.length ; col++ ) {
          if ( rowdata[col] ) {
            var blockType = this[rowdata[col]];
            this.addChild(blockType.create({
              x: this.BRICK_SIZE/2 + col*this.BRICK_SIZE,
              y: this.BRICK_SIZE/2 + row*this.BRICK_SIZE,
              width: this.BRICK_SIZE,
              height: 5
            }));
          }
        }
      }

      // draw vertical lines
      m = this.MAZE_VERT;
      for ( var row = 0 ; row < m.length ; row++ ) {
        var rowdata = m[row];
        for ( var col = 0 ; col < rowdata.length ; col++ ) {
          if ( rowdata[col] ) {
            var blockType = this[rowdata[col]];
            this.addChild(blockType.create({
              x: this.BRICK_SIZE/2 + col*this.BRICK_SIZE,
              y: this.BRICK_SIZE/2 + row*this.BRICK_SIZE,
              width: 5,
              height: this.BRICK_SIZE
            }));
          }
        }
      }

    },

    function initE() {
      this.SUPER();
      this.focus();
      this.style({display:'flex'}).add(this.table).add(' ').tag(null, null, this.questionArea$);
    },

    function gameOver() {
      if ( this.isGameOver ) return;
      this.isGameOver = true;

      this.table.color = 'white';
      this.addChild(label = this.Label.create({
        text: 'You Win!',
        align: 'center',
        color: 'red',
        x: this.table.width/2,
        y: 180
      }));

      this.Animation.create({
        duration: 2000,
        f: ()=> { label.scaleX = label.scaleY = 10; label.rotation = 2 * Math.PI; },
        objs: [label]
      }).start();

      this.Speak.create({text: "You Win! You're so smart!"}).play();
    },

    function addChild(c) {
      this.table.add(c);
      if ( c.intersects ) this.collider.add(c);
    },

    function removeChild(c) {
      this.table.remove(c);
      if ( c.intersects ) this.collider.remove(c);
    }
  ],

  listeners: [
    {
      name: 'tick',
      code: function() {
        if ( this.hittingWall ) {
          this.robot.x = this.lastX;
          this.robot.y = this.lastY;
          this.hittingWall = false;
        } else {
          this.lastX = this.robot.x;
          this.lastY = this.robot.y;
        }

        if ( this.gamepad.button0 ) this.up();
        if ( this.gamepad.button1 ) this.right();
        if ( this.gamepad.button2 ) this.down();
        if ( this.gamepad.button3 ) this.left();
      }
    }
  ],

  actions: [
    {
      name: 'up',
      keyboardShortcuts: [ 38 /* up arrow */, 'w' ],
      code: function() { this.robot.y -= 3; }
    },
    {
      name: 'down',
      keyboardShortcuts: [ 40 /* down arrow */, 's' ],
      code: function() { this.robot.y += 3; }
    },
    {
      name: 'left',
      keyboardShortcuts: [ 37 /* left arrow */, 'a' ],
      code: function() { this.robot.x -= 3; }
    },
    {
      name: 'right',
      keyboardShortcuts: [ 39 /* right arrow */, 'd' ],
      code: function() { this.robot.x += 3; }
    },
    {
      name: 'fire',
      keyboardShortcuts: [ ' ', 'x' ],
      code: function() {
        this.Laser.create({x: this.robot.x, y: this.robot.y, vx: 1, vy: 0});
        this.Laser.create({x: this.robot.x, y: this.robot.y, vx: 0, vy: 1});
        this.Laser.create({x: this.robot.x, y: this.robot.y, vx: -1, vy: 0});
        this.Laser.create({x: this.robot.x, y: this.robot.y, vx: 0, vy: -1});
      }
    }
  ]
});
<commit_msg>Update Maze game.<commit_after>/**
 * @license
 * Copyright 2020 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Question1',
  properties: [
    {
      name: 'question',
      label: 'Who was the best Star Wars robot?',
      view: {
        class: 'foam.u2.view.RadioView',
        placeholder: 'Please select',
        choices: [
          'C3-PO',
          'R2-D2',
          'BB-8',
          'K-2SO'
        ]
      }
    },
    {
      name: 'answer',
      hidden: true,
      value: 'R2-D2'
    }
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Question2',
  properties: [
    {
      name: 'question',
      label: 'Which of the following do robots make',
      view: {
        class: 'foam.u2.view.RadioView',
        placeholder: 'Please select',
        choices: [
          'Cars',
          'Washing Machines',
          'Computers',
          'Robots',
          'All of the Above'

        ]
      }
    },
    {
      name: 'answer',
      hidden: true,
      value: 'All of the Above'
    }
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Door',
  extends: 'foam.graphics.Box',
  properties: [
    [ 'color', 'red' ],
    [ 'isClosed', true ]
  ],
  methods: [
    function open() {
      this.isClosed = false;
      this.rotation = Math.PI / 4;
//      this.width = this.height = 0;
    }
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Wall',
  extends: 'foam.graphics.Box',
  properties: [
    [ 'color', 'gray' ]
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Exit',
  extends: 'foam.graphics.Box',
  properties: [
    [ 'color', 'blue' ]
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Laser',
  extends: 'foam.graphics.Circle',

  requires: [ 'foam.animation.Animation' ],
  imports: [ 'game'],

  properties: [
    [ 'color', 'yellow' ],
    [ 'radius', 8 ],
    'vx',
    'vy'
  ],

  methods: [
    function init() {
      this.SUPER();

      this.game.addChild(this);
      this.Animation.create({
        duration: 5000,
        f: () => {
          this.x += 2000 * this.vx;
          this.y += 2000 * this.vy;
        },
        onEnd: () => this.game.removeChild(this),
        objs: [ this ]
      }).start();
    }
  ]
});

foam.CLASS({
  package: 'com.foamdev.demos.maze',
  name: 'Game',
  extends: 'foam.u2.Element',

  requires: [
    'com.foamdev.demos.maze.Door',
    'com.foamdev.demos.maze.Exit',
    'com.foamdev.demos.maze.Laser',
    'com.foamdev.demos.maze.Question1',
    'com.foamdev.demos.maze.Question2',
    'com.foamdev.demos.maze.Wall',
    'com.google.foam.demos.robot.Robot',
    'foam.animation.Animation',
    'foam.audio.Speak',
    'foam.graphics.Box as Rectangle',
    'foam.graphics.CView',
    'foam.graphics.Label',
    'foam.input.Gamepad',
    'foam.physics.Collider',
    'foam.util.Timer'
  ],

  exports: [
    'timer',
    'as game'
  ],

  constants: {
    BRICK_SIZE: 40,
    MAZE_HORIZ: [
      ['Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall'],
      ['Wall', null, null, 'Wall', null, 'Wall', null, null, 'Wall'],
      [null, 'Door', null, null, null, null, null, 'Wall', null, 'Wall', 'Wall'],
      [null, 'Wall', 'Wall', null, 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall', null],
      [null, null, 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall', null, 'Wall', 'Wall'],
      [null, null, 'Door', 'Wall', null, 'Door', null, null, null, 'Wall'],
      ['Wall', 'Door', null, 'Wall', null, null, null, null, 'Wall', null, 'Wall'],
      ['Wall', 'Wall', null, 'Wall', 'Wall', null, null, 'Door', null, 'Wall'],
      ['Wall', null, 'Wall', 'Wall', null, 'Wall', null, null, 'Wall', null, 'Wall'],
      [null, null, 'Wall', null, 'Wall', null, 'Wall', null, null, 'Wall', 'Wall'],
      [null, 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', null, 'Wall', null, 'Wall'],
      ['Door', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall', 'Wall']
    ],
    MAZE_VERT: [
      ['Wall', null, 'Wall', null, null, 'Wall', 'Wall', 'Wall', null, null, 'Wall', 'Exit'],
      ['Wall', 'Wall', 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall', null, 'Wall', null, 'Wall'],
      ['Wall', null, null, 'Wall', null, 'Wall', null, null, 'Wall', null, null, 'Wall'],
      ['Wall', 'Wall', null, null, null, null, null, 'Wall', null, null, null, 'Wall'],
      ['Wall', 'Wall', 'Wall', null, null, 'Wall', null, null, 'Wall', 'Wall', null, 'Wall'],
      ['Wall', 'Wall', null, null, 'Wall', null, 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall'],
      ['Wall', null, null, 'Wall', null, 'Door', 'Wall', 'Wall', null, 'Wall', null, 'Wall'],
      ['Wall', null, 'Wall', null, null, null, 'Wall', 'Wall', 'Wall', null, 'Wall', 'Wall'],
      ['Wall', 'Wall', null, null, 'Wall', 'Wall', null, 'Wall', 'Wall', null, null, 'Wall'],
      ['Wall', 'Wall', null, 'Wall', null, null, null, 'Wall', null, 'Wall', null, 'Wall'],
      ['Wall', null, null, null, null, null, null, null, 'Wall', null, false, 'Wall']
    ]
   },

  properties: [
    [ 'isGameOver', false ],
    [ 'width', 1600 ],
    [ 'height', 800 ],
    {
      name: 'gamepad',
      factory: function() { return this.Gamepad.create(); }
    },
    {
      name: 'timer',
      factory: function() { return this.Timer.create(); }
    },
    {
      name: 'table',
      factory: function() {
        return this.Rectangle.create({
          color: 'black',
          scaleX: 1.8,
          scaleY: 1.8,
          width: 500, // window.innerWidth,
          height: 500 // window.innerHeight
        });
      }
    },
    {
      name: 'robot',
      factory: function() {
        return this.Robot.create({x:37.5, y:435, scaleX: 0.5, scaleY: 0.5, width: 3, height: 3});
      }
    },
    {
      name: 'collider',
      factory: function() { return this.Collider.create(); }
    },
    'lastX', 'lastY', 'hittingWall',
    'questionArea'
  ],

  methods: [
    function init() {
      this.SUPER();

      this.buildMaze();
      this.addChild(this.robot);

      this.gamepad.pressed.sub('button4', () => this.fire());
      this.gamepad.pressed.sub('button5', () => this.fire());

      // Setup Physics
      this.collider.collide = function(o1, o2) {
        if ( o2 == this.robot ) {
          o2 = o1;
          o1 = this.robot;
        }
        if ( o1 == this.robot ) {
          if ( this.Door.isInstance(o2) ) {
            if ( ! o2.isClosed ) return;
            console.log('*************************** Door');
            o2.open();
            this.hittingWall = true;
            this.questionArea.removeAllChildren();
            this.questionArea.add(this.Question1.create());
          } else if ( this.Wall.isInstance(o2) ) {
            console.log('*************************** Wall');
            this.hittingWall = true;
          } else if ( this.Exit.isInstance(o2) ) {
            this.gameOver();
          }
        }
      }.bind(this);
      this.collider.start();
      this.timer.i$.sub(this.tick);
      this.timer.start();
    },

    function buildMaze() {
      var m = this.MAZE_HORIZ;

      // draw horizontal lines
      for ( var row = 0 ; row < m.length ; row++ ) {
        var rowdata = m[row];
        for ( var col = 0 ; col < rowdata.length ; col++ ) {
          if ( rowdata[col] ) {
            var blockType = this[rowdata[col]];
            this.addChild(blockType.create({
              x: this.BRICK_SIZE/2 + col*this.BRICK_SIZE,
              y: this.BRICK_SIZE/2 + row*this.BRICK_SIZE,
              width: this.BRICK_SIZE,
              height: 5
            }));
          }
        }
      }

      // draw vertical lines
      m = this.MAZE_VERT;
      for ( var row = 0 ; row < m.length ; row++ ) {
        var rowdata = m[row];
        for ( var col = 0 ; col < rowdata.length ; col++ ) {
          if ( rowdata[col] ) {
            var blockType = this[rowdata[col]];
            this.addChild(blockType.create({
              x: this.BRICK_SIZE/2 + col*this.BRICK_SIZE,
              y: this.BRICK_SIZE/2 + row*this.BRICK_SIZE,
              width: 5,
              height: this.BRICK_SIZE
            }));
          }
        }
      }

    },

    function initE() {
      this.SUPER();
      this.focus();
      this.style({display:'flex'}).add(this.table).add(' ').tag(null, null, this.questionArea$);
    },

    function gameOver() {
      if ( this.isGameOver ) return;
      this.isGameOver = true;

      this.table.color = 'white';

      var label = this.Label.create({
        text: 'You Win!',
        align: 'center',
        color: 'red',
        x: this.table.width/2,
        y: 180
      });
      this.addChild(label);

      this.Animation.create({
        duration: 2000,
        f: ()=> { label.scaleX = label.scaleY = 10; label.rotation = 2 * Math.PI; },
        objs: [label]
      }).start();

      this.Speak.create({text: "You Win! You're so smart! You're a JavaScript master!"}).play();
    },

    function addChild(c) {
      this.table.add(c);
      if ( c.intersects ) this.collider.add(c);
    },

    function removeChild(c) {
      this.table.remove(c);
      if ( c.intersects ) this.collider.remove(c);
    }
  ],

  listeners: [
    {
      name: 'tick',
      code: function() {
        if ( this.hittingWall ) {
          this.robot.x = this.lastX;
          this.robot.y = this.lastY;
          this.hittingWall = false;
        } else {
          this.lastX = this.robot.x;
          this.lastY = this.robot.y;
        }

        if ( this.gamepad.button0 ) this.up();
        if ( this.gamepad.button1 ) this.right();
        if ( this.gamepad.button2 ) this.down();
        if ( this.gamepad.button3 ) this.left();
      }
    }
  ],

  actions: [
    {
      name: 'up',
      keyboardShortcuts: [ 38 /* up arrow */, 'w' ],
      code: function() { this.robot.y -= 3; }
    },
    {
      name: 'down',
      keyboardShortcuts: [ 40 /* down arrow */, 's' ],
      code: function() { this.robot.y += 3; }
    },
    {
      name: 'left',
      keyboardShortcuts: [ 37 /* left arrow */, 'a' ],
      code: function() { this.robot.x -= 3; }
    },
    {
      name: 'right',
      keyboardShortcuts: [ 39 /* right arrow */, 'd' ],
      code: function() { this.robot.x += 3; }
    },
    {
      name: 'fire',
      keyboardShortcuts: [ ' ', 'x' ],
      code: function() {
        this.Laser.create({x: this.robot.x, y: this.robot.y, vx: 1, vy: 0});
        this.Laser.create({x: this.robot.x, y: this.robot.y, vx: 0, vy: 1});
        this.Laser.create({x: this.robot.x, y: this.robot.y, vx: -1, vy: 0});
        this.Laser.create({x: this.robot.x, y: this.robot.y, vx: 0, vy: -1});
      }
    }
  ]
});
<|endoftext|>


<commit_before>/* jqBootstrapValidation
 * A plugin for automating validation on Twitter Bootstrap formatted forms.
 *
 * v1.3.6
 *
 * License: MIT <http://opensource.org/licenses/mit-license.php> - see LICENSE file
 *
 * http://ReactiveRaven.github.com/jqBootstrapValidation/
 */

(function( $ ){

	var createdElements = [];

	var defaults = {
		options: {
			prependExistingHelpBlock: false,
			sniffHtml: true, // sniff for 'required', 'maxlength', etc
			preventSubmit: true, // stop the form submit event from firing if validation fails
			submitError: false, // function called if there is an error when trying to submit
			submitSuccess: false, // function called just before a successful submit event is sent to the server
            semanticallyStrict: false, // set to true to tidy up generated HTML output
			autoAdd: {
				helpBlocks: true
			},
            filter: function () {
                // return $(this).is(":visible"); // only validate elements you can see
                return true; // validate everything
            }
		},
    methods: {
      init : function( options ) {

        var settings = $.extend(true, {}, defaults);

        settings.options = $.extend(true, settings.options, options);

        var $siblingElements = this;

        var uniqueForms = $.unique(
          $siblingElements.map( function () {
            return $(this).parents("form")[0];
          }).toArray()
        );

        $(uniqueForms).bind("submit", function (e) {
          var $form = $(this);
          var warningsFound = 0;
          var $inputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
          $inputs.trigger("submit.validation").trigger("validationLostFocus.validation");

          $inputs.each(function (i, el) {
            var $this = $(el),
              $controlGroup = $this.parents(".control-group").first();
            if (
              $controlGroup.hasClass("warning")
            ) {
              $controlGroup.removeClass("warning").addClass("error");
              warningsFound++;
            }
          });

          $inputs.trigger("validationLostFocus.validation");

          if (warningsFound) {
            if (settings.options.preventSubmit) {
              e.preventDefault();
            }
            $form.addClass("error");
            if ($.isFunction(settings.options.submitError)) {
              settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true));
            }
          } else {
            $form.removeClass("error");
            if ($.isFunction(settings.options.submitSuccess)) {
              settings.options.submitSuccess($form, e);
            }
          }
        });

        return this.each(function(){

          // Get references to everything we're interested in
          var $this = $(this),
            $controlGroup = $this.parents(".control-group").first(),
            $helpBlock = $controlGroup.find(".help-block").first(),
            $form = $this.parents("form").first(),
            validatorNames = [];

          // create message container if not exists
          if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) {
              $helpBlock = $('<div class="help-block" />');
              $controlGroup.find('.controls').append($helpBlock);
							createdElements.push($helpBlock[0]);
          }

          // =============================================================
          //                                     SNIFF HTML FOR VALIDATORS
          // =============================================================

          // *snort sniff snuffle*

          if (settings.options.sniffHtml) {
            var message = "";
            // ---------------------------------------------------------
            //                                                   PATTERN
            // ---------------------------------------------------------
            if ($this.attr("pattern") !== undefined) {
              message = "Not in the expected format<!-- data-validation-pattern-message to override -->";
              if ($this.data("validationPatternMessage")) {
                message = $this.data("validationPatternMessage");
              }
              $this.data("validationPatternMessage", message);
              $this.data("validationPatternRegex", $this.attr("pattern"));
            }
            // ---------------------------------------------------------
            //                                                       MAX
            // ---------------------------------------------------------
            if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) {
              var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax"));
              message = "Too high: Maximum of '" + max + "'<!-- data-validation-max-message to override -->";
              if ($this.data("validationMaxMessage")) {
                message = $this.data("validationMaxMessage");
              }
              $this.data("validationMaxMessage", message);
              $this.data("validationMaxMax", max);
            }
            // ---------------------------------------------------------
            //                                                       MIN
            // ---------------------------------------------------------
            if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) {
              var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin"));
              message = "Too low: Minimum of '" + min + "'<!-- data-validation-min-message to override -->";
              if ($this.data("validationMinMessage")) {
                message = $this.data("validationMinMessage");
              }
              $this.data("validationMinMessage", message);
              $this.data("validationMinMin", min);
            }
            // ---------------------------------------------------------
            //                                                 MAXLENGTH
            // ---------------------------------------------------------
            if ($this.attr("maxlength") !== undefined) {
              message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters<!-- data-validation-maxlength-message to override -->";
              if ($this.data("validationMaxlengthMessage")) {
                message = $this.data("validationMaxlengthMessage");
              }
              $this.data("validationMaxlengthMessage", message);
              $this.data("validationMaxlengthMaxlength", $this.attr("maxlength"));
            }
            // ---------------------------------------------------------
            //                                                 MINLENGTH
            // ---------------------------------------------------------
            if ($this.attr("minlength") !== undefined) {
              message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters<!-- data-validation-minlength-message to override -->";
              if ($this.data("validationMinlengthMessage")) {
                message = $this.data("validationMinlengthMessage");
              }
              $this.data("validationMinlengthMessage", message);
              $this.data("validationMinlengthMinlength", $this.attr("minlength"));
            }
            // ---------------------------------------------------------
            //                                                  REQUIRED
            // ---------------------------------------------------------
            if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) {
              message = settings.builtInValidators.required.message;
              if ($this.data("validationRequiredMessage")) {
                message = $this.data("validationRequiredMessage");
              }
              $this.data("validationRequiredMessage", message);
            }
            // ---------------------------------------------------------
            //                                                    NUMBER
            // ---------------------------------------------------------
            if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") {
              message = settings.builtInValidators.number.message;
              if ($this.data("validationNumberMessage")) {
                message = $this.data("validationNumberMessage");
              }
              $this.data("validationNumberMessage", message);
            }
            // ---------------------------------------------------------
            //                                                     EMAIL
            // ---------------------------------------------------------
            if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") {
              message = "Not a valid email address<!-- data-validator-validemail-message to override -->";
              if ($this.data("validationValidemailMessage")) {
                message = $this.data("validationValidemailMessage");
              } else if ($this.data("validationEmailMessage")) {
                message = $this.data("validationEmailMessage");
              }
              $this.data("validationValidemailMessage", message);
            }
            // ---------------------------------------------------------
            //                                                MINCHECKED
            // ---------------------------------------------------------
            if ($this.attr("minchecked") !== undefined) {
              message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required<!-- data-validation-minchecked-message to override -->";
              if ($this.data("validationMincheckedMessage")) {
                message = $this.data("validationMincheckedMessage");
              }
              $this.data("validationMincheckedMessage", message);
              $this.data("validationMincheckedMinchecked", $this.attr("minchecked"));
            }
            // ---------------------------------------------------------
            //                                                MAXCHECKED
            // ---------------------------------------------------------
            if ($this.attr("maxchecked") !== undefined) {
              message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required<!-- data-validation-maxchecked-message to override -->";
              if ($this.data("validationMaxcheckedMessage")) {
                message = $this.data("validationMaxcheckedMessage");
              }
              $this.data("validationMaxcheckedMessage", message);
              $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked"));
            }
          }

          // =============================================================
          //                                       COLLECT VALIDATOR NAMES
          // =============================================================

          // Get named validators
          if ($this.data("validation") !== undefined) {
            validatorNames = $this.data("validation").split(",");
          }

          // Get extra ones defined on the element's data attributes
          $.each($this.data(), function (i, el) {
            var parts = i.replace(/([A-Z])/g, ",$1").split(",");
            if (parts[0] === "validation" && parts[1]) {
              validatorNames.push(parts[1]);
            }
          });

          // =============================================================
          //                                     NORMALISE VALIDATOR NAMES
          // =============================================================

          var validatorNamesToInspect = validatorNames;
          var newValidatorNamesToInspect = [];

          do // repeatedly expand 'shortcut' validators into their real validators
          {
            // Uppercase only the first letter of each name
            $.each(validatorNames, function (i, el) {
              validatorNames[i] = formatValidatorName(el);
            });

            // Remove duplicate validator names
            validatorNames = $.unique(validatorNames);

            // Pull out the new validator names from each shortcut
            newValidatorNamesToInspect = [];
            $.each(validatorNamesToInspect, function(i, el) {
              if ($this.data("validation" + el + "Shortcut") !== undefined) {
                // Are these custom validators?
                // Pull them out!
                $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) {
                  newValidatorNamesToInspect.push(el2);
                });
              } else if (settings.builtInValidators[el.toLowerCase()]) {
                // Is this a recognised built-in?
                // Pull it out!
                var validator = settings.builtInValidators[el.toLowerCase()];
                if (validator.type.toLowerCase() === "shortcut") {
                  $.each(validator.shortcut.split(","), function (i, el) {
                    el = formatValidatorName(el);
                    newValidatorNamesToInspect.push(el);
                    validatorNames.push(el);
                  });
                }
              }
            });

            validatorNamesToInspect = newValidatorNamesToInspect;

          } while (validatorNamesToInspect.length > 0)

          // =============================================================
          //                                       SET UP VALIDATOR ARRAYS
          // =============================================================

          var validators = {};

          $.each(validatorNames, function (i, el) {
            // Set up the 'override' message
            var message = $this.data("validation" + el + "Message");
            var hasOverrideMessage = (message !== undefined);
            var foundValidator = false;
            message =
              (
                message
                  ? message
                  : "'" + el + "' validation failed <!-- Add attribute 'data-validation-" + el.toLowerCase() + "-message' to input to change this message -->"
              )
            ;

            $.each(
              settings.validatorTypes,
              function (validatorType, validatorTemplate) {
                if (validators[validatorType] === undefined) {
                  validators[validatorType] = [];
                }
                if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) {
                  validators[validatorType].push(
                    $.extend(
                      true,
                      {
                        name: formatValidatorName(validatorTemplate.name),
                        message: message
                      },
                      validatorTemplate.init($this, el)
                    )
                  );
                  foundValidator = true;
                }
              }
            );

            if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) {

              var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]);
              if (hasOverrideMessage) {
                validator.message = message;
              }
              var validatorType = validator.type.toLowerCase();

              if (validatorType === "shortcut") {
                foundValidator = true;
              } else {
                $.each(
                  settings.validatorTypes,
                  function (validatorTemplateType, validatorTemplate) {
                    if (validators[validatorTemplateType] === undefined) {
                      validators[validatorTemplateType] = [];
                    }
                    if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) {
                      $this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]);
                      validators[validatorType].push(
                        $.extend(
                          validator,
                          validatorTemplate.init($this, el)
                        )
                      );
                      foundValidator = true;
                    }
                  }
                );
              }
            }

            if (! foundValidator) {
              $.error("Cannot find validation info for '" + el + "'");
            }
          });

          // =============================================================
          //                                         STORE FALLBACK VALUES
          // =============================================================

          $helpBlock.data(
            "original-contents",
            (
              $helpBlock.data("original-contents")
                ? $helpBlock.data("original-contents")
                : $helpBlock.html()
            )
          );

          $helpBlock.data(
            "original-role",
            (
              $helpBlock.data("original-role")
                ? $helpBlock.data("original-role")
                : $helpBlock.attr("role")
            )
          );

          $controlGroup.data(
            "original-classes",
            (
              $controlGroup.data("original-clases")
                ? $controlGroup.data("original-classes")
                : $controlGroup.attr("class")
            )
          );

          $this.data(
            "original-aria-invalid",
            (
              $this.data("original-aria-invalid")
                ? $this.data("original-aria-invalid")
                : $this.attr("aria-invalid")
            )
          );

          // =============================================================
          //                                                    VALIDATION
          // =============================================================

          $this.bind(
            "validation.validation",
            function (event, params) {

              var value = getValue($this);

              // Get a list of the errors to apply
              var errorsFound = [];

              $.each(validators, function (validatorType, validatorTypeArray) {
                if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) {
                  $.each(validatorTypeArray, function (i, validator) {
                    if (settings.validatorTypes[validatorType].validate($this, value, validator)) {
                      errorsFound.push(validator.message);
                    }
                  });
                }
              });

              return errorsFound;
            }
          );

          $this.bind(
            "getValidators.validation",
            function () {
              return validators;
            }
          );

          // =============================================================
          //                                             WATCH FOR CHANGES
          // =============================================================
          $this.bind(
            "submit.validation",
            function () {
              return $this.triggerHandler("change.validation", {submitting: true});
            }
          );
          $this.bind(
            [
              "keyup",
              "focus",
              "blur",
              "click",
              "keydown",
              "keypress",
              "change"
            ].join(".validation ") + ".validation",
            function (e, params) {

              var value = getValue($this);

              var errorsFound = [];

              $controlGroup.find("input,textarea,select").each(function (i, el) {
                var oldCount = errorsFound.length;
                $.each($(el).triggerHandler("validation.validation", params), function (j, message) {
                  errorsFound.push(message);
                });
                if (errorsFound.length > oldCount) {
                  $(el).attr("aria-invalid", "true");
                } else {
                  var original = $this.data("original-aria-invalid");
                  $(el).attr("aria-invalid", (original !== undefined ? original : false));
                }
              });

              $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation");

              errorsFound = $.unique(errorsFound.sort());

              // Were there any errors?
              if (errorsFound.length) {
                // Better flag it up as a warning.
                $controlGroup.removeClass("success error").addClass("warning");

                // How many errors did we find?
                if (settings.options.semanticallyStrict && errorsFound.length === 1) {
                  // Only one? Being strict? Just output it.
                  $helpBlock.html(errorsFound[0] +
                    ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
                } else {
                  // Multiple? Being sloppy? Glue them together into an UL.
                  $helpBlock.html("<ul role=\"alert\"><li>" + errorsFound.join("</li><li>") + "</li></ul>" +
                    ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
                }
              } else {
                $controlGroup.removeClass("warning error success");
                if (value.length > 0) {
                  $controlGroup.addClass("success");
                }
                $helpBlock.html($helpBlock.data("original-contents"));
              }

              if (e.type === "blur") {
                $controlGroup.removeClass("success");
              }
            }
          );
          $this.bind("validationLostFocus.validation", function () {
            $controlGroup.removeClass("success");
          });
        });
      },
      destroy : function( ) {

        return this.each(
          function() {

            var
              $this = $(this),
              $controlGroup = $this.parents(".control-group").first(),
              $helpBlock = $controlGroup.find(".help-block").first();

            // remove our events
            $this.unbind('.validation'); // events are namespaced.
            // reset help text
            $helpBlock.html($helpBlock.data("original-contents"));
            // reset classes
            $controlGroup.attr("class", $controlGroup.data("original-classes"));
            // reset aria
            $this.attr("aria-invalid", $this.data("original-aria-invalid"));
            // reset role
            $helpBlock.attr("role", $this.data("original-role"));
						// remove all elements we created
						if (createdElements.indexOf($helpBlock[0]) > -1) {
							$helpBlock.remove();
						}

          }
        );

      },
      collectErrors : function(includeEmpty) {

        var errorMessages = {};
        this.each(function (i, el) {
          var $el = $(el);
          var name = $el.attr("name");
          var errors = $el.triggerHandler("validation.validation", {includeEmpty: true});
          errorMessages[name] = $.extend(true, errors, errorMessages[name]);
        });

        $.each(errorMessages, function (i, el) {
          if (el.length === 0) {
            delete errorMessages[i];
          }
        });

        return errorMessages;

      },
      hasErrors: function() {

        var errorMessages = [];

        this.each(function (i, el) {
          errorMessages = errorMessages.concat(
            $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : []
          );
        });

        return (errorMessages.length > 0);
      },
      override : function (newDefaults) {
        defaults = $.extend(true, defaults, newDefaults);
      }
    },
		validatorTypes: {
      callback: {
        name: "callback",
        init: function ($this, name) {
          return {
            validatorName: name,
            callback: $this.data("validation" + name + "Callback"),
            lastValue: $this.val(),
            lastValid: true,
            lastFinished: true
          };
        },
        validate: function ($this, value, validator) {
          if (validator.lastValue === value && validator.lastFinished) {
            return !validator.lastValid;
          }

          if (validator.lastFinished === true)
          {
            validator.lastValue = value;
            validator.lastValid = true;
            validator.lastFinished = false;

            var rrjqbvValidator = validator;
            var rrjqbvThis = $this;
            executeFunctionByName(
              validator.callback,
              window,
              $this,
              value,
              function (data) {
                if (rrjqbvValidator.lastValue === data.value) {
                  rrjqbvValidator.lastValid = data.valid;
                  if (data.message) {
                    rrjqbvValidator.message = data.message;
                  }
                  rrjqbvValidator.lastFinished = true;
                  rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message);
                  // Timeout is set to avoid problems with the events being considered 'already fired'
                  setTimeout(function () {
                    rrjqbvThis.trigger("change.validation");
                  }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
                }
              }
            );
          }

          return false;

        }
      },
      ajax: {
        name: "ajax",
        init: function ($this, name) {
          return {
            validatorName: name,
            url: $this.data("validation" + name + "Ajax"),
            lastValue: $this.val(),
            lastValid: true,
            lastFinished: true
          };
        },
        validate: function ($this, value, validator) {
          if (""+validator.lastValue === ""+value && validator.lastFinished === true) {
            return validator.lastValid === false;
          }

          if (validator.lastFinished === true)
          {
            validator.lastValue = value;
            validator.lastValid = true;
            validator.lastFinished = false;
            $.ajax({
              url: validator.url,
              data: "value=" + value + "&field=" + $this.attr("name"),
              dataType: "json",
              success: function (data) {
                if (""+validator.lastValue === ""+data.value) {
                  validator.lastValid = !!(data.valid);
                  if (data.message) {
                    validator.message = data.message;
                  }
                  validator.lastFinished = true;
                  $this.data("validation" + validator.validatorName + "Message", validator.message);
                  // Timeout is set to avoid problems with the events being considered 'already fired'
                  setTimeout(function () {
                    $this.trigger("change.validation");
                  }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
                }
              },
              failure: function () {
                validator.lastValid = true;
                validator.message = "ajax call failed";
                validator.lastFinished = true;
                $this.data("validation" + validator.validatorName + "Message", validator.message);
                // Timeout is set to avoid problems with the events being considered 'already fired'
                setTimeout(function () {
                  $this.trigger("change.validation");
                }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
              }
            });
          }

          return false;

        }
      },
			regex: {
				name: "regex",
				init: function ($this, name) {
					return {regex: regexFromString($this.data("validation" + name + "Regex"))};
				},
				validate: function ($this, value, validator) {
					return (!validator.regex.test(value) && ! validator.negative)
						|| (validator.regex.test(value) && validator.negative);
				}
			},
			required: {
				name: "required",
				init: function ($this, name) {
					return {};
				},
				validate: function ($this, value, validator) {
					return !!(value.length === 0  && ! validator.negative)
						|| !!(value.length > 0 && validator.negative);
				},
        blockSubmit: true
			},
			match: {
				name: "match",
				init: function ($this, name) {
					var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first();
					element.bind("validation.validation", function () {
						$this.trigger("change.validation", {submitting: true});
					});
					return {"element": element};
				},
				validate: function ($this, value, validator) {
					return (value !== validator.element.val() && ! validator.negative)
						|| (value === validator.element.val() && validator.negative);
				},
        blockSubmit: true
			},
			max: {
				name: "max",
				init: function ($this, name) {
					return {max: $this.data("validation" + name + "Max")};
				},
				validate: function ($this, value, validator) {
					return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative)
						|| (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative);
				}
			},
			min: {
				name: "min",
				init: function ($this, name) {
					return {min: $this.data("validation" + name + "Min")};
				},
				validate: function ($this, value, validator) {
					return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative)
						|| (parseFloat(value) >= parseFloat(validator.min) && validator.negative);
				}
			},
			maxlength: {
				name: "maxlength",
				init: function ($this, name) {
					return {maxlength: $this.data("validation" + name + "Maxlength")};
				},
				validate: function ($this, value, validator) {
					return ((value.length > validator.maxlength) && ! validator.negative)
						|| ((value.length <= validator.maxlength) && validator.negative);
				}
			},
			minlength: {
				name: "minlength",
				init: function ($this, name) {
					return {minlength: $this.data("validation" + name + "Minlength")};
				},
				validate: function ($this, value, validator) {
					return ((value.length < validator.minlength) && ! validator.negative)
						|| ((value.length >= validator.minlength) && validator.negative);
				}
			},
			maxchecked: {
				name: "maxchecked",
				init: function ($this, name) {
					var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
					elements.bind("click.validation", function () {
						$this.trigger("change.validation", {includeEmpty: true});
					});
					return {maxchecked: $this.data("validation" + name + "Maxchecked"), elements: elements};
				},
				validate: function ($this, value, validator) {
					return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative)
						|| (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative);
				},
        blockSubmit: true
			},
			minchecked: {
				name: "minchecked",
				init: function ($this, name) {
					var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
					elements.bind("click.validation", function () {
						$this.trigger("change.validation", {includeEmpty: true});
					});
					return {minchecked: $this.data("validation" + name + "Minchecked"), elements: elements};
				},
				validate: function ($this, value, validator) {
					return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative)
						|| (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative);
				},
        blockSubmit: true
			}
		},
		builtInValidators: {
			email: {
				name: "Email",
				type: "shortcut",
				shortcut: "validemail"
			},
			validemail: {
				name: "Validemail",
				type: "regex",
				regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}",
				message: "Not a valid email address<!-- data-validator-validemail-message to override -->"
			},
			passwordagain: {
				name: "Passwordagain",
				type: "match",
				match: "password",
				message: "Does not match the given password<!-- data-validator-paswordagain-message to override -->"
			},
			positive: {
				name: "Positive",
				type: "shortcut",
				shortcut: "number,positivenumber"
			},
			negative: {
				name: "Negative",
				type: "shortcut",
				shortcut: "number,negativenumber"
			},
			number: {
				name: "Number",
				type: "regex",
				regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?",
				message: "Must be a number<!-- data-validator-number-message to override -->"
			},
			integer: {
				name: "Integer",
				type: "regex",
				regex: "[+-]?\\\d+",
				message: "No decimal places allowed<!-- data-validator-integer-message to override -->"
			},
			positivenumber: {
				name: "Positivenumber",
				type: "min",
				min: 0,
				message: "Must be a positive number<!-- data-validator-positivenumber-message to override -->"
			},
			negativenumber: {
				name: "Negativenumber",
				type: "max",
				max: 0,
				message: "Must be a negative number<!-- data-validator-negativenumber-message to override -->"
			},
			required: {
				name: "Required",
				type: "required",
				message: "This is required<!-- data-validator-required-message to override -->"
			},
			checkone: {
				name: "Checkone",
				type: "minchecked",
				minchecked: 1,
				message: "Check at least one option<!-- data-validation-checkone-message to override -->"
			}
		}
	};

	var formatValidatorName = function (name) {
		return name
			.toLowerCase()
			.replace(
				/(^|\s)([a-z])/g ,
				function(m,p1,p2) {
					return p1+p2.toUpperCase();
				}
			)
		;
	};

	var getValue = function ($this) {
		// Extract the value we're talking about
		var value = $this.val();
		var type = $this.attr("type");
		if (type === "checkbox") {
			value = ($this.is(":checked") ? value : "");
		}
		if (type === "radio") {
			value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : "");
		}
		return value;
	};

  function regexFromString(inputstring) {
		return new RegExp("^" + inputstring + "$");
	}

  /**
   * Thanks to Jason Bunting via StackOverflow.com
   *
   * http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910
   * Short link: http://tinyurl.com/executeFunctionByName
  **/
  function executeFunctionByName(functionName, context /*, args*/) {
    var args = Array.prototype.slice.call(arguments).splice(2);
    var namespaces = functionName.split(".");
    var func = namespaces.pop();
    for(var i = 0; i < namespaces.length; i++) {
      context = context[namespaces[i]];
    }
    return context[func].apply(this, args);
  }

	$.fn.jqBootstrapValidation = function( method ) {

		if ( defaults.methods[method] ) {
			return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
		} else if ( typeof method === 'object' || ! method ) {
			return defaults.methods.init.apply( this, arguments );
		} else {
		$.error( 'Method ' +  method + ' does not exist on jQuery.jqBootstrapValidation' );
			return null;
		}

	};

  $.jqBootstrapValidation = function (options) {
    $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments);
  };

})( jQuery );
<commit_msg>Delete jqBootstrapValidation.js<commit_after><|endoftext|>


<commit_before>const { Command } = require('discord-akairo');
const request = require('snekfetch');

const Logger = require('../../util/Logger');

class DocsCommand extends Command {
    constructor() {
        super('docs', {
            aliases: ['docs'],
            category: 'info',
            args: [
                {
                    id: 'query'
                },
                {
                    id: 'version',
                    type: ['master', 'stable'],
                    default: 'stable'
                }
            ]
        });

        this.docs = {};
    }

    async fetchDocs(version) {
        if (this.docs[version]) return this.docs[version];

        const link = `https://raw.githubusercontent.com/hydrabolt/discord.js/docs/${version}.json`;
        const { text } = await request.get(link);
        const json = JSON.parse(text);

        this.docs[version] = json;
        return json;
    }

    clean(text) {
        return text.replace(/\n/g, ' ').replace(/<\/?(?:info|warn)>/g, '').replace(/\{@link (.+?)\}/g, '`$1`');
    }

    joinType(type) {
        return type.map(t => t.map(a => Array.isArray(a) ? a.join('') : a).join('')).join(' | ');
    }

    makeLink(mainItem, item, version) {
        return `https://discord.js.org/#/docs/main/${version}/class/${mainItem.name}?scrollTo=${item.scope === 'static' ? 's-' : ''}${item.name}`;
    }

    formatMain(item, version) {
        const embed = this.client.util.embed();

        let description = `__**[${item.name}`;
        if (item.extends) description += ` (extends ${item.extends[0]})`;
        description += `](https://discord.js.org/#/docs/main/${version}/class/${item.name})**__\n`;

        if (item.description) description += `\n${this.clean(item.description)}`;
        embed.setDescription(description);

        const join = it => `\`${it.map(i => i.name).join('` `')}\``;

        const props = item.props ? join(item.props) : null;
        if (props) embed.addField('Properties', props);

        const methods = item.methods ? join(item.methods) : null;
        if (methods) embed.addField('Methods', methods);

        const events = item.events ? join(item.events) : null;
        if (events) embed.addField('Events', events);

        return embed;
    }

    formatProp(item, mainItem, version) {
        const embed = this.client.util.embed();

        let description = `__**[${mainItem.name}${item.scope === 'static' ? '.' : '#'}${item.name}](${this.makeLink(mainItem, item, version)})**__\n`;

        if (item.description) description += `\n${this.clean(item.description)}`;
        embed.setDescription(description);

        const type = this.joinType(item.type);
        embed.addField('Type', `\`${type}\``);

        return embed;
    }

    formatMethod(item, mainItem, version) {
        const embed = this.client.util.embed();

        let description = `__**[${mainItem.name}${item.scope === 'static' ? '.' : '#'}${item.name}()](${this.makeLink(mainItem, item, version)})**__\n`;

        if (item.description) description += `\n${this.clean(item.description)}`;
        embed.setDescription(description);

        if (item.params) {
            const params = item.params.map(param => {
                const name = param.optional ? `[${param.name}]` : param.name;
                const type = this.joinType(param.type);
                return `\`${name}: ${type}\`\n${this.clean(param.description)}`;
            });

            embed.addField('Parameters', params.join('\n\n'));
        }

        if (item.returns) {
            const desc = item.returns.description ? `${this.clean(item.returns.description)}\n` : '';
            const type = this.joinType(item.returns.types || item.returns);
            const returns = `${desc}\`=> ${type}\``;
            embed.addField('Returns', returns);
        } else {
            embed.addField('Returns', '`=> void`');
        }

        return embed;
    }

    formatEvent(item, mainItem, version) {
        const embed = this.client.util.embed();

        let description = `__**[${mainItem.name}#${item.name}](${this.makeLink(mainItem, item, version)})**__\n`;

        if (item.description) description += `\n${this.clean(item.description)}`;
        embed.setDescription(description);

        if (item.params) {
            const params = item.params.map(param => {
                const type = this.joinType(param.type);
                return `\`${param.name}: ${type}\`\n${this.clean(param.description)}`;
            });

            embed.addField('Parameters', params.join('\n\n'));
        }

        return embed;
    }

    async exec(message, { query, version }) {
        if (!query) {
            Logger.error('No query provided.');
            return message.delete();
        }

        const docs = await this.fetchDocs(version);
        const [main, member] = new DocsSearch(docs, query).find();

        if (!main) {
            Logger.error('Could not find entry in docs.');
            return message.delete();
        }

        let embed;

        if (!member) {
            embed = this.formatMain(main.item, version);
        } else {
            embed = {
                props: this.formatProp,
                methods: this.formatMethod,
                events: this.formatEvent
            }[member.type].call(this, member.item, main.item, version);
        }

        const color = this.client.getColor(message);

        embed
        .setColor(color)
        .setURL(`https://discord.js.org/#/docs/main/${version}`)
        .setAuthor(`Discord.js Docs (${version})`, 'https://cdn.discordapp.com/icons/222078108977594368/bc226f09db83b9176c64d923ff37010b.webp');

        return message.edit({ embed });
    }
}

class DocsSearch {
    constructor(docs, query) {
        this.docs = docs;

        query = query.split(/[#.]/);
        this.mainQuery = query[0].toLowerCase();
        this.memberQuery = query[1] ? query[1].toLowerCase() : null;
    }

    find() {
        const main = this.findWithin(this.docs, ['classes', 'interfaces', 'typedefs'], this.mainQuery);
        if (!main) return [];

        const res = [main];
        if (!this.memberQuery) return res;

        const member = this.findWithin(main.item, {
            classes: ['props', 'methods', 'events'],
            interfaces: ['props', 'methods', 'events'],
            typedefs: ['props']
        }[main.type], this.memberQuery);

        if (!member) return [];
        res.push(member);
        return res;
    }

    findWithin(parentItem, props, query) {
        let found = null;

        for (const type of props) {
            if (!parentItem[type]) continue;
            const item = parentItem[type].find(i => i.name.toLowerCase() === query);
            if (item) {
                found = { item, type };
                break;
            }
        }

        return found;
    }
}

DocsCommand.DocsSearch = DocsSearch;
module.exports = DocsCommand;
<commit_msg>Cleanup<commit_after>const { Command } = require('discord-akairo');
const request = require('snekfetch');

const Logger = require('../../util/Logger');

class DocsCommand extends Command {
    constructor() {
        super('docs', {
            aliases: ['docs'],
            category: 'info',
            args: [
                {
                    id: 'query'
                },
                {
                    id: 'version',
                    type: ['master', 'stable'],
                    default: 'stable'
                }
            ]
        });

        this.docs = {};
    }

    async fetchDocs(version) {
        if (this.docs[version]) return this.docs[version];

        const link = `https://raw.githubusercontent.com/hydrabolt/discord.js/docs/${version}.json`;
        const { text } = await request.get(link);
        const json = JSON.parse(text);

        this.docs[version] = json;
        return json;
    }

    search(docs, query) {
        query = query.split(/[#.]/);
        const mainQuery = query[0].toLowerCase();
        const memberQuery = query[1] ? query[1].toLowerCase() : null;

        const findWithin = (parentItem, props, name) => {
            let found = null;
            for (const type of props) {
                if (!parentItem[type]) continue;
                const item = parentItem[type].find(i => i.name.toLowerCase() === name);
                if (item) {
                    found = { item, type };
                    break;
                }
            }

            return found;
        };

        const main = findWithin(docs, ['classes', 'interfaces', 'typedefs'], mainQuery);
        if (!main) return [];

        const res = [main];
        if (!memberQuery) return res;

        const member = findWithin(main.item, {
            classes: ['props', 'methods', 'events'],
            interfaces: ['props', 'methods', 'events'],
            typedefs: ['props']
        }[main.type], memberQuery);

        if (!member) return [];
        res.push(member);
        return res;
    }

    clean(text) {
        return text
        .replace(/\n/g, ' ')
        .replace(/<\/?(?:info|warn)>/g, '')
        .replace(/\{@link (.+?)\}/g, '`$1`');
    }

    joinType(type) {
        return type.map(t => t.map(a => Array.isArray(a) ? a.join('') : a).join('')).join(' | ');
    }

    makeLink(mainItem, item, version) {
        return `https://discord.js.org/#/docs/main/${version}/class/${mainItem.name}?scrollTo=${item.scope === 'static' ? 's-' : ''}${item.name}`;
    }

    formatMain(item, version) {
        const embed = this.client.util.embed();

        let description = `__**[${item.name}`;
        if (item.extends) description += ` (extends ${item.extends[0]})`;
        description += `](https://discord.js.org/#/docs/main/${version}/class/${item.name})**__\n`;

        if (item.description) description += `\n${this.clean(item.description)}`;
        embed.setDescription(description);

        const join = it => `\`${it.map(i => i.name).join('` `')}\``;

        const props = item.props ? join(item.props) : null;
        if (props) embed.addField('Properties', props);

        const methods = item.methods ? join(item.methods) : null;
        if (methods) embed.addField('Methods', methods);

        const events = item.events ? join(item.events) : null;
        if (events) embed.addField('Events', events);

        return embed;
    }

    formatProp(item, mainItem, version) {
        const embed = this.client.util.embed();

        let description = `__**[${mainItem.name}${item.scope === 'static' ? '.' : '#'}${item.name}](${this.makeLink(mainItem, item, version)})**__\n`;

        if (item.description) description += `\n${this.clean(item.description)}`;
        embed.setDescription(description);

        const type = this.joinType(item.type);
        embed.addField('Type', `\`${type}\``);

        return embed;
    }

    formatMethod(item, mainItem, version) {
        const embed = this.client.util.embed();

        let description = `__**[${mainItem.name}${item.scope === 'static' ? '.' : '#'}${item.name}()](${this.makeLink(mainItem, item, version)})**__\n`;

        if (item.description) description += `\n${this.clean(item.description)}`;
        embed.setDescription(description);

        if (item.params) {
            const params = item.params.map(param => {
                const name = param.optional ? `[${param.name}]` : param.name;
                const type = this.joinType(param.type);
                return `\`${name}: ${type}\`\n${this.clean(param.description)}`;
            });

            embed.addField('Parameters', params.join('\n\n'));
        }

        if (item.returns) {
            const desc = item.returns.description ? `${this.clean(item.returns.description)}\n` : '';
            const type = this.joinType(item.returns.types || item.returns);
            const returns = `${desc}\`=> ${type}\``;
            embed.addField('Returns', returns);
        } else {
            embed.addField('Returns', '`=> void`');
        }

        return embed;
    }

    formatEvent(item, mainItem, version) {
        const embed = this.client.util.embed();

        let description = `__**[${mainItem.name}#${item.name}](${this.makeLink(mainItem, item, version)})**__\n`;

        if (item.description) description += `\n${this.clean(item.description)}`;
        embed.setDescription(description);

        if (item.params) {
            const params = item.params.map(param => {
                const type = this.joinType(param.type);
                return `\`${param.name}: ${type}\`\n${this.clean(param.description)}`;
            });

            embed.addField('Parameters', params.join('\n\n'));
        }

        return embed;
    }

    async exec(message, { query, version }) {
        if (!query) {
            Logger.error('No query provided.');
            return message.delete();
        }

        const docs = await this.fetchDocs(version);
        const [main, member] = this.search(docs, query);

        if (!main) {
            Logger.error('Could not find entry in docs.');
            return message.delete();
        }

        let embed;

        if (!member) {
            embed = this.formatMain(main.item, version);
        } else {
            embed = {
                props: this.formatProp,
                methods: this.formatMethod,
                events: this.formatEvent
            }[member.type].call(this, member.item, main.item, version);
        }

        const color = this.client.getColor(message);

        embed
        .setColor(color)
        .setURL(`https://discord.js.org/#/docs/main/${version}`)
        .setAuthor(`Discord.js Docs (${version})`, 'https://cdn.discordapp.com/icons/222078108977594368/bc226f09db83b9176c64d923ff37010b.webp');

        return message.edit({ embed });
    }
}

module.exports = DocsCommand;
<|endoftext|>


<commit_before>Template.inputForm.events({
  "submit #inputForm": function (evt, templ) {
    evt.preventDefault();
    var title = templ.find("#title").value;
    var numSessions = +templ.find("#numSessions").value;
    var hoursPerSession = +templ.find("#hoursPerSession").value;

    if (Session.get("selected_commitment")==="new_commitment"){
      Commitments.insert(
        {
          userId: Meteor.userId(),
          numSessions: numSessions,
          hoursPerSession: hoursPerSession,
          title: title,
          eventIds: []
        },
        function (err, commitmentId) {
          if (err) {
            alert(err + ". Are you signed in?");
          } else {
            generateEvents(commitmentId);
          };
        });
    }
    else{
      var commitment = Commitments.findOne(Session.get("selected_commitment"));
      _.each(commitment.eventIds, function(id){
        Events.remove(id);
      });
      Commitments.update(commitment._id,
                         { $set:
                           {
                             'title': title,
                             'numSessions': numSessions,
                             'hoursPerSession': hoursPerSession,
                             'eventIds': []
                           },
                         });
      generateEvents(commitment._id);
    }
  },

  "reset #inputForm": function (evt, tmpl){
    var commitment = Commitments.findOne(Session.get("selected_commitment"));
    _.each(commitment.eventIds, function(id){
      Events.remove(id);
    });
    Commitments.remove(commitment._id);
  }
});
<commit_msg>use Session.equals<commit_after>Template.inputForm.events({
  "submit #inputForm": function (evt, templ) {
    evt.preventDefault();
    var title = templ.find("#title").value;
    var numSessions = +templ.find("#numSessions").value;
    var hoursPerSession = +templ.find("#hoursPerSession").value;

    if (Session.equals("selected_commitment", "new_commitment")){
      Commitments.insert(
        {
          userId: Meteor.userId(),
          numSessions: numSessions,
          hoursPerSession: hoursPerSession,
          title: title,
          eventIds: []
        },
        function (err, commitmentId) {
          if (err) {
            alert(err + ". Are you signed in?");
          } else {
            generateEvents(commitmentId);
          };
        });
    }
    else{
      var commitment = Commitments.findOne(Session.get("selected_commitment"));
      _.each(commitment.eventIds, function(id){
        Events.remove(id);
      });
      Commitments.update(commitment._id,
                         { $set:
                           {
                             'title': title,
                             'numSessions': numSessions,
                             'hoursPerSession': hoursPerSession,
                             'eventIds': []
                           },
                         });
      generateEvents(commitment._id);
    }
  },

  "reset #inputForm": function (evt, tmpl){
    var commitment = Commitments.findOne(Session.get("selected_commitment"));
    _.each(commitment.eventIds, function(id){
      Events.remove(id);
    });
    Commitments.remove(commitment._id);
  }
});
<|endoftext|>