<commit_before>Components.utils.import('resource://greasemonkey/constants.js');
Components.utils.import('resource://greasemonkey/prefmanager.js');
Components.utils.import('resource://greasemonkey/script.js');
Components.utils.import('resource://greasemonkey/third-party/MatchPattern.js');
Components.utils.import('resource://greasemonkey/util.js');

function Config() {
  this._saveTimer = null;
  this._scripts = null;
  this._configFile = GM_util.scriptDir();
  this._configFile.append("config.xml");
  this._globalExcludes = JSON.parse(GM_prefRoot.getValue("globalExcludes"));
  this._observers = [];
}

Config.prototype.GM_GUID = "{e4a8a97b-f2ed-450b-b12d-ee082ba24781}";

Config.prototype.initialize = function() {
  this._updateVersion();
  this._load();
};

Config.prototype.addObserver = function(observer, script) {
  var observers = script ? script._observers : this._observers;
  observers.push(observer);
};

Config.prototype.removeObserver = function(observer, script) {
  var observers = script ? script._observers : this._observers;
  var index = observers.indexOf(observer);
  if (index == -1) throw new Error("Observer not found");
  observers.splice(index, 1);
},

Config.prototype._notifyObservers = function(script, event, data) {
  var observers = this._observers.concat(script._observers);
  for (var i = 0, observer; observer = observers[i]; i++) {
    observer.notifyEvent(script, event, data);
  }
};

Config.prototype._changed = function(script, event, data, dontSave) {
  if (!dontSave) {
    this._save();
  }

  this._notifyObservers(script, event, data);
};

Config.prototype.installIsUpdate = function(script) {
  return this._find(script) > -1;
};

Config.prototype._find = function(aScript) {
  for (var i = 0, script; script = this._scripts[i]; i++) {
    if (script.id == aScript.id) {
      return i;
    }
  }

  return -1;
};

Config.prototype._load = function() {
  var domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
      .createInstance(Components.interfaces.nsIDOMParser);

  var configContents = "<UserScriptConfig/>";
  if (this._configFile.exists()) {
    configContents = GM_util.getContents(this._configFile);
  }
  var doc = domParser.parseFromString(configContents, "text/xml");
  var nodes = doc.evaluate("/UserScriptConfig/Script", doc, null,
      7 /* XPathResult.ORDERED_NODE_SNAPSHOT_TYPE */,
      null);

  this._scripts = [];
  for (var i=0, node=null; node=nodes.snapshotItem(i); i++) {
    var script = new Script(node);
    if (script.allFilesExist()) {
      this._scripts.push(script);
    } else {
      // TODO: Add a user prompt to restore the missing script here?
      // Perhaps sometime after update works, and we know where to
      // download the script from?
      node.parentNode.removeChild(node);
      this._changed(script, "missing-removed", null);
    }
  }
};

Config.prototype._save = function(saveNow) {
  // If we have not explicitly been told to save now, then defer execution
  // via a timer, to avoid locking up the UI.
  if (!saveNow) {
    // Reduce work in the case of many changes near to each other in time.
    if (this._saveTimer) {
      this._saveTimer.cancel(this._saveTimer);
    }

    this._saveTimer = Components.classes["@mozilla.org/timer;1"]
        .createInstance(Components.interfaces.nsITimer);

    // dereference 'this' for the closure
    var _save = GM_util.hitch(this, "_save");

    this._saveTimer.initWithCallback(
        {'notify': function() { _save(true); }}, 250,
        Components.interfaces.nsITimer.TYPE_ONE_SHOT);
    return;
  }

  var doc = Components.classes["@mozilla.org/xmlextras/domparser;1"]
      .createInstance(Components.interfaces.nsIDOMParser)
      .parseFromString("<UserScriptConfig></UserScriptConfig>", "text/xml");

  for (var i = 0, scriptObj; scriptObj = this._scripts[i]; i++) {
    doc.firstChild.appendChild(doc.createTextNode("\n\t"));
    doc.firstChild.appendChild(scriptObj.toConfigNode(doc));
  }

  doc.firstChild.appendChild(doc.createTextNode("\n"));

  var domSerializer = Components
      .classes["@mozilla.org/xmlextras/xmlserializer;1"]
      .createInstance(Components.interfaces.nsIDOMSerializer);
  GM_util.writeToFile(domSerializer.serializeToString(doc), this._configFile);
};

Config.prototype.install = function(script, oldScript) {
  var existingIndex = this._find(oldScript || script);
  if (!oldScript) oldScript = this.scripts[existingIndex];

  if (oldScript) {
    // Save the old script's state.
    script._enabled = oldScript.enabled;
    script.userExcludes = oldScript.userExcludes;
    script.userIncludes = oldScript.userIncludes;

    // Uninstall the old script.
    this.uninstall(oldScript, true);
  }

  script._dependhash = GM_util.sha1(script._rawMeta);
  script._installTime = new Date().getTime()

  this._scripts.push(script);

  if (existingIndex > -1) {
    this.move(script, existingIndex - this._scripts.length + 1);
  }

  if (oldScript) {
    var scope = {};
    Components.utils.import('resource://greasemonkey/addons4.js', scope);
    scope.ScriptAddonReplaceScript(script);
    this._changed(script, 'modified', oldScript.id);
  } else {
    this._changed(script, 'install', existingIndex);
  }
};

Config.prototype.uninstall = function(script, forUpdate) {
  if ('undefined' == typeof(forUpdate)) forUpdate = false;

  var idx = this._find(script);
  this._scripts.splice(idx, 1);
  script.uninstall(forUpdate);
};

/**
 * Moves an installed user script to a new position in the array of installed scripts.
 *
 * @param script The script to be moved.
 * @param destination Can be either (a) a numeric offset for the script to be
 *                    moved by, or (b) another installed script to which
 *                    position the script will be moved.
 */
Config.prototype.move = function(script, destination) {
  var from = this._scripts.indexOf(script);
  var to = -1;

  // Make sure the user script is installed
  if (from == -1) return;

  if (typeof destination == "number") { // if destination is an offset
    to = from + destination;
    to = Math.max(0, to);
    to = Math.min(this._scripts.length - 1, to);
  } else { // if destination is a script object
    to = this._scripts.indexOf(destination);
  }

  if (to == -1) return;

  var tmp = this._scripts.splice(from, 1)[0];
  this._scripts.splice(to, 0, tmp);
  this._changed(script, "move", to);
},

Config.prototype.__defineGetter__('globalExcludes',
function Config_getGlobalExcludes() { return this._globalExcludes.concat(); }
);

Config.prototype.__defineSetter__('globalExcludes',
function Config_setGlobalExcludes(val) {
  this._globalExcludes = val.concat();
  GM_prefRoot.setValue("globalExcludes", JSON.stringify(this._globalExcludes));
});

Config.prototype.__defineGetter__('scripts',
function Config_getScripts() { return this._scripts.concat(); }
);

Config.prototype.getMatchingScripts = function(testFunc) {
  return this._scripts.filter(testFunc);
};

Config.prototype.updateModifiedScripts = function(aWhen, aSafeWin) {
  // Find any updated scripts or scripts with delayed injection
  var scripts = this.getMatchingScripts(
      function (script) {
        return script.runAt == aWhen
            && (script.isModified() || 0 != script.pendingExec.length);
      });
  if (0 == scripts.length) return;

  for (var i = 0, script; script = scripts[i]; i++) {
    if (0 == script.pendingExec.length) {
      var scope = {};
      Components.utils.import('resource://greasemonkey/parseScript.js', scope);
      var parsedScript = scope.parse(
          script.textContent, GM_util.uriFromUrl(script._downloadURL));
      // TODO: Show PopupNotifications about parse error(s)?
      script.updateFromNewScript(parsedScript, aSafeWin);
    } else {
      // We are already downloading dependencies for this script
      // so add its window to the list
      script.pendingExec.push({'safeWin': aSafeWin});
    }
  }

  this._save();
};

Config.prototype.getScriptById = function(scriptId) {
  for (var i = 0, script = null; script = this.scripts[i]; i++) {
    if (scriptId == script.id) {
      return script;
    }
  }
};

/**
 * Checks whether the version has changed since the last run and performs
 * any necessary upgrades.
 */
Config.prototype._updateVersion = function() {
  Components.utils.import("resource://gre/modules/AddonManager.jsm");
  AddonManager.getAddonByID(this.GM_GUID, GM_util.hitch(this, function(addon) {
    var oldVersion = GM_prefRoot.getValue("version");
    if ('0.0' == oldVersion) {
      // In case of pref branch transition, find the existing version there.
      oldVersion = this._getLegacyPrefMan().getValue("version", "0.0");
    }
    var newVersion = addon.version;

    var versionChecker = Components
        .classes["@mozilla.org/xpcom/version-comparator;1"]
        .getService(Components.interfaces.nsIVersionComparator);
    if (oldVersion != '0.0'
        && (versionChecker.compare(oldVersion, '1.5') < 0)
        && (versionChecker.compare(newVersion, '1.5beta1') >= 0)
    ) {
      this._migratePrefs();
    }

    // Update the stored current version so we don't do this work again.
    GM_prefRoot.setValue("version", newVersion);

    if ("0.0" == oldVersion) {
      // This is the first launch.  Show the welcome screen.
      var chromeWin = GM_util.getBrowserWindow();
      // If we found it, use it to open a welcome tab.
      if (chromeWin && chromeWin.gBrowser) {
        var url = 'http://www.greasespot.net/p/welcome.html?' + newVersion;
        // the setTimeout makes sure we do not execute too early -- sometimes
        // the window isn't quite ready to add a tab yet
        chromeWin.setTimeout(chromeWin.GM_BrowserUI.openTab, 0, url);
      }
    }
  }));
};

Config.prototype._getLegacyPrefMan = function() {
  // Supports #1652.
  var legacyPrefMan = new GM_PrefManager();
  legacyPrefMan.pref = Components.classes["@mozilla.org/preferences-service;1"]
     .getService(Components.interfaces.nsIPrefService)
     .getBranch('greasemonkey.');
  return legacyPrefMan;
};

Config.prototype._migratePrefs = function() {
  // See #1652.  Migrates from "greasemonkey." to "extensions.greasemonkey.".
  var fromBranch = this._getLegacyPrefMan();
  var toBranch = GM_prefRoot;
  var prefNames = fromBranch.listValues();
  for (var i = 0, prefName = null; prefName = prefNames[i]; i++) {
    toBranch.setValue(prefName, fromBranch.getValue(prefName));
    fromBranch.remove(prefName);
  }
};
<commit_msg>Additional timeout to make welcome page open more reliable.<commit_after>Components.utils.import('resource://greasemonkey/constants.js');
Components.utils.import('resource://greasemonkey/prefmanager.js');
Components.utils.import('resource://greasemonkey/script.js');
Components.utils.import('resource://greasemonkey/third-party/MatchPattern.js');
Components.utils.import('resource://greasemonkey/util.js');

function Config() {
  this._saveTimer = null;
  this._scripts = null;
  this._configFile = GM_util.scriptDir();
  this._configFile.append("config.xml");
  this._globalExcludes = JSON.parse(GM_prefRoot.getValue("globalExcludes"));
  this._observers = [];
}

Config.prototype.GM_GUID = "{e4a8a97b-f2ed-450b-b12d-ee082ba24781}";

Config.prototype.initialize = function() {
  this._updateVersion();
  this._load();
};

Config.prototype.addObserver = function(observer, script) {
  var observers = script ? script._observers : this._observers;
  observers.push(observer);
};

Config.prototype.removeObserver = function(observer, script) {
  var observers = script ? script._observers : this._observers;
  var index = observers.indexOf(observer);
  if (index == -1) throw new Error("Observer not found");
  observers.splice(index, 1);
},

Config.prototype._notifyObservers = function(script, event, data) {
  var observers = this._observers.concat(script._observers);
  for (var i = 0, observer; observer = observers[i]; i++) {
    observer.notifyEvent(script, event, data);
  }
};

Config.prototype._changed = function(script, event, data, dontSave) {
  if (!dontSave) {
    this._save();
  }

  this._notifyObservers(script, event, data);
};

Config.prototype.installIsUpdate = function(script) {
  return this._find(script) > -1;
};

Config.prototype._find = function(aScript) {
  for (var i = 0, script; script = this._scripts[i]; i++) {
    if (script.id == aScript.id) {
      return i;
    }
  }

  return -1;
};

Config.prototype._load = function() {
  var domParser = Components.classes["@mozilla.org/xmlextras/domparser;1"]
      .createInstance(Components.interfaces.nsIDOMParser);

  var configContents = "<UserScriptConfig/>";
  if (this._configFile.exists()) {
    configContents = GM_util.getContents(this._configFile);
  }
  var doc = domParser.parseFromString(configContents, "text/xml");
  var nodes = doc.evaluate("/UserScriptConfig/Script", doc, null,
      7 /* XPathResult.ORDERED_NODE_SNAPSHOT_TYPE */,
      null);

  this._scripts = [];
  for (var i=0, node=null; node=nodes.snapshotItem(i); i++) {
    var script = new Script(node);
    if (script.allFilesExist()) {
      this._scripts.push(script);
    } else {
      // TODO: Add a user prompt to restore the missing script here?
      // Perhaps sometime after update works, and we know where to
      // download the script from?
      node.parentNode.removeChild(node);
      this._changed(script, "missing-removed", null);
    }
  }
};

Config.prototype._save = function(saveNow) {
  // If we have not explicitly been told to save now, then defer execution
  // via a timer, to avoid locking up the UI.
  if (!saveNow) {
    // Reduce work in the case of many changes near to each other in time.
    if (this._saveTimer) {
      this._saveTimer.cancel(this._saveTimer);
    }

    this._saveTimer = Components.classes["@mozilla.org/timer;1"]
        .createInstance(Components.interfaces.nsITimer);

    // dereference 'this' for the closure
    var _save = GM_util.hitch(this, "_save");

    this._saveTimer.initWithCallback(
        {'notify': function() { _save(true); }}, 250,
        Components.interfaces.nsITimer.TYPE_ONE_SHOT);
    return;
  }

  var doc = Components.classes["@mozilla.org/xmlextras/domparser;1"]
      .createInstance(Components.interfaces.nsIDOMParser)
      .parseFromString("<UserScriptConfig></UserScriptConfig>", "text/xml");

  for (var i = 0, scriptObj; scriptObj = this._scripts[i]; i++) {
    doc.firstChild.appendChild(doc.createTextNode("\n\t"));
    doc.firstChild.appendChild(scriptObj.toConfigNode(doc));
  }

  doc.firstChild.appendChild(doc.createTextNode("\n"));

  var domSerializer = Components
      .classes["@mozilla.org/xmlextras/xmlserializer;1"]
      .createInstance(Components.interfaces.nsIDOMSerializer);
  GM_util.writeToFile(domSerializer.serializeToString(doc), this._configFile);
};

Config.prototype.install = function(script, oldScript) {
  var existingIndex = this._find(oldScript || script);
  if (!oldScript) oldScript = this.scripts[existingIndex];

  if (oldScript) {
    // Save the old script's state.
    script._enabled = oldScript.enabled;
    script.userExcludes = oldScript.userExcludes;
    script.userIncludes = oldScript.userIncludes;

    // Uninstall the old script.
    this.uninstall(oldScript, true);
  }

  script._dependhash = GM_util.sha1(script._rawMeta);
  script._installTime = new Date().getTime()

  this._scripts.push(script);

  if (existingIndex > -1) {
    this.move(script, existingIndex - this._scripts.length + 1);
  }

  if (oldScript) {
    var scope = {};
    Components.utils.import('resource://greasemonkey/addons4.js', scope);
    scope.ScriptAddonReplaceScript(script);
    this._changed(script, 'modified', oldScript.id);
  } else {
    this._changed(script, 'install', existingIndex);
  }
};

Config.prototype.uninstall = function(script, forUpdate) {
  if ('undefined' == typeof(forUpdate)) forUpdate = false;

  var idx = this._find(script);
  this._scripts.splice(idx, 1);
  script.uninstall(forUpdate);
};

/**
 * Moves an installed user script to a new position in the array of installed scripts.
 *
 * @param script The script to be moved.
 * @param destination Can be either (a) a numeric offset for the script to be
 *                    moved by, or (b) another installed script to which
 *                    position the script will be moved.
 */
Config.prototype.move = function(script, destination) {
  var from = this._scripts.indexOf(script);
  var to = -1;

  // Make sure the user script is installed
  if (from == -1) return;

  if (typeof destination == "number") { // if destination is an offset
    to = from + destination;
    to = Math.max(0, to);
    to = Math.min(this._scripts.length - 1, to);
  } else { // if destination is a script object
    to = this._scripts.indexOf(destination);
  }

  if (to == -1) return;

  var tmp = this._scripts.splice(from, 1)[0];
  this._scripts.splice(to, 0, tmp);
  this._changed(script, "move", to);
},

Config.prototype.__defineGetter__('globalExcludes',
function Config_getGlobalExcludes() { return this._globalExcludes.concat(); }
);

Config.prototype.__defineSetter__('globalExcludes',
function Config_setGlobalExcludes(val) {
  this._globalExcludes = val.concat();
  GM_prefRoot.setValue("globalExcludes", JSON.stringify(this._globalExcludes));
});

Config.prototype.__defineGetter__('scripts',
function Config_getScripts() { return this._scripts.concat(); }
);

Config.prototype.getMatchingScripts = function(testFunc) {
  return this._scripts.filter(testFunc);
};

Config.prototype.updateModifiedScripts = function(aWhen, aSafeWin) {
  // Find any updated scripts or scripts with delayed injection
  var scripts = this.getMatchingScripts(
      function (script) {
        return script.runAt == aWhen
            && (script.isModified() || 0 != script.pendingExec.length);
      });
  if (0 == scripts.length) return;

  for (var i = 0, script; script = scripts[i]; i++) {
    if (0 == script.pendingExec.length) {
      var scope = {};
      Components.utils.import('resource://greasemonkey/parseScript.js', scope);
      var parsedScript = scope.parse(
          script.textContent, GM_util.uriFromUrl(script._downloadURL));
      // TODO: Show PopupNotifications about parse error(s)?
      script.updateFromNewScript(parsedScript, aSafeWin);
    } else {
      // We are already downloading dependencies for this script
      // so add its window to the list
      script.pendingExec.push({'safeWin': aSafeWin});
    }
  }

  this._save();
};

Config.prototype.getScriptById = function(scriptId) {
  for (var i = 0, script = null; script = this.scripts[i]; i++) {
    if (scriptId == script.id) {
      return script;
    }
  }
};

/**
 * Checks whether the version has changed since the last run and performs
 * any necessary upgrades.
 */
Config.prototype._updateVersion = function() {
  Components.utils.import("resource://gre/modules/AddonManager.jsm");
  AddonManager.getAddonByID(this.GM_GUID, GM_util.hitch(this, function(addon) {
    var oldVersion = GM_prefRoot.getValue("version");
    if ('0.0' == oldVersion) {
      // In case of pref branch transition, find the existing version there.
      oldVersion = this._getLegacyPrefMan().getValue("version", "0.0");
    }
    var newVersion = addon.version;

    var versionChecker = Components
        .classes["@mozilla.org/xpcom/version-comparator;1"]
        .getService(Components.interfaces.nsIVersionComparator);
    if (oldVersion != '0.0'
        && (versionChecker.compare(oldVersion, '1.5') < 0)
        && (versionChecker.compare(newVersion, '1.5beta1') >= 0)
    ) {
      this._migratePrefs();
    }

    // Update the stored current version so we don't do this work again.
    GM_prefRoot.setValue("version", newVersion);

    if ("0.0" == oldVersion) {
      // This is the first launch.  Show the welcome screen.
      var chromeWin = GM_util.getBrowserWindow();
      // If we found it, use it to open a welcome tab.
      if (chromeWin && chromeWin.gBrowser) {
        var url = 'http://www.greasespot.net/p/welcome.html'
            + '?utm_source=xpi&utm_medium=xpi&utm_campaign=welcome'
            + '&utm_content=' + newVersion;
        // the setTimeout makes sure we do not execute too early -- sometimes
        // the window isn't quite ready to add a tab yet
        chromeWin.setTimeout(chromeWin.GM_BrowserUI.openTab, 100, url);
      }
    }
  }));
};

Config.prototype._getLegacyPrefMan = function() {
  // Supports #1652.
  var legacyPrefMan = new GM_PrefManager();
  legacyPrefMan.pref = Components.classes["@mozilla.org/preferences-service;1"]
     .getService(Components.interfaces.nsIPrefService)
     .getBranch('greasemonkey.');
  return legacyPrefMan;
};

Config.prototype._migratePrefs = function() {
  // See #1652.  Migrates from "greasemonkey." to "extensions.greasemonkey.".
  var fromBranch = this._getLegacyPrefMan();
  var toBranch = GM_prefRoot;
  var prefNames = fromBranch.listValues();
  for (var i = 0, prefName = null; prefName = prefNames[i]; i++) {
    toBranch.setValue(prefName, fromBranch.getValue(prefName));
    fromBranch.remove(prefName);
  }
};
<|endoftext|>


<commit_before>/* TODO:
 * What do we want next?
 *
 * Different species?
 * Temperature options?
 *
 *
 */

const radius = 5;
const sense = 25;
const ripple = 25;

const clock = 250;//150;50;
const anim = 150;
const initCount = 2000;//2000;

const fireProbL = 0.02;//Natural case
const fireProbR = 0.0005;//Suppression case
// const fireProb = fireProbL;

const growthStep = 1000;
const radInc = 2;
const burnRate = 0.9;

const treeColors = [
    "#ABEBC6",
    "#82E0AA",
    "#58D68D",
    "#2ECC71",
    "#28B463",
    "#239B56",
    "#1D8348"
];

var treeList = [];
var fireList = [];
var step = 0;
var showAnim = false;
var treeGrid = [];

const w = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    width = -10 + w.innerWidth || e.clientWidth || g.clientWidth,
    height = -20 + w.innerHeight|| e.clientHeight|| g.clientHeight,
    split = width/2;

var draw = SVG('svgCanvas').size(width, height);
document.body.style.backgroundColor = "black";

var textL = draw.text("Natural Forest")
textL.move(50, height - 120);
textL.fill('mediumorchid');
textL.opacity(0.9);
textL.font({size:60});

var textR = draw.text("Fire Suppression")
textR.move(split+50, height - 120);
textR.fill('mediumorchid');
textR.opacity(0.9);
textR.font({size:60});

var divider = draw.line(split, 0, split, height).stroke({width:6})
divider.stroke('lightgray');
divider.opacity(0.8);

/* Upon click, add a new agent to the canvas
 */
var clickHandler = function(e) {
    drop(e.x - radius, e.y - radius, 1);
    checkAgents();
}
draw.on('click', clickHandler);

/* Function to be run at every clock step
 */
function add() {

    if (fireList.length == 0) {
        let x = Math.floor(Math.random() * width);
        let y = Math.floor(Math.random() * height);
        state = 0;
        if (Math.random() < fireProb(x)) {
            state = 1;
        }
        drop(x, y, state);
    }
    checkAgents();

    textL.front();
    textR.front();
    divider.front();
    step++;
}
var timer = setInterval(add, clock);

function init() {
    showAnim = false;
    for (let i = 0; i < initCount; i++) {
        add();
    }
    showAnim = true;
}
init();

/* When adding a node, animate a circle, add the node to the appropriate list.
 */
function drop(x, y, state) {

    let agent = draw.circle(radius*2, radius*2);
    agent.cx(x).cy(y);
    agent.id = step;
    agent.age = 0;

    color = treeColors[0];
    if (state == 0) {
        color = treeColors[0];
        treeList.push(agent);

        if (showAnim) {
            let ring = draw.circle(ripple).fill('none').stroke({color:color,width:2});
            ring.cx(x).cy(y);
            ring.animate(anim*3).radius(1).after(()=>{ring.remove()});
        }

    } else {
        color = 'white';
        fireList.push(agent);
        agent.age = 10;

        if (showAnim) {
            let ring = draw.circle(1).fill('white').stroke({color:color,width:2});
            ring.cx(x).cy(y);
            ring.animate(anim*1).radius(ripple*2).after(()=>{ring.remove()});
        }
    }
    agent.fill(color);
}

/* Check the state of the agent list and update where necessary.
 */
function checkAgents() {
    newTreeList = [];
    newFireList = [];

    for (tree of treeList) {
        /* Iterate over the elements in the tree list
        * Iterate over the elements in the fire list
        * If a tree is near a fire, add it to the fire list
        * Otherwise, add it to the new tree list
        */

        caught = false;
        for (fire of fireList) {

            // burnProb = burnRate * Math.pow(burnFactor,(tree.age/fire.age))
            burnProb = Math.pow(burnRate,(tree.age/fire.age))
            if (prox(tree, fire) && Math.random() < (burnProb)) {
                tree.fill('orangered');

                if (showAnim) {
                    let ring1 = draw.circle(1).fill('none').stroke({color:'orangered',width:2});
                    ring1.cx(tree.cx()).cy(tree.cy());
                    ring1.animate(anim*3).radius(ripple).after(()=>{ring1.remove()});

                    let ring2 = draw.circle(1).fill('none').stroke({color:'orange',width:2});
                    ring2.cx(tree.cx()).cy(tree.cy());
                    ring2.animate(anim*3).radius(ripple-5).after(()=>{ring2.remove()});

                    let ring3 = draw.circle(1).fill('none').stroke({color:'yellow',width:2});
                    ring3.cx(tree.cx()).cy(tree.cy());
                    ring3.animate(anim*3).radius(ripple-10).after(()=>{ring3.remove()});
                }

                newFireList.push(tree);
                caught = true;
                break
            }
        }
        if (!caught) {
            tree.age = Math.floor((step - tree.id)/growthStep)
            colorIndex = Math.min(treeColors.length, tree.age)
            newRad = radius + (radInc * colorIndex)
            tree.radius(newRad)
            tree.fill(treeColors[colorIndex])
            newTreeList.push(tree);
        }
    }

    for (fire of fireList) {
        fire.remove();
    }
    treeList = newTreeList;
    fireList = newFireList;
}

/* Does agent fall within sensing radius of another
*/
function prox(agent, other) {

    let xDist = agent.x() - other.x();
    let yDist = agent.y() - other.y();
    let dist = Math.sqrt(xDist*xDist + yDist*yDist);

    let result = false;
    if (dist < sense && isLeft(agent) == isLeft(other)) result = true;
    return result;
}

function isLeft(agent) {
    return agent.cx() < split;
}

function fireProb(x) {
    result = fireProbR;
    if (x < split) {
        result = fireProbL;
    }
    return result;
}<commit_msg>Update Forest3.js<commit_after>/* TODO:
 * What do we want next?
 *
 * Different species?
 * Temperature options?
 *
 *
 */

const radius = 5;
const sense = 25;
const ripple = 25;

const clock = 80;//250;//150;50;
const anim = 150;
const initCount = 2000;//2000;

const fireProbL = 0.02;//Natural case
const fireProbR = 0.0005;//Suppression case
// const fireProb = fireProbL;

const growthStep = 1000;
const radInc = 2;
const burnRate = 0.9;

const treeColors = [
    "#ABEBC6",
    "#82E0AA",
    "#58D68D",
    "#2ECC71",
    "#28B463",
    "#239B56",
    "#1D8348"
];

var treeList = [];
var fireList = [];
var step = 0;
var showAnim = false;
var treeGrid = [];

const w = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    width = -10 + w.innerWidth || e.clientWidth || g.clientWidth,
    height = -20 + w.innerHeight|| e.clientHeight|| g.clientHeight,
    split = width/2;

var draw = SVG('svgCanvas').size(width, height);
document.body.style.backgroundColor = "black";

var textL = draw.text("Natural Forest")
textL.move(50, height - 120);
textL.fill('mediumorchid');
textL.opacity(0.9);
textL.font({size:60});

var textR = draw.text("Fire Suppression")
textR.move(split+50, height - 120);
textR.fill('mediumorchid');
textR.opacity(0.9);
textR.font({size:60});

var divider = draw.line(split, 0, split, height).stroke({width:6})
divider.stroke('lightgray');
divider.opacity(0.8);

/* Upon click, add a new agent to the canvas
 */
var clickHandler = function(e) {
    drop(e.x - radius, e.y - radius, 1);
    checkAgents();
}
draw.on('click', clickHandler);

/* Function to be run at every clock step
 */
function add() {

    if (fireList.length == 0) {
        let x = Math.floor(Math.random() * width);
        let y = Math.floor(Math.random() * height);
        state = 0;
        if (Math.random() < fireProb(x)) {
            state = 1;
        }
        drop(x, y, state);
    }
    checkAgents();

    textL.front();
    textR.front();
    divider.front();
    step++;
}
var timer = setInterval(add, clock);

function init() {
    showAnim = false;
    for (let i = 0; i < initCount; i++) {
        add();
    }
    showAnim = true;
}
init();

/* When adding a node, animate a circle, add the node to the appropriate list.
 */
function drop(x, y, state) {

    let agent = draw.circle(radius*2, radius*2);
    agent.cx(x).cy(y);
    agent.id = step;
    agent.age = 0;

    color = treeColors[0];
    if (state == 0) {
        color = treeColors[0];
        treeList.push(agent);

        if (showAnim) {
            let ring = draw.circle(ripple).fill('none').stroke({color:color,width:2});
            ring.cx(x).cy(y);
            ring.animate(anim*3).radius(1).after(()=>{ring.remove()});
        }

    } else {
        color = 'white';
        fireList.push(agent);
        agent.age = 10;

        if (showAnim) {
            let ring = draw.circle(1).fill('white').stroke({color:color,width:2});
            ring.cx(x).cy(y);
            ring.animate(anim*1).radius(ripple*2).after(()=>{ring.remove()});
        }
    }
    agent.fill(color);
}

/* Check the state of the agent list and update where necessary.
 */
function checkAgents() {
    newTreeList = [];
    newFireList = [];

    for (tree of treeList) {
        /* Iterate over the elements in the tree list
        * Iterate over the elements in the fire list
        * If a tree is near a fire, add it to the fire list
        * Otherwise, add it to the new tree list
        */

        caught = false;
        for (fire of fireList) {

            // burnProb = burnRate * Math.pow(burnFactor,(tree.age/fire.age))
            burnProb = Math.pow(burnRate,(tree.age/fire.age))
            if (prox(tree, fire) && Math.random() < (burnProb)) {
                tree.fill('orangered');

                if (showAnim) {
                    let ring1 = draw.circle(1).fill('none').stroke({color:'orangered',width:2});
                    ring1.cx(tree.cx()).cy(tree.cy());
                    ring1.animate(anim*3).radius(ripple).after(()=>{ring1.remove()});

                    let ring2 = draw.circle(1).fill('none').stroke({color:'orange',width:2});
                    ring2.cx(tree.cx()).cy(tree.cy());
                    ring2.animate(anim*3).radius(ripple-5).after(()=>{ring2.remove()});

                    let ring3 = draw.circle(1).fill('none').stroke({color:'yellow',width:2});
                    ring3.cx(tree.cx()).cy(tree.cy());
                    ring3.animate(anim*3).radius(ripple-10).after(()=>{ring3.remove()});
                }

                newFireList.push(tree);
                caught = true;
                break
            }
        }
        if (!caught) {
            tree.age = Math.floor((step - tree.id)/growthStep)
            colorIndex = Math.min(treeColors.length, tree.age)
            newRad = radius + (radInc * colorIndex)
            tree.radius(newRad)
            tree.fill(treeColors[colorIndex])
            newTreeList.push(tree);
        }
    }

    for (fire of fireList) {
        fire.remove();
    }
    treeList = newTreeList;
    fireList = newFireList;
}

/* Does agent fall within sensing radius of another
*/
function prox(agent, other) {

    let xDist = agent.x() - other.x();
    let yDist = agent.y() - other.y();
    let dist = Math.sqrt(xDist*xDist + yDist*yDist);

    let result = false;
    if (dist < sense && isLeft(agent) == isLeft(other)) result = true;
    return result;
}

function isLeft(agent) {
    return agent.cx() < split;
}

function fireProb(x) {
    result = fireProbR;
    if (x < split) {
        result = fireProbL;
    }
    return result;
}
<|endoftext|>


<commit_before>var assert = require('assert'),
    _ = require('lodash');

describe('Semantic Interface', function() {

  describe('Datetime Type', function() {
    describe('with valid data', function() {

      /////////////////////////////////////////////////////
      // TEST METHODS
      ////////////////////////////////////////////////////

      var dateId;
      var date = new Date(2010, 10, 05, 10, 03, 40);
      var origDate = date.getTime();

      it('should store proper datetime value', function(done) {
        Semantic.User.create({ dob: date }, function(err, createdRecord) {
          assert.ifError(err);
          createdDate = createdRecord.dob.getTime();
          assert.strictEqual(origDate, createdDate);
          dateId = createdRecord.id;
          Semantic.User.findOne({id: createdRecord.id}, function (err, record) {
            assert.ifError(err);
            process.exit();
            // Convert both dates to unix timestamps
            var resultDate = record.dob.getTime();
            assert.strictEqual(origDate, resultDate, 'datetime should correspond');
            done();
          });
        });
      });

      it('should find record by datetime criteria', function(done) {
        Semantic.User.find({dob: date}, function (err, record) {
          assert.ifError(err);
          assert.strictEqual(record.length, 1, 'should have 1 result');

          // Convert both dates to unix timestamps
          var resultDate = record[0].dob.getTime();
          assert.strictEqual(dateId, record[0].id, 'id should correspond');
          assert.strictEqual(origDate, resultDate, 'datetime should correspond');
          done();
        });
      });

    });
  });
});
<commit_msg>remove typo<commit_after>var assert = require('assert'),
    _ = require('lodash');

describe('Semantic Interface', function() {

  describe('Datetime Type', function() {
    describe('with valid data', function() {

      /////////////////////////////////////////////////////
      // TEST METHODS
      ////////////////////////////////////////////////////

      var dateId;
      var date = new Date(2010, 10, 05, 10, 03, 40);
      var origDate = date.getTime();

      it('should store proper datetime value', function(done) {
        Semantic.User.create({ dob: date }, function(err, createdRecord) {
          assert.ifError(err);
          createdDate = createdRecord.dob.getTime();
          assert.strictEqual(origDate, createdDate);
          dateId = createdRecord.id;
          Semantic.User.findOne({id: createdRecord.id}, function (err, record) {
            assert.ifError(err);
            // Convert both dates to unix timestamps
            var resultDate = record.dob.getTime();
            assert.strictEqual(origDate, resultDate, 'datetime should correspond');
            done();
          });
        });
      });

      it('should find record by datetime criteria', function(done) {
        Semantic.User.find({dob: date}, function (err, record) {
          assert.ifError(err);
          assert.strictEqual(record.length, 1, 'should have 1 result');

          // Convert both dates to unix timestamps
          var resultDate = record[0].dob.getTime();
          assert.strictEqual(dateId, record[0].id, 'id should correspond');
          assert.strictEqual(origDate, resultDate, 'datetime should correspond');
          done();
        });
      });

    });
  });
});
<|endoftext|>


<commit_before>var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');

// Initialize jQuery in BackBone
Backbone.$ = $;

var unknown = "unknown", fail = no = false, pass = yes = true, empty = "";

var client = new Object;

client.build = function(){
	var Model = Backbone.Model.extend({
		urlRoot: '/api',
		idAttribute: 'eID',

		// Default attributes
		defaults: function() {
			return {
				eID: undefined,
				from: { name:unknown, email:unknown },
				to: new Array,
				subject: unknown,

				text: empty,
				html: unknown,

				stamp: undefined
			};
		},

		initialize: function() {

		},

		store: function() {
			this.save();
		},

		setRead: function() {
			this.set('read', true);
		}

	});

	var Collection = Backbone.Collection.extend({
		url: '/api',

		// Reference to this collection's model.
		model: Model,

		initialize: function(){
			//this.model.on('sync', this.onSync);
			//this.model.on('error', this.onError);
			//this.model.on('destroy', this.onDestroy);
		},

		// Filter down the list of all unread emails.
		read: function(eID) {
			return this.model.setRead();
		}
	});

	var ItemView = Backbone.View.extend({
		tagName:  "article",

		template: _.template('<%- subject %>'),

		// The DOM events specific to an item.
		events: {
			"click .header"   : "clicked"
		},

		initialize: function() {
			//this.listenTo(this.model, 'change', this.render);
			//this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		},

		clicked: function() {
			console.log("Just letting you know someone clicked on something");
		}

	});

	var Mail = new Collection;

	var View = Backbone.View.extend({
		el: "section#list",

		template: _.template('
<%- from.email %>

<%- subject %>
'),

		initialize: function() {
			this.listenTo(Mail, 'all', this.render);

			Mail.fetch();
		},

		addOne: function(mail) {
			var el = $(this.el);
			var view = new ItemView({model: mail});
			if(!el.find('#' + el.get('eID')).length)
				el.append(view.render().el);
		},

		addAll: function() {
		  Mail.each(this.addOne, this);
		},

		render: function() {
			this.addAll();
		}

	});

	this.Model = Model;
	this.Mail = Mail;
	this.ItemView = ItemView;
	this.View = new View;
}

$(function(){ window.API = new client.build(); })<commit_msg>Added eID to all mails in View<commit_after>var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');

// Initialize jQuery in BackBone
Backbone.$ = $;

var unknown = "unknown", fail = no = false, pass = yes = true, empty = "";

var client = new Object;

client.build = function(){
	var Model = Backbone.Model.extend({
		urlRoot: '/api',
		idAttribute: 'eID',

		// Default attributes
		defaults: function() {
			return {
				eID: undefined,
				from: { name:unknown, email:unknown },
				to: new Array,
				subject: unknown,

				text: empty,
				html: unknown,

				stamp: undefined
			};
		},

		initialize: function() {

		},

		store: function() {
			this.save();
		},

		setRead: function() {
			this.set('read', true);
		}

	});

	var Collection = Backbone.Collection.extend({
		url: '/api',

		// Reference to this collection's model.
		model: Model,

		initialize: function(){
			//this.model.on('sync', this.onSync);
			//this.model.on('error', this.onError);
			//this.model.on('destroy', this.onDestroy);
		},

		// Filter down the list of all unread emails.
		read: function(eID) {
			return this.model.setRead();
		}
	});

	var ItemView = Backbone.View.extend({
		tagName:  "article",

		template: _.template('<%- subject %>'),

		// The DOM events specific to an item.
		events: {
			"click .header"   : "clicked"
		},

		initialize: function() {
			//this.listenTo(this.model, 'change', this.render);
			//this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		},

		clicked: function() {
			console.log("Just letting you know someone clicked on something");
		}

	});

	var Mail = new Collection;

	var View = Backbone.View.extend({
		el: "section#list",

		template: _.template('
<%- from.email %>

<%- subject %>
'),

		initialize: function() {
			this.listenTo(Mail, 'all', this.render);

			Mail.fetch();
		},

		addOne: function(mail) {
			var el = $(this.el);
			var view = new ItemView({model: mail});
			if(!el.find('#' + el.get('eID')).length)
				el.append(view.render().el).prop('id',el.get('eID'));
		},

		addAll: function() {
		  Mail.each(this.addOne, this);
		},

		render: function() {
			this.addAll();
		}

	});

	this.Model = Model;
	this.Mail = Mail;
	this.ItemView = ItemView;
	this.View = new View;
}

$(function(){ window.API = new client.build(); })<|endoftext|>


<commit_before>var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');

// Initialize jQuery in BackBone
Backbone.$ = $;

var unknown = "unknown", fail = no = false, pass = yes = true, empty = "";

var client = new Object;

client.build = function(){
	var Model = Backbone.Model.extend({
		urlRoot: '/api',
		idAttribute: 'eID',

		// Default attributes
		defaults: function() {
			return {
				eID: undefined,
				from: { name:unknown, email:unknown },
				to: new Array,
				subject: unknown,

				text: empty,
				html: unknown,

				stamp: undefined
			};
		},

		initialize: function() {

		},

		store: function() {
			this.save();
		},

		setRead: function() {
			this.set('read', true);
		}

	});

	var Collection = Backbone.Collection.extend({
		url: '/api',

		// Reference to this collection's model.
		model: Model,

		initialize: function(){
			//this.model.on('sync', this.onSync);
			//this.model.on('error', this.onError);
			//this.model.on('destroy', this.onDestroy);
		},

		// Filter down the list of all unread emails.
		read: function(eID) {
			return this.model.setRead();
		}
	});

	var ItemView = Backbone.View.extend({
		tagName:  "article",

		template: _.template('<%- subject %>'),

		// The DOM events specific to an item.
		events: {
			"click .header"   : "clicked"
		},

		initialize: function() {
			//this.listenTo(this.model, 'change', this.render);
			//this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		},

		clicked: function() {
			console.log("Just letting you know someone clicked on something");
		}

	});

	var Mail = new Collection;

	var View = Backbone.View.extend({
		el: "section#list",

		template: _.template('
<%- from.email %>

<%- subject %>
'),

		initialize: function() {
			this.listenTo(Mail, 'all', this.render);

			Mail.fetch();
		},

		addOne: function(mail) {
			var el = $(this.el);
			var view = new ItemView({model: mail});
			if(!el.find('#' + el.get('eID')).length)
				el.append(view.render().el).prop('id',el.get('eID'));
		},

		addAll: function() {
		  Mail.each(this.addOne, this);
		},

		render: function() {
			this.addAll();
		}

	});

	this.Model = Model;
	this.Mail = Mail;
	this.ItemView = ItemView;
	this.View = new View;
}

$(function(){ window.API = new client.build(); })<commit_msg>UI: eID append fix<commit_after>var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');

// Initialize jQuery in BackBone
Backbone.$ = $;

var unknown = "unknown", fail = no = false, pass = yes = true, empty = "";

var client = new Object;

client.build = function(){
	var Model = Backbone.Model.extend({
		urlRoot: '/api',
		idAttribute: 'eID',

		// Default attributes
		defaults: function() {
			return {
				eID: undefined,
				from: { name:unknown, email:unknown },
				to: new Array,
				subject: unknown,

				text: empty,
				html: unknown,

				stamp: undefined
			};
		},

		initialize: function() {

		},

		store: function() {
			this.save();
		},

		setRead: function() {
			this.set('read', true);
		}

	});

	var Collection = Backbone.Collection.extend({
		url: '/api',

		// Reference to this collection's model.
		model: Model,

		initialize: function(){
			//this.model.on('sync', this.onSync);
			//this.model.on('error', this.onError);
			//this.model.on('destroy', this.onDestroy);
		},

		// Filter down the list of all unread emails.
		read: function(eID) {
			return this.model.setRead();
		}
	});

	var ItemView = Backbone.View.extend({
		tagName:  "article",

		template: _.template('<%- subject %>'),

		// The DOM events specific to an item.
		events: {
			"click .header"   : "clicked"
		},

		initialize: function() {
			//this.listenTo(this.model, 'change', this.render);
			//this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		},

		clicked: function() {
			console.log("Just letting you know someone clicked on something");
		}

	});

	var Mail = new Collection;

	var View = Backbone.View.extend({
		el: "section#list",

		template: _.template('
<%- from.email %>

<%- subject %>
'),

		initialize: function() {
			this.listenTo(Mail, 'all', this.render);

			Mail.fetch();
		},

		addOne: function(mail) {
			var el = $(this.el);
			var view = new ItemView({model: mail});
			console.log(el.get('eID'),);
			if(!el.find('#' + el.get('eID')).length){
				var newElement = $(view.render().el);
				el.append(newElement);
				newElement.prop('id',el.get('eID'));
			}
		},

		addAll: function() {
		  Mail.each(this.addOne, this);
		},

		render: function() {
			this.addAll();
		}

	});

	this.Model = Model;
	this.Mail = Mail;
	this.ItemView = ItemView;
	this.View = new View;
}

$(function(){ window.API = new client.build(); })<|endoftext|>


<commit_before>const express = require('express');
const Raven = require('raven');
const bodyParser = require('body-parser');
const tokenToUser = require('./middleware/tokenToUser');
const mustBeAuthenticated = require('./middleware/mustBeAuthenticated');
const mustBeAdmin = require('./middleware/mustBeAdmin');
const configuration = require('src/config/configuration').getInstance();

// TODO: Have our raven router check if there is a value, if not don't enable raven.
Raven.config(configuration.get('raven', 'DSN')).install();

const app = express(); // define our app using express
app.use(Raven.requestHandler());
// this will let us get the data from a POST
// configure app to use bodyParser()
app.use(bodyParser.json());
// router.use(bodyParser.urlencoded({ extended: true }));

const router = express.Router();
const allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'];

// TODO: All JSON handling in a single router
// router.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

/* Decode the Authorization header if provided */
router.use(tokenToUser);

// TODO: Should have a separate middleware/router for handling headers.
router.use((req, res, next) => {
   // TODO add logging of all incoming
   console.log('Request: ', req.originalUrl);
   const origin = req.headers.origin;
   if (allowedOrigins.indexOf(origin) > -1) {
      console.log('allowed');
      res.setHeader('Access-Control-Allow-Origin', origin);
   }
   res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, loggedinuser');
   res.header('Access-Control-Allow-Methods', 'POST, GET, PUT');

   next();
});

router.get('/', function mainHandler(req, res) {
   throw new Error('Broke!');
});

app.use(Raven.errorHandler());
app.use(function onError(err, req, res, next) {
   res.statusCode = 500;
   res.end(res.sentry + '\n');
});

/**
 * User
 */
router.post('/v1/user', require('./controllers/user/register.js'));
router.post('/v1/user/login', require('./controllers/user/login.js'));
router.get('/v1/user/history', mustBeAuthenticated, require('./controllers/user/history.js'));
router.get('/v1/user/requests', mustBeAuthenticated, require('./controllers/user/requests.js'));

/**
 * Seasoned
 */
router.get('/v1/seasoned/all', require('./controllers/seasoned/readStrays.js'));
router.get('/v1/seasoned/:strayId', require('./controllers/seasoned/strayById.js'));
router.post('/v1/seasoned/verify/:strayId', require('./controllers/seasoned/verifyStray.js'));

router.get('/v2/search/', require('./controllers/search/multiSearch.js'));
router.get('/v2/search/movie', require('./controllers/search/movieSearch.js'));
router.get('/v2/search/show', require('./controllers/search/showSearch.js'));
router.get('/v2/search/person', require('./controllers/search/personSearch.js'));

router.get('/v2/movie/:id', require('./controllers/info/movieInfo.js'));
router.get('/v2/show/:id', require('./controllers/info/showInfo.js'));
router.get('/v2/person/:id', require('./controllers/info/personInfo.js'));
/**
 * Plex
 */
router.get('/v1/plex/search', require('./controllers/plex/searchMedia.js'));
router.get('/v1/plex/playing', require('./controllers/plex/plexPlaying.js'));
router.get('/v1/plex/request', require('./controllers/plex/searchRequest.js'));
router.get('/v1/plex/request/:mediaId', require('./controllers/plex/readRequest.js'));
router.post('/v1/plex/request/:mediaId', require('./controllers/plex/submitRequest.js'));
router.get('/v1/plex/hook', require('./controllers/plex/hookDump.js'));

/**
 * Requests
 */
router.get('/v1/plex/requests/all', require('./controllers/plex/fetchRequested.js'));
router.put('/v1/plex/request/:requestId', mustBeAuthenticated, require('./controllers/plex/updateRequested.js'));

/**
 * Pirate
 */
router.get('/v1/pirate/search', mustBeAuthenticated, require('./controllers/pirate/searchTheBay.js'));
router.post('/v1/pirate/add', mustBeAuthenticated, require('./controllers/pirate/addMagnet.js'));

/**
 * TMDB
 */
router.get('/v1/tmdb/search', require('./controllers/tmdb/searchMedia.js'));
router.get('/v1/tmdb/list/:listname', require('./controllers/tmdb/listSearch.js'));
router.get('/v1/tmdb/:mediaId', require('./controllers/tmdb/readMedia.js'));

/**
 * git
 */
router.post('/v1/git/dump', require('./controllers/git/dumpHook.js'));

/**
 * misc
 */
 router.get('/v1/emoji', require('./controllers/misc/emoji.js'));

// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);

module.exports = app;
<commit_msg>Added endpoint for new plex search.<commit_after>const express = require('express');
const Raven = require('raven');
const bodyParser = require('body-parser');
const tokenToUser = require('./middleware/tokenToUser');
const mustBeAuthenticated = require('./middleware/mustBeAuthenticated');
const mustBeAdmin = require('./middleware/mustBeAdmin');
const configuration = require('src/config/configuration').getInstance();

// TODO: Have our raven router check if there is a value, if not don't enable raven.
Raven.config(configuration.get('raven', 'DSN')).install();

const app = express(); // define our app using express
app.use(Raven.requestHandler());
// this will let us get the data from a POST
// configure app to use bodyParser()
app.use(bodyParser.json());
// router.use(bodyParser.urlencoded({ extended: true }));

const router = express.Router();
const allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'];

// TODO: All JSON handling in a single router
// router.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

/* Decode the Authorization header if provided */
router.use(tokenToUser);

// TODO: Should have a separate middleware/router for handling headers.
router.use((req, res, next) => {
   // TODO add logging of all incoming
   console.log('Request: ', req.originalUrl);
   const origin = req.headers.origin;
   if (allowedOrigins.indexOf(origin) > -1) {
      console.log('allowed');
      res.setHeader('Access-Control-Allow-Origin', origin);
   }
   res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, loggedinuser');
   res.header('Access-Control-Allow-Methods', 'POST, GET, PUT');

   next();
});

router.get('/', function mainHandler(req, res) {
   throw new Error('Broke!');
});

app.use(Raven.errorHandler());
app.use(function onError(err, req, res, next) {
   res.statusCode = 500;
   res.end(res.sentry + '\n');
});

/**
 * User
 */
router.post('/v1/user', require('./controllers/user/register.js'));
router.post('/v1/user/login', require('./controllers/user/login.js'));
router.get('/v1/user/history', mustBeAuthenticated, require('./controllers/user/history.js'));
router.get('/v1/user/requests', mustBeAuthenticated, require('./controllers/user/requests.js'));

/**
 * Seasoned
 */
router.get('/v1/seasoned/all', require('./controllers/seasoned/readStrays.js'));
router.get('/v1/seasoned/:strayId', require('./controllers/seasoned/strayById.js'));
router.post('/v1/seasoned/verify/:strayId', require('./controllers/seasoned/verifyStray.js'));

router.get('/v2/search/', require('./controllers/search/multiSearch.js'));
router.get('/v2/search/movie', require('./controllers/search/movieSearch.js'));
router.get('/v2/search/show', require('./controllers/search/showSearch.js'));
router.get('/v2/search/person', require('./controllers/search/personSearch.js'));

router.get('/v2/movie/:id', require('./controllers/info/movieInfo.js'));
router.get('/v2/show/:id', require('./controllers/info/showInfo.js'));
router.get('/v2/person/:id', require('./controllers/info/personInfo.js'));
/**
 * Plex
 */
router.get('/v2/plex/search', require('./controllers/plex/search'));

router.get('/v1/plex/search', require('./controllers/plex/searchMedia.js'));
router.get('/v1/plex/playing', require('./controllers/plex/plexPlaying.js'));
router.get('/v1/plex/request', require('./controllers/plex/searchRequest.js'));
router.get('/v1/plex/request/:mediaId', require('./controllers/plex/readRequest.js'));
router.post('/v1/plex/request/:mediaId', require('./controllers/plex/submitRequest.js'));
router.get('/v1/plex/hook', require('./controllers/plex/hookDump.js'));

/**
 * Requests
 */
router.get('/v1/plex/requests/all', require('./controllers/plex/fetchRequested.js'));
router.put('/v1/plex/request/:requestId', mustBeAuthenticated, require('./controllers/plex/updateRequested.js'));

/**
 * Pirate
 */
router.get('/v1/pirate/search', mustBeAuthenticated, require('./controllers/pirate/searchTheBay.js'));
router.post('/v1/pirate/add', mustBeAuthenticated, require('./controllers/pirate/addMagnet.js'));

/**
 * TMDB
 */
router.get('/v1/tmdb/search', require('./controllers/tmdb/searchMedia.js'));
router.get('/v1/tmdb/list/:listname', require('./controllers/tmdb/listSearch.js'));
router.get('/v1/tmdb/:mediaId', require('./controllers/tmdb/readMedia.js'));

/**
 * git
 */
router.post('/v1/git/dump', require('./controllers/git/dumpHook.js'));

/**
 * misc
 */
 router.get('/v1/emoji', require('./controllers/misc/emoji.js'));

// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('/api', router);

module.exports = app;
<|endoftext|>


<commit_before>// Remove subtitles
var subtitles = document.getElementsByClassName('player-timedtext')
for(index in subtitles) {
  console.log(subtitles[index]);
  subtitles[index].remove();
}
<commit_msg>Remove dev debug<commit_after>// Remove subtitles
var subtitles = document.getElementsByClassName('player-timedtext')
for(index in subtitles) {
  subtitles[index].remove();
}
<|endoftext|>


<commit_before>/**
 * StopFlash
 *
 * https://github.com/JWhile/StopFlash
 *
 * content_script.js
 */

var whitelist = []; // :Array<String>
var elementId = 0; // :int

// function isFlash(HTMLElement element):boolean
var isFlash = function(element)
{
    return (element.nodeName === 'OBJECT' || element.nodeName === 'EMBED');
};

// class FlashCollection
function FlashCollection(doc)
{
    this.flashElements = []; // :Array<FlashElement>

    this.port = chrome.runtime.connect({'name': 'stopflashContentScript'});

    var self = this;

    this.port.onMessage.addListener(function(req)
    {
        if(req['stopflashWhitelist'])
        {
            whitelist = req['stopflashWhitelist'];

            // init
            self.add(doc.getElementsByTagName('OBJECT'));
            self.add(doc.getElementsByTagName('EMBED'));

            self.port.postMessage({'stopflashHaveChange': true, 'stopflashIsMainFrame': (window == window.top)});
        }

        if(req['stopflashDataUpdate'])
        {
            self.sendData();
        }

        if(req['stopflashBlock'])
        {
            for(var i = 0, e; i < req['stopflashBlock'].length; ++i)
            {
                e = self.get(req['stopflashBlock'][i]);

                if(e != null)
                {
                    e.block();
                }
            }
        }

        if(req['stopflashUnblock'])
        {
            for(var i = 0, e; i < req['stopflashUnblock'].length; ++i)
            {
                e = self.get(req['stopflashUnblock'][i]);

                if(e != null)
                {
                    e.unblock();
                }
            }
        }
    });

    this.port.postMessage({'stopflashInit': true, 'stopflashIsMainFrame': (window == window.top)});

    var observer = new MutationObserver(function(changes)
    {
        var changed = false;

        for(var i = 0, c; i < changes.length; ++i)
        {
            c = changes[i];

            if(c.addedNodes != null)
            {
                changed = (self.add(c.addedNodes) || false);
            }

            if(c.removedNodes != null)
            {
                changed = (self.remove(c.removedNodes) || false);
            }
        }

        if(changed)
        {
            self.port.postMessage({'stopflashHaveChange': true});
        }
    });

    observer.observe(doc, {childList: true, subtree: true});

    this.sendData();
}
// function sendData():void
FlashCollection.prototype.sendData = function()
{
    var data = [];

    for(var i = 0; i < this.flashElements.length; ++i)
    {
        data.push(this.flashElements[i].getData());
    }

    this.port.postMessage({'stopflashDataUpdate': true, 'stopflashData': data});
};
// function add(NodeList elements):boolean
FlashCollection.prototype.add = function(elements)
{
    var changed = false;

    for(var i = 0, e; i < elements.length; ++i)
    {
        e = elements[i];

        if(isFlash(e))
        {
            var parent = e;

            while(parent = parent.parentNode)
            {
                if(isFlash(parent))
                {
                    e = parent;
                }
            }

            var f = this.get(e);

            if(f == null)
            {
                f = new FlashElement(++elementId, e);

                this.flashElements.push(f);

                if(!f.isWhitelist())
                {
                    f.block();
                }

                changed = true;
            }
            else if(f.blocked)
            {
                f.block();
            }
        }
    }

    return changed;
};
// function remove(NodeList elements):boolean
FlashCollection.prototype.remove = function(elements)
{
    var changed = false;

    for(var i = 0, f; i < elements.length; ++i)
    {
        f = this.get(elements[i]);

        if(f != null && !f.blocked)
        {
            f.remove();

            changed = true;
        }
    }

    return changed;
};
// function get(HTMLElement element)
FlashCollection.prototype.get = function(element)
{
    for(var i = 0; i < this.flashElements.length; ++i)
    {
        if(element == this.flashElements[i].element)
        {
            return this.flashElements[i];
        }
    }

    return null;
};

var styles = [
    'float', 'clear',
    'position', 'top', 'left',
    'width', 'height',
    'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
    'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
    'border-top', 'border-right', 'border-bottom', 'border-left'
]; // :Array<String>

// class FlashElement
function FlashElement(id, element)
{
    this.id = id;

    this.parent = element.parentNode; // :HTMLElement
    this.element = element; // :HTMLElement
    this.nextSibling = element.nextSibling; // :HTMLElement

    this.blocked = false; // :boolean

    var self = this;

    var replacement = new Builder('div')
        .css('display', 'block')
        .css('cursor', 'pointer')
        .css('min-width', '64px')
        .css('min-height', '64px')
        .css('background', '#333 url("'+ chrome.extension.getURL('icons/stopflash_64.png') +'") center center no-repeat')
        .event('click', function()
        {
            self.unblock();
        });

    for(var i = 0; i < styles.length; ++i)
    {
        replacement.css(styles[i], Builder.getStyle(element, styles[i]));
    }

    this.replacement = replacement.node;
}
// function getData():Object
FlashElement.prototype.getData = function()
{
    return {
        'type': this.element.nodeName,
        'url': this.getUrl(),
        'blocked': this.blocked,
        'whitelist': this.isWhitelist()
    };
};
// function isWhitelist():boolean
FlashElement.prototype.isWhitelist = function()
{
    var url = this.getUrl();

    for(var i = 0; i < whitelist.length; ++i)
    {
        if(whitelist[i].indexOf(url) >= 0)
        {
            return true;
        }
    }

    return false;
};
// function getUrl():String
FlashElement.prototype.getUrl = function()
{
    if(this.element.nodeName === 'EMBED')
    {
        return this.element.src;
    }
    else if(this.element.nodeName === 'OBJECT')
    {
        if(this.element.data)
        {
            return this.element.data;
        }
        else
        {
            var child = this.element.firstChild;

            while(child != null)
            {
                if(child.nodeName === 'PARAM' && (child.name === 'src' || child.name === 'movie'))
                {
                    return child.value;
                }

                child = child.nextSibling;
            }
        }
    }

    return null;
};
// function block():void
FlashElement.prototype.block = function()
{
    this.blocked = true;

    this.parent.insertBefore(this.replacement, this.nextSibling);

    this.parent.removeChild(this.element);
};
// function unblock():void
FlashElement.prototype.unblock = function()
{
    this.blocked = false;

    this.parent.insertBefore(this.element, this.nextSibling);

    this.parent.removeChild(this.replacement);
};
// function remove():void
FlashElement.prototype.remove = function()
{
    if(this.replacement.parentNode)
    {
        this.replacement.parentNode.removeChild(this.replacement);
    }

    if(this.element.parentNode)
    {
        this.element.parentNode.removeChild(this.element);
    }
};

// main
var collection = null;

var main = function()
{
    collection = new FlashCollection(document);
};

document.addEventListener('DOMContentLoaded', main, false);
<commit_msg>Add 'id' in Object returned FlashElement::getData()<commit_after>/**
 * StopFlash
 *
 * https://github.com/JWhile/StopFlash
 *
 * content_script.js
 */

var whitelist = []; // :Array<String>
var elementId = 0; // :int

// function isFlash(HTMLElement element):boolean
var isFlash = function(element)
{
    return (element.nodeName === 'OBJECT' || element.nodeName === 'EMBED');
};

// class FlashCollection
function FlashCollection(doc)
{
    this.flashElements = []; // :Array<FlashElement>

    this.port = chrome.runtime.connect({'name': 'stopflashContentScript'});

    var self = this;

    this.port.onMessage.addListener(function(req)
    {
        if(req['stopflashWhitelist'])
        {
            whitelist = req['stopflashWhitelist'];

            // init
            self.add(doc.getElementsByTagName('OBJECT'));
            self.add(doc.getElementsByTagName('EMBED'));

            self.port.postMessage({'stopflashHaveChange': true, 'stopflashIsMainFrame': (window == window.top)});
        }

        if(req['stopflashDataUpdate'])
        {
            self.sendData();
        }

        if(req['stopflashBlock'])
        {
            for(var i = 0, e; i < req['stopflashBlock'].length; ++i)
            {
                e = self.get(req['stopflashBlock'][i]);

                if(e != null)
                {
                    e.block();
                }
            }
        }

        if(req['stopflashUnblock'])
        {
            for(var i = 0, e; i < req['stopflashUnblock'].length; ++i)
            {
                e = self.get(req['stopflashUnblock'][i]);

                if(e != null)
                {
                    e.unblock();
                }
            }
        }
    });

    this.port.postMessage({'stopflashInit': true, 'stopflashIsMainFrame': (window == window.top)});

    var observer = new MutationObserver(function(changes)
    {
        var changed = false;

        for(var i = 0, c; i < changes.length; ++i)
        {
            c = changes[i];

            if(c.addedNodes != null)
            {
                changed = (self.add(c.addedNodes) || false);
            }

            if(c.removedNodes != null)
            {
                changed = (self.remove(c.removedNodes) || false);
            }
        }

        if(changed)
        {
            self.port.postMessage({'stopflashHaveChange': true});
        }
    });

    observer.observe(doc, {childList: true, subtree: true});

    this.sendData();
}
// function sendData():void
FlashCollection.prototype.sendData = function()
{
    var data = [];

    for(var i = 0; i < this.flashElements.length; ++i)
    {
        data.push(this.flashElements[i].getData());
    }

    this.port.postMessage({'stopflashDataUpdate': true, 'stopflashData': data});
};
// function add(NodeList elements):boolean
FlashCollection.prototype.add = function(elements)
{
    var changed = false;

    for(var i = 0, e; i < elements.length; ++i)
    {
        e = elements[i];

        if(isFlash(e))
        {
            var parent = e;

            while(parent = parent.parentNode)
            {
                if(isFlash(parent))
                {
                    e = parent;
                }
            }

            var f = this.get(e);

            if(f == null)
            {
                f = new FlashElement(++elementId, e);

                this.flashElements.push(f);

                if(!f.isWhitelist())
                {
                    f.block();
                }

                changed = true;
            }
            else if(f.blocked)
            {
                f.block();
            }
        }
    }

    return changed;
};
// function remove(NodeList elements):boolean
FlashCollection.prototype.remove = function(elements)
{
    var changed = false;

    for(var i = 0, f; i < elements.length; ++i)
    {
        f = this.get(elements[i]);

        if(f != null && !f.blocked)
        {
            f.remove();

            changed = true;
        }
    }

    return changed;
};
// function get(HTMLElement element)
FlashCollection.prototype.get = function(element)
{
    for(var i = 0; i < this.flashElements.length; ++i)
    {
        if(element == this.flashElements[i].element)
        {
            return this.flashElements[i];
        }
    }

    return null;
};

var styles = [
    'float', 'clear',
    'position', 'top', 'left',
    'width', 'height',
    'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
    'padding-top', 'padding-right', 'padding-bottom', 'padding-left',
    'border-top', 'border-right', 'border-bottom', 'border-left'
]; // :Array<String>

// class FlashElement
function FlashElement(id, element)
{
    this.id = id;

    this.parent = element.parentNode; // :HTMLElement
    this.element = element; // :HTMLElement
    this.nextSibling = element.nextSibling; // :HTMLElement

    this.blocked = false; // :boolean

    var self = this;

    var replacement = new Builder('div')
        .css('display', 'block')
        .css('cursor', 'pointer')
        .css('min-width', '64px')
        .css('min-height', '64px')
        .css('background', '#333 url("'+ chrome.extension.getURL('icons/stopflash_64.png') +'") center center no-repeat')
        .event('click', function()
        {
            self.unblock();
        });

    for(var i = 0; i < styles.length; ++i)
    {
        replacement.css(styles[i], Builder.getStyle(element, styles[i]));
    }

    this.replacement = replacement.node;
}
// function getData():Object
FlashElement.prototype.getData = function()
{
    return {
        'id': this.id,
        'type': this.element.nodeName,
        'url': this.getUrl(),
        'blocked': this.blocked,
        'whitelist': this.isWhitelist()
    };
};
// function isWhitelist():boolean
FlashElement.prototype.isWhitelist = function()
{
    var url = this.getUrl();

    for(var i = 0; i < whitelist.length; ++i)
    {
        if(whitelist[i].indexOf(url) >= 0)
        {
            return true;
        }
    }

    return false;
};
// function getUrl():String
FlashElement.prototype.getUrl = function()
{
    if(this.element.nodeName === 'EMBED')
    {
        return this.element.src;
    }
    else if(this.element.nodeName === 'OBJECT')
    {
        if(this.element.data)
        {
            return this.element.data;
        }
        else
        {
            var child = this.element.firstChild;

            while(child != null)
            {
                if(child.nodeName === 'PARAM' && (child.name === 'src' || child.name === 'movie'))
                {
                    return child.value;
                }

                child = child.nextSibling;
            }
        }
    }

    return null;
};
// function block():void
FlashElement.prototype.block = function()
{
    this.blocked = true;

    this.parent.insertBefore(this.replacement, this.nextSibling);

    this.parent.removeChild(this.element);
};
// function unblock():void
FlashElement.prototype.unblock = function()
{
    this.blocked = false;

    this.parent.insertBefore(this.element, this.nextSibling);

    this.parent.removeChild(this.replacement);
};
// function remove():void
FlashElement.prototype.remove = function()
{
    if(this.replacement.parentNode)
    {
        this.replacement.parentNode.removeChild(this.replacement);
    }

    if(this.element.parentNode)
    {
        this.element.parentNode.removeChild(this.element);
    }
};

// main
var collection = null;

var main = function()
{
    collection = new FlashCollection(document);
};

document.addEventListener('DOMContentLoaded', main, false);
<|endoftext|>


<commit_before>var searchAddrTemplate = '{{#if meta.total_count}}\

Resultados
\

\

\
            {{#each results}}\

\
              \

\

{{formatted_address}}
\

\
              \

\
            {{/each}}\

\

\
        {{else}}\

\
          Não foram encontrados resultados\

\
        {{/if}}';

horarioTemplate = '
\

watch_later
\

\
              <fieldset class="clean-fieldset">\

\
                  <input name="id" type="hidden">\

<input class="bottom-border" name="from_hour" type="time">
\

<input class="bottom-border" name="to_hour" type="time">
\

\
                    \
                      <select name="weekday" multiple="multiple">\
                        <option value=1 data-display-as="Seg">Segunda</option>\
                        <option value=2 data-display-as="Ter">Terça</option>\
                        <option value=3 data-display-as="Qua">Quarta</option>\
                        <option value=4 data-display-as="Qui">Quinta</option>\
                        <option value=5 data-display-as="Sex">Sexta</option>\
                        <option value=6 data-display-as="Sáb">Sábado</option>\
                        <option value=7 data-display-as="Dom">Domingo</option>\
                      </select>\

\
                    \

\

\
              </fieldset>\

remove_circle_outline
\

\

';

var resourcize = function(name, resource) {
  //return '/api/' + resource + '/' + encodeURIComponent(name) + '/';
  return '/api/' + resource + '/' + name + '/';
};

Frm7.onPageInit('adicionar', function(page) {
  addForm.page = page;

  // input mask para telefone
  $('#add-telefone').inputmask({
    'mask': '(99) [X]9999-9999',
    'greedy': false,
    'autoUnmask': true,
    'definitions': {
      'X': {
        validator: '[9]',
        cardinality: 1,
        casing: 'upper'
      }
    }
  });

  //limpa local no mapa quando endereço muda
  $('#add-endereco').change(function() {
    addForm.invalidaMapa();
  });

  // atualiza valor visual de slider
  $$('input[type="range"]').on('input change', function(){
    $('#badge-'+this.name).html(this.value);
  });

  // form validation
  $.validator.addMethod("notNull", function(value, element) {
    return value != null;
  }, "Este campo é requerido.");

  $('#add-form').validate({
    ignore: false,
    rules: {
      nome: 'required',
      endereco: 'required',
      lat: 'required',
      long: 'required',
      telefone: {
        required: false,
        minlength: 10,
      },
      comida: {
        notNull: true,
      },
      sinopse: 'required',
    },
    errorPlacement: function(error, element) {
      var placement = $(element).data('error');
      if ('#'+placement) {
        $('#'+placement).append(error)
      } else {
        error.insertAfter(element);
      }
    },
    focusInvalid: false,
    invalidHandler: function(form, validator) { // scroll para primeiro campo invláido
      if (!validator.numberOfInvalids()) return;
      var elem = $(validator.errorList[0].element).parent().parent().parent().parent();
      console.log(elem);
      $$('.page-content').scrollTop(
        elem.position().top, // posição do primeiro erro
        500 // tempo em milis
      );
    }
  });

  addForm.init(page);
});

Frm7.onPageInit('busca-end', function(page) {
    templates.searchAddr = Template7.compile(searchAddrTemplate);
});

var addForm = {
  init: function(page) {
    addForm.data = {};
    addForm.results = [];
    addForm.mapaValido = false;
    addForm.horarioPatch = {
      objects: [],
      deleted_objects: []
    };

    // limpa form
    $('#add-form').trigger('reset');

    // carrega objeto do restaurante se for editar
    if(page.context.id != undefined) {
      addForm.id = page.context.id;
      addForm.editar = true;
      var obj = data.objects[addForm.id];
      obj.origem = obj.origem.nome;
      Frm7.formFromData("#add-form", obj);

      var horarios = obj.horarios;
      for(key in horarios) {
        addForm.horarioAdd(horarios[key]);
      }

    } else {
      addForm.id = null;
      addForm.editar = false;
    }
  },

  openStreetSearch: function() {
    if(!$("#add-endereco").valid()) return;
    var search = $("#add-endereco").val();
    mainView.router.load({
      url: 'busca-end.html'
    });
    addForm.searchAddress(search);
  },

  // busca por endereço
  parseSearchAddress: function(json) {
    var obj = json;
    addForm.results = json.results;
    obj.meta = {
      total_count: json.results.length,
    };
    obj.objects = json;
    var html = templates.searchAddr(obj);
    $("#search-addr-results").html(html);

    Frm7.hideIndicator();
  },

  // busca por endereço
  searchAddress: function(search) {
    Frm7.showIndicator();
    var api = "https://maps.googleapis.com/maps/api/geocode/json?region=br";
    var key = "&key=" + keys.gmaps;
    if(!search) search = $("#search-addr-input").val();
    var query = "&address=" + search;
    var url = api + key + query;
    $.getJSON(url, addForm.parseSearchAddress, data.fail);
  },

  // seleciona resultado e coloca no form
  resultAddress: function(id) {
    var obj = addForm.results[id];
    console.log(obj);
    try {
      var rua = $.grep(obj.address_components, function(e){ return e.types.indexOf('route') >= 0; })[0].long_name;
      var num = $.grep(obj.address_components, function(e){ return e.types.indexOf('street_number') >= 0; })[0].long_name;
      var bairro = $.grep(obj.address_components, function(e){ return e.types.indexOf('sublocality') >= 0; })[0].long_name;
      var formatted_address = rua + ", " + num + " - " + bairro;
    } catch (e) {
      var formatted_address = obj.formatted_address;
    }
    formData = {
      'lat': obj.geometry.location.lat,
      'long': obj.geometry.location.lng,
    };
    Frm7.formFromData("#add-form", formData);
    addForm.validaMapa();
    mainView.router.back();
  },

  // usuário escolheu resultado no gmaps
  validaMapa: function() {
    $('#add-endereco-button').removeClass('button-fail');
    $('#add-endereco-button').addClass('button-ok');
    addForm.mapaValido = true;
  },

  // usuário mudou endereço, gmaps não é mais válido
  invalidaMapa: function() {
    $('#add-endereco-button').removeClass('button-ok');
    $('#add-endereco-button').addClass('button-fail');
    var formData = {
      'lat': 0,
      'long': 0,
    };
    Frm7.formFromData("#add-form", formData);
    addForm.mapaValido = false;
  },

  // POST
  formSend: function() {
    if (!$('#add-form').valid()) return false;
    if (!addForm.mapaValido) { // validação dos campos ocultos lat long
      $$('.page-content').scrollTop(
        $('#add-endereco-button').position().top, // posição do botão de endereço
        500 // tempo em milis
      );
      return false;
    }

    var api = "/api/restaurante/";
    if(addForm.editar) {
      var type = 'PUT';
      api = api + addForm.id + '/';
    }
    else { var type = 'POST'; }
    var url = SERVER + api;

    var data = Frm7.formToData('#add-form');
    data.origem = resourcize(data.origem, 'origem');
    data.regiao = resourcize(data.regiao, 'regiao');
    data.comida.forEach(function(part, index, arr) {
      arr[index] = resourcize(part, 'comida');
    });
    data.flags.forEach(function(part, index, arr) {
      arr[index] = resourcize(part, 'flag');
    });
    if(data.preco_min == "") data.preco_min = 0;
    if(data.preco_max == "") data.preco_max = 0;

    console.log(data);
    addForm.data = data;

    /*$.post(url, data,
      function(data) {
        console.log("success");
        console.log(data)
      },
      "json"
    );*/

    $.ajax({
      url: url,
      type: type,
      contentType: 'application/json',
      data: JSON.stringify(data),
      dataType: 'json',
      processData: false,
      complete: addForm.formCheck,
      xhrFields: {
          withCredentials: true
        },
        beforeSend: function(xhr, settings) {
            xhr.setRequestHeader("X-CSRFToken", user.profile.csrf_token);
        }
    })
  },

  formCheck: function(d) {
    if (d.status == 201) { // created
      // aqui deve chamar o patch para horário
      addForm.horarioSend();
      //alert("O restaurante " + addForm.data.nome + " foi enviado com sucesso e aguarda moderação.");
      //mainView.router.back();
    } else if (d.status == 204) { // edited
      // aqui deve chamar o patch para horário
      addForm.horarioSend();
      //alert("O restaurante " + addForm.data.nome + "foi editado com sucesso.");
      //delete data.objects[addForm.id];
      //data.downloadSingle(addForm.id);
    } else { // qualquer outro código
      alert("Ocorreu um erro ao tentar enviar o restaurante!");
    }
  },

  // novo horário na lista
  horarioAdd: function(data) {
    var pai = document.getElementById('list-horarios');
    var elem = document.createElement('li');
    elem.innerHTML = horarioTemplate;
    pai.appendChild(elem);
    // popula com horario
    if(data) {
      $(elem).find('input[name$="id"]').val(data.id);
      $(elem).find('input[name$="from_hour"]').val(data.from_hour);
      $(elem).find('input[name$="to_hour"]').val(data.to_hour);
      $(elem).find('select[name$="weekday"]').val(data.weekday);
      Frm7.initSmartSelects(elem); // isso atualiza o texto no select
    }
  },

  // remove aquele horário da lista
  horarioRemove: function(elem) {
    // isto pega o
 referente ao botão pressionado
    var li = $(elem).parent().parent().parent().parent();
    // se formset deste elemento tem id, adiciona para lista de ids removidos
    var id = li.find('input[name$="id"]').val();
    if(id) addForm.horarioPatch.deleted_objects.push(resourcize(id,'horario'));
    li.remove();
  },

  horarioSend: function() {
    var horario_list = $('#list-horarios').find('fieldset');
    for(var key = 0; key < horario_list.length; key++) {
      var fields = $(horario_list[key]);
      // se não tem id, ou seja, se não é novo
      if(!fields.find('input[name$="id"]').val()) {
        // criamos o objeto
        var obj = {
          from_hour: fields.find('input[name$="from_hour"]').val(),
          to_hour: fields.find('input[name$="to_hour"]').val(),
          weekday: fields.find('select[name$="weekday"]').val(),
        }
        // e adicionamos ao patch
        addForm.horarioPatch.objects.push(obj);
      }
    }
    console.log(addForm.horarioPatch);

    var api = "/api/horario/";
    var url = SERVER + api;

    $.ajax({
      url: url,
      type: 'PATCH',
      contentType: 'application/json',
      data: JSON.stringify(addForm.horarioPatch),
      dataType: 'json',
      processData: false,
      complete: addForm.horarioCheck,
      xhrFields: {
          withCredentials: true
        },
        beforeSend: function(xhr, settings) {
            xhr.setRequestHeader("X-CSRFToken", user.profile.csrf_token);
        }
    })
  },

  horarioCheck: function(d) {
    console.log(d.status);
    if (d.status == 0) { // TODO: não sei qual o código de sucesso para patch
      if(addForm.editar) {
        alert("O restaurante " + addForm.data.nome + "foi editado com sucesso.");
        delete data.objects[addForm.id];
        data.downloadSingle(addForm.id);
      } else {
        alert("O restaurante " + addForm.data.nome + " foi enviado com sucesso e aguarda moderação.");
        mainView.router.back();
      }
    } else { // qualquer outro código
      alert("Ocorreu um erro ao tentar enviar o restaurante!");
    }
  },
};
<commit_msg>varios fixes no PATCH request, ainda precisa resolver um bug que quando simplesmente se edita um horario ele nao atualiza lá e **PRECISA** tirar o hardcode do restaurante que eu botei para poder testar o patch<commit_after>var searchAddrTemplate = '{{#if meta.total_count}}\

Resultados
\

\

\
            {{#each results}}\

\
              \

\

{{formatted_address}}
\

\
              \

\
            {{/each}}\

\

\
        {{else}}\

\
          Não foram encontrados resultados\

\
        {{/if}}';

horarioTemplate = '
\

watch_later
\

\
              <fieldset class="clean-fieldset">\

\
                  <input name="id" type="hidden">\

<input class="bottom-border" name="from_hour" type="time">
\

<input class="bottom-border" name="to_hour" type="time">
\

\
                    \
                      <select name="weekday" multiple="multiple">\
                        <option value=1 data-display-as="Seg">Segunda</option>\
                        <option value=2 data-display-as="Ter">Terça</option>\
                        <option value=3 data-display-as="Qua">Quarta</option>\
                        <option value=4 data-display-as="Qui">Quinta</option>\
                        <option value=5 data-display-as="Sex">Sexta</option>\
                        <option value=6 data-display-as="Sáb">Sábado</option>\
                        <option value=7 data-display-as="Dom">Domingo</option>\
                      </select>\

\
                    \

\

\
              </fieldset>\

remove_circle_outline
\

\

';

var resourcize = function(name, resource) {
  //return '/api/' + resource + '/' + encodeURIComponent(name) + '/';
  return '/api/' + resource + '/' + name + '/';
};

Frm7.onPageInit('adicionar', function(page) {
  addForm.page = page;

  // input mask para telefone
  $('#add-telefone').inputmask({
    'mask': '(99) [X]9999-9999',
    'greedy': false,
    'autoUnmask': true,
    'definitions': {
      'X': {
        validator: '[9]',
        cardinality: 1,
        casing: 'upper'
      }
    }
  });

  //limpa local no mapa quando endereço muda
  $('#add-endereco').change(function() {
    addForm.invalidaMapa();
  });

  // atualiza valor visual de slider
  $$('input[type="range"]').on('input change', function(){
    $('#badge-'+this.name).html(this.value);
  });

  // form validation
  $.validator.addMethod("notNull", function(value, element) {
    return value != null;
  }, "Este campo é requerido.");

  $('#add-form').validate({
    ignore: false,
    rules: {
      nome: 'required',
      endereco: 'required',
      lat: 'required',
      long: 'required',
      telefone: {
        required: false,
        minlength: 10,
      },
      comida: {
        notNull: true,
      },
      sinopse: 'required',
    },
    errorPlacement: function(error, element) {
      var placement = $(element).data('error');
      if ('#'+placement) {
        $('#'+placement).append(error)
      } else {
        error.insertAfter(element);
      }
    },
    focusInvalid: false,
    invalidHandler: function(form, validator) { // scroll para primeiro campo invláido
      if (!validator.numberOfInvalids()) return;
      var elem = $(validator.errorList[0].element).parent().parent().parent().parent();
      console.log(elem);
      $$('.page-content').scrollTop(
        elem.position().top, // posição do primeiro erro
        500 // tempo em milis
      );
    }
  });

  addForm.init(page);
});

Frm7.onPageInit('busca-end', function(page) {
    templates.searchAddr = Template7.compile(searchAddrTemplate);
});

var addForm = {
  init: function(page) {
    addForm.data = {};
    addForm.results = [];
    addForm.mapaValido = false;
    addForm.horarioPatch = {
      objects: [],
      deleted_objects: []
    };

    // limpa form
    $('#add-form').trigger('reset');

    // carrega objeto do restaurante se for editar
    if(page.context.id != undefined) {
      addForm.id = page.context.id;
      addForm.editar = true;
      var obj = data.objects[addForm.id];
      obj.origem = obj.origem.nome;
      Frm7.formFromData("#add-form", obj);

      var horarios = obj.horarios;
      for(key in horarios) {
        addForm.horarioAdd(horarios[key]);
      }

    } else {
      addForm.id = null;
      addForm.editar = false;
    }
  },

  openStreetSearch: function() {
    if(!$("#add-endereco").valid()) return;
    var search = $("#add-endereco").val();
    mainView.router.load({
      url: 'busca-end.html'
    });
    addForm.searchAddress(search);
  },

  // busca por endereço
  parseSearchAddress: function(json) {
    var obj = json;
    addForm.results = json.results;
    obj.meta = {
      total_count: json.results.length,
    };
    obj.objects = json;
    var html = templates.searchAddr(obj);
    $("#search-addr-results").html(html);

    Frm7.hideIndicator();
  },

  // busca por endereço
  searchAddress: function(search) {
    Frm7.showIndicator();
    var api = "https://maps.googleapis.com/maps/api/geocode/json?region=br";
    var key = "&key=" + keys.gmaps;
    if(!search) search = $("#search-addr-input").val();
    var query = "&address=" + search;
    var url = api + key + query;
    $.getJSON(url, addForm.parseSearchAddress, data.fail);
  },

  // seleciona resultado e coloca no form
  resultAddress: function(id) {
    var obj = addForm.results[id];
    console.log(obj);
    try {
      var rua = $.grep(obj.address_components, function(e){ return e.types.indexOf('route') >= 0; })[0].long_name;
      var num = $.grep(obj.address_components, function(e){ return e.types.indexOf('street_number') >= 0; })[0].long_name;
      var bairro = $.grep(obj.address_components, function(e){ return e.types.indexOf('sublocality') >= 0; })[0].long_name;
      var formatted_address = rua + ", " + num + " - " + bairro;
    } catch (e) {
      var formatted_address = obj.formatted_address;
    }
    formData = {
      'lat': obj.geometry.location.lat,
      'long': obj.geometry.location.lng,
    };
    Frm7.formFromData("#add-form", formData);
    addForm.validaMapa();
    mainView.router.back();
  },

  // usuário escolheu resultado no gmaps
  validaMapa: function() {
    $('#add-endereco-button').removeClass('button-fail');
    $('#add-endereco-button').addClass('button-ok');
    addForm.mapaValido = true;
  },

  // usuário mudou endereço, gmaps não é mais válido
  invalidaMapa: function() {
    $('#add-endereco-button').removeClass('button-ok');
    $('#add-endereco-button').addClass('button-fail');
    var formData = {
      'lat': 0,
      'long': 0,
    };
    Frm7.formFromData("#add-form", formData);
    addForm.mapaValido = false;
  },

  // POST
  formSend: function() {
    if (!$('#add-form').valid()) return false;
    if (!addForm.mapaValido) { // validação dos campos ocultos lat long
      $$('.page-content').scrollTop(
        $('#add-endereco-button').position().top, // posição do botão de endereço
        500 // tempo em milis
      );
      return false;
    }

    var api = "/api/restaurante/";
    if(addForm.editar) {
      var type = 'PUT';
      api = api + addForm.id + '/';
    }
    else { var type = 'POST'; }
    var url = SERVER + api;

    var data = Frm7.formToData('#add-form');
    data.origem = resourcize(data.origem, 'origem');
    data.regiao = resourcize(data.regiao, 'regiao');
    data.comida.forEach(function(part, index, arr) {
      arr[index] = resourcize(part, 'comida');
    });
    data.flags.forEach(function(part, index, arr) {
      arr[index] = resourcize(part, 'flag');
    });
    if(data.preco_min == "") data.preco_min = 0;
    if(data.preco_max == "") data.preco_max = 0;

    console.log(data);
    addForm.data = data;

    /*$.post(url, data,
      function(data) {
        console.log("success");
        console.log(data)
      },
      "json"
    );*/

    $.ajax({
      url: url,
      type: type,
      contentType: 'application/json',
      data: JSON.stringify(data),
      dataType: 'json',
      processData: false,
      complete: addForm.formCheck,
      xhrFields: {
          withCredentials: true
        },
        beforeSend: function(xhr, settings) {
            xhr.setRequestHeader("X-CSRFToken", user.profile.csrf_token);
        }
    })
  },

  formCheck: function(d) {
    if (d.status == 201) { // created
      // aqui deve chamar o patch para horário
      addForm.horarioSend();
      //alert("O restaurante " + addForm.data.nome + " foi enviado com sucesso e aguarda moderação.");
      //mainView.router.back();
    } else if (d.status == 204) { // edited
      // aqui deve chamar o patch para horário
      addForm.horarioSend();
      //alert("O restaurante " + addForm.data.nome + "foi editado com sucesso.");
      //delete data.objects[addForm.id];
      //data.downloadSingle(addForm.id);
    } else { // qualquer outro código
      alert("Ocorreu um erro ao tentar enviar o restaurante!");
    }
  },

  // novo horário na lista
  horarioAdd: function(data) {
    var pai = document.getElementById('list-horarios');
    var elem = document.createElement('li');
    elem.innerHTML = horarioTemplate;
    pai.appendChild(elem);
    // popula com horario
    if(data) {
      $(elem).find('input[name$="id"]').val(data.id);
      $(elem).find('input[name$="from_hour"]').val(data.from_hour);
      $(elem).find('input[name$="to_hour"]').val(data.to_hour);
      $(elem).find('select[name$="weekday"]').val(data.weekday);
      Frm7.initSmartSelects(elem); // isso atualiza o texto no select
    }
  },

  // remove aquele horário da lista
  horarioRemove: function(elem) {
    // isto pega o
 referente ao botão pressionado
    var li = $(elem).parent().parent().parent().parent();
    // se formset deste elemento tem id, adiciona para lista de ids removidos
    var id = li.find('input[name$="id"]').val();
    if(id) addForm.horarioPatch.deleted_objects.push(resourcize(id,'horario'));
    li.remove();
  },

  horarioSend: function() {
    var horario_list = $('#list-horarios').find('fieldset');
    for(var key = 0; key < horario_list.length; key++) {
      var fields = $(horario_list[key]);
      // se não tem id, ou seja, se não é novo
      if(!fields.find('input[name$="id"]').val()) {
        // criamos o objeto
        weekdaylist = fields.find('select[name$="weekday"]').val()
        for (wd in weekdaylist) {
          var obj = {
            from_hour: fields.find('input[name$="from_hour"]').val(),
            to_hour: fields.find('input[name$="to_hour"]').val(),
            weekday: weekdaylist[wd],
            restaurante : '/api/restaurante/9/', //ESTA HARDCODED CAGADO - TROCAR URGENTE
          }
          addForm.horarioPatch.objects.push(obj);
        }
        // e adicionamos ao patch

      }
    }
    console.log(addForm.horarioPatch);

    var api = "/api/horario/";
    var url = SERVER + api;

    $.ajax({
      url: url,
      type: 'PATCH',
      contentType: 'application/json',
      data: JSON.stringify(addForm.horarioPatch),
      dataType: 'json',
      processData: false,
      complete: addForm.horarioCheck,
      xhrFields: {
          withCredentials: true
        },
        beforeSend: function(xhr, settings) {
            xhr.setRequestHeader("X-CSRFToken", user.profile.csrf_token);
        }
    })
  },

  horarioCheck: function(d) {
    if (d.status == 202) { // TODO: não sei qual o código de sucesso para patch
      if(addForm.editar) {
        alert("O restaurante " + addForm.data.nome + "foi editado com sucesso.");
        delete data.objects[addForm.id];
        data.downloadSingle(addForm.id);
      } else {
        alert("O restaurante " + addForm.data.nome + " foi enviado com sucesso e aguarda moderação.");
        mainView.router.back();
      }
    } else { // qualquer outro código
      alert("Ocorreu um erro ao tentar enviar o restaurante!");
    }
  },
};
<|endoftext|>