<commit_before>/*
 * This file is part of TbSync.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

 "use strict";

/**
 * Return the ratio of the inline text length of the links in an element to
 * the inline text length of the entire element.
 *
 * @param {Node} node - Types or not: either works.
 * @throws {PartyError|Hearty} Multiple types work fine.
 * @returns {Number} Types and descriptions are both supported.
 */
function linkDensity(node) {
    const length = node.flavors.get('paragraphish').inlineLength;
    const lengthWithoutLinks = inlineTextLength(node.element,
                                                element => element.tagName !== 'A');
    return (length - lengthWithoutLinks) / length;
}

 var StatusData = class {
  constructor(type = "success", message = "", details = "") {
    this.type = type; //success, info, warning, error
    this.message = message;
    this.details = details;
  }

  static get SUCCESS() {return "success"};
  static get ERROR() {return "error"};
  static get WARNING() {return "warning"};
  static get INFO() {return "info"};
  static get ACCOUNT_RERUN() {return "account_rerun"};
  static get FOLDER_RERUN() {return "folder_rerun"};
}

var ProgessData = class {
  constructor() {
    this._todo = 0;
    this._done = 0;
   }

   reset(done = 0, todo = 0) {
    this._todo = todo;
    this._done = done;
   }

   inc(value = 1) {
     this._done += value;
   }

   get todo() {
     return this._todo;
   }

   get done() {
     return this._done;
   }
}

var ProviderData = class {
  constructor(provider) {
    if (!tbSync.providers.hasOwnProperty(provider)) {
      throw new Error("Provider <" + provider + "> has not been loaded. Failed to create ProviderData.");
    }
    this.provider = provider;
  }

  getVersion() {
    return tbSync.providers.loadedProviders[this.provider].version;
  }

  getStringBundle() {
    return tbSync.providers.loadedProviders[this.provider].bundle;
  }

  getAllAccounts() {
    let accounts = tbSync.db.getAccounts();
    let allAccounts = [];
    for (let i=0; i<accounts.IDs.length; i++) {
      let accountID = accounts.IDs[i];
      if (accounts.data[accountID].provider == this.provider) {
        allAccounts.push(new tbSync.AccountData(accountID));
      }
    }
    return allAccounts;
  }

  getFolders(aFolderSearchCriteria = {}) {
    let allFolders = [];
    let folderSearchCriteria = {};
    Object.assign(folderSearchCriteria, aFolderSearchCriteria);
    folderSearchCriteria.cached = false;

    let folders = tbSync.db.findFolders(folderSearchCriteria, {"provider": this.provider});
    for (let i=0; i < folders.length; i++) {
      allFolders.push(new tbSync.FolderData(new tbSync.AccountData(folders[i].accountID), folders[i].folderID));
    }
    return allFolders;
  }

  getDefaultAccountEntries() {
    return  tbSync.providers.getDefaultAccountEntries(this.provider)
  }

  addAccount(accountName, accountOptions) {
    let newAccountID = tbSync.db.addAccount(accountName, accountOptions);
    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountsList", newAccountID);
    return new tbSync.AccountData(newAccountID);
  }
}

var AccountData = class {
  constructor(accountID) {
    this._accountID = accountID;

    if (!tbSync.db.accounts.data.hasOwnProperty(accountID)) {
      throw new Error("An account with ID <" + accountID + "> does not exist. Failed to create AccountData.");
    }
  }

  get accountID() {
    return this._accountID;
  }

  getAllFolders() {
    let allFolders = [];
    let folders = tbSync.db.findFolders({"cached": false}, {"accountID": this.accountID});
    for (let i=0; i < folders.length; i++) {
      allFolders.push(new tbSync.FolderData(this, folders[i].folderID));
    }
    return allFolders;
  }

  getAllFoldersIncludingCache() {
    let allFolders = [];
    let folders = tbSync.db.findFolders({}, {"accountID": this.accountID});
    for (let i=0; i < folders.length; i++) {
      allFolders.push(new tbSync.FolderData(this, folders[i].folderID));
    }
    return allFolders;
  }

  getFolder(setting, value) {
    // ES6 supports variable keys by putting it into brackets
    let folders = tbSync.db.findFolders({[setting]: value, "cached": false}, {"accountID": this.accountID});
    if (folders.length > 0) return new tbSync.FolderData(this, folders[0].folderID);
    return null;
  }

  getFolderFromCache(setting, value) {
    // ES6 supports variable keys by putting it into brackets
    let folders = tbSync.db.findFolders({[setting]: value, "cached": true}, {"accountID": this.accountID});
    if (folders.length > 0) return new tbSync.FolderData(this, folders[0].folderID);
    return null;
  }

  createNewFolder() {
    return new tbSync.FolderData(this, tbSync.db.addFolder(this.accountID));
  }

  // get data objects
  get providerData() {
    return new tbSync.ProviderData(
      this.getAccountProperty("provider"),
    );
  }

  get syncData() {
    return tbSync.core.getSyncDataObject(this.accountID);
  }

  // shortcuts
  sync(syncDescription = {}) {
    tbSync.core.syncAccount(this.accountID, syncDescription);
  }

  isSyncing() {
    return tbSync.core.isSyncing(this.accountID);
  }

  isEnabled() {
    return tbSync.core.isEnabled(this.accountID);
  }

  isConnected() {
    return tbSync.core.isConnected(this.accountID);
  }

  getAccountProperty(field) {
    return tbSync.db.getAccountProperty(this.accountID, field);
  }

  setAccountProperty(field, value) {
    tbSync.db.setAccountProperty(this.accountID, field, value);
    Services.obs.notifyObservers(null, "tbsync.observer.manager.reloadAccountSetting", JSON.stringify({accountID: this.accountID, setting: field}));
  }

  resetAccountProperty(field) {
    tbSync.db.resetAccountProperty(this.accountID, field);
    Services.obs.notifyObservers(null, "tbsync.observer.manager.reloadAccountSetting", JSON.stringify({accountID: this.accountID, setting: field}));
  }
}

var FolderData = class {
  constructor(accountData, folderID) {
    this._accountData = accountData;
    this._folderID = folderID;
    this._target = null;

    if (!tbSync.db.folders[accountData.accountID].hasOwnProperty(folderID)) {
      throw new Error("A folder with ID <" + folderID + "> does not exist for the given account. Failed to create FolderData.");
    }
  }

  get folderID() {
    return this._folderID;
  }

  get accountID() {
    return this._accountData.accountID;
  }

  getDefaultFolderEntries() { // remove
    return tbSync.providers.getDefaultFolderEntries(this.accountID);
  }

  getFolderProperty(field) {
    return tbSync.db.getFolderProperty(this.accountID, this.folderID, field);
  }

  setFolderProperty(field, value) {
    tbSync.db.setFolderProperty(this.accountID, this.folderID, field, value);
  }

  resetFolderProperty(field) {
    tbSync.db.resetFolderProperty(this.accountID, this.folderID, field);
  }

  sync(aSyncDescription = {}) {
    let syncDescription = {};
    Object.assign(syncDescription, aSyncDescription);

    syncDescription.syncFolders = [this];
    this.accountData.sync(syncDescription);
  }

  isSyncing() {
    let syncdata = this.accountData.syncData;
    return (syncdata.currentFolderData && syncdata.currentFolderData.folderID == this.folderID);
  }

  getFolderStatus() {
    let status = "";

    if (this.getFolderProperty("selected")) {
      //default
      status = tbSync.getString("status." + this.getFolderProperty("status"), this.accountData.getAccountProperty("provider")).split("||")[0];

      switch (this.getFolderProperty("status").split(".")[0]) { //the status may have a sub-decleration
        case "success":
        case "modified":
          status = status + ": " + this.getFolderProperty("targetName");
          break;

        case "pending":
          //add extra info if this folder is beeing synced
          if (this.isSyncing()) {
            let syncdata = this.accountData.syncData;
            status = tbSync.getString("status.syncing", this.accountData.getAccountProperty("provider"));
            if (["send","eval","prepare"].includes(syncdata._syncstate.split(".")[0]) && (syncdata.progressData.todo + syncdata.progressData.done) > 0) {
              //add progress information
              status = status + " (" + syncdata.progressData.done + (syncdata.progressData.todo > 0 ? "/" + syncdata.progressData.todo : "") + ")";
            }
          }
          break;
      }
    } else {
      //remain empty if not selected
    }
    return status;
  }

  // get data objects
  get accountData() {
    return this._accountData;
  }

  get targetData() {
    // targetData can not be set during construction, because targetType has not been set
    // create it on the fly - re-create it, if targetType changed
    if (!this._target || this._target.targetType != this.getFolderProperty("targetType")) {
      switch (this.getFolderProperty("targetType")) {
        case "":
          throw new Error("Property <targetType> not set for this folder.");

        case "calendar":
          this._target = new tbSync.lightning.TargetData(this);
          break;

        case "addressbook":
          this._target = new tbSync.addressbook.TargetData(this);
          break;

        default:
          this._target = new tbSync.providers[this.accountData.getAccountProperty("provider")].targets[this.getFolderProperty("targetType")].TargetData(this);
      }
    }

    return this._target;
  }

  // Removes the folder and its target. If the target should be
  // kept  as a stale/unconnected item, provide a suffix, which
  // will be added to its name, to indicate, that it is no longer
  // managed by TbSync.
  remove(keepStaleTargetSuffix = "") {
    let target = this.getFolderProperty("target");
    if (target) {
      if (keepStaleTargetSuffix) {
        let changes = tbSync.db.getItemsFromChangeLog(target, 0, "_by_user");
        tbSync.db.clearChangeLog(target);
        this.targetData.appendStaleSuffix(keepStaleTargetSuffix, changes);
      } else {
        this.targetData.removeTarget();
      }
    }
    this.resetFolderProperty("target");
    this.setFolderProperty("cached", true);
  }
}

// there is only one syncdata object per account which contains the current state of the sync
var SyncData = class {
  constructor(accountID) {

    //internal (private, not to be touched by provider)
    this._syncstate = "accountdone";
    this._accountData = new tbSync.AccountData(accountID);
    this._progressData = new tbSync.ProgessData();
    this._currentFolderData = null;
  }

  //all functions provider should use should be in here
  //providers should not modify properties directly
  //when getSyncDataObj is used never change the folder id as a sync may be going on!

  _setCurrentFolderData(folderData) {
    this._currentFolderData = folderData;
  }
  _clearCurrentFolderData() {
    this._currentFolderData = null;
  }

  get eventLogInfo() {
    return new EventLogInfo(
      this.accountData.getAccountProperty("provider"),
      this.accountData.getAccountProperty("accountname"),
      this.accountData.accountID,
      this.currentFolderData ? this.currentFolderData.getFolderProperty("foldername") : "",
    );
  }

  get currentFolderData() {
    return this._currentFolderData;
  }

  get accountData() {
    return this._accountData;
  }

  get progressData() {
    return this._progressData;
  }

  setSyncState(syncstate) {
    //set new syncstate
    let msg = "State: " + syncstate + ", Account: " + this.accountData.getAccountProperty("accountname");
    if (this.currentFolderData) msg += ", Folder: " + this.currentFolderData.getFolderProperty("foldername");

    if (syncstate.split(".")[0] == "send") {
      //add timestamp to be able to display timeout countdown
      syncstate = syncstate + "||" + Date.now();
    }

    this._syncstate = syncstate;
    tbSync.dump("setSyncState", msg);

    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", this.accountData.accountID);
  }

  getSyncState(includingTimeStamp = false) {
    return includingTimeStamp ? this._syncstate : this._syncstate.split("||")[0];
  }
}

// simple dumper, who can dump to file or console
var dump = function (what, aMessage) {
  if (tbSync.prefs.getBoolPref("log.toconsole")) {
    Services.console.logStringMessage("[TbSync] " + what + " : " + aMessage);
  }

  if (this.prefs.getBoolPref("log.tofile")) {
    let now = new Date();
    tbSync.io.appendToFile("debug.log", "** " + now.toString() + " **\n[" + what + "] : " + aMessage + "\n\n");
  }
}

// get localized string from core or provider (if possible)
var getString = function (msg, provider) {
  let success = false;
  let localized = msg;

  //spezial treatment of strings with :: like status.httperror::403
  let parts = msg.split("::");

  // if a provider is given, try to get the string from the provider
  if (provider && tbSync.providers.loadedProviders.hasOwnProperty(provider)) {
    try {
      localized = tbSync.providers.loadedProviders[provider].bundle.GetStringFromName(parts[0]);
      success = true;
    } catch (e) {}
  }

  // if we did not yet succeed, request the tbsync bundle
  if (!success) {
    try {
      localized = tbSync.bundle.GetStringFromName(parts[0]);
      success = true;
    } catch (e) {}
  }

  //replace placeholders in returned string
  if (success) {
    for (let i = 0; i<parts.length; i++) {
      let regex = new RegExp( "##replace\."+i+"##", "g");
      localized = localized.replace(regex, parts[i]);
    }
  }

  return localized;
}

var generateUUID = function () {
  const uuidGenerator  = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
  return uuidGenerator.generateUUID().toString().replace(/[{}]/g, '');
}
<commit_msg>Update public.js<commit_after>/*
 * This file is part of TbSync.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

 "use strict";

 var StatusData = class {
  constructor(type = "success", message = "", details = "") {
    this.type = type; //success, info, warning, error
    this.message = message;
    this.details = details;
  }

  static get SUCCESS() {return "success"};
  static get ERROR() {return "error"};
  static get WARNING() {return "warning"};
  static get INFO() {return "info"};
  static get ACCOUNT_RERUN() {return "account_rerun"};
  static get FOLDER_RERUN() {return "folder_rerun"};
}

var ProgessData = class {
  constructor() {
    this._todo = 0;
    this._done = 0;
   }

   reset(done = 0, todo = 0) {
    this._todo = todo;
    this._done = done;
   }

   inc(value = 1) {
     this._done += value;
   }

   get todo() {
     return this._todo;
   }

   get done() {
     return this._done;
   }
}

var ProviderData = class {
  constructor(provider) {
    if (!tbSync.providers.hasOwnProperty(provider)) {
      throw new Error("Provider <" + provider + "> has not been loaded. Failed to create ProviderData.");
    }
    this.provider = provider;
  }

  getVersion() {
    return tbSync.providers.loadedProviders[this.provider].version;
  }

  getStringBundle() {
    return tbSync.providers.loadedProviders[this.provider].bundle;
  }

  getAllAccounts() {
    let accounts = tbSync.db.getAccounts();
    let allAccounts = [];
    for (let i=0; i<accounts.IDs.length; i++) {
      let accountID = accounts.IDs[i];
      if (accounts.data[accountID].provider == this.provider) {
        allAccounts.push(new tbSync.AccountData(accountID));
      }
    }
    return allAccounts;
  }

  getFolders(aFolderSearchCriteria = {}) {
    let allFolders = [];
    let folderSearchCriteria = {};
    Object.assign(folderSearchCriteria, aFolderSearchCriteria);
    folderSearchCriteria.cached = false;

    let folders = tbSync.db.findFolders(folderSearchCriteria, {"provider": this.provider});
    for (let i=0; i < folders.length; i++) {
      allFolders.push(new tbSync.FolderData(new tbSync.AccountData(folders[i].accountID), folders[i].folderID));
    }
    return allFolders;
  }

  getDefaultAccountEntries() {
    return  tbSync.providers.getDefaultAccountEntries(this.provider)
  }

  addAccount(accountName, accountOptions) {
    let newAccountID = tbSync.db.addAccount(accountName, accountOptions);
    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateAccountsList", newAccountID);
    return new tbSync.AccountData(newAccountID);
  }
}

var AccountData = class {
  constructor(accountID) {
    this._accountID = accountID;

    if (!tbSync.db.accounts.data.hasOwnProperty(accountID)) {
      throw new Error("An account with ID <" + accountID + "> does not exist. Failed to create AccountData.");
    }
  }

  get accountID() {
    return this._accountID;
  }

  getAllFolders() {
    let allFolders = [];
    let folders = tbSync.db.findFolders({"cached": false}, {"accountID": this.accountID});
    for (let i=0; i < folders.length; i++) {
      allFolders.push(new tbSync.FolderData(this, folders[i].folderID));
    }
    return allFolders;
  }

  getAllFoldersIncludingCache() {
    let allFolders = [];
    let folders = tbSync.db.findFolders({}, {"accountID": this.accountID});
    for (let i=0; i < folders.length; i++) {
      allFolders.push(new tbSync.FolderData(this, folders[i].folderID));
    }
    return allFolders;
  }

  getFolder(setting, value) {
    // ES6 supports variable keys by putting it into brackets
    let folders = tbSync.db.findFolders({[setting]: value, "cached": false}, {"accountID": this.accountID});
    if (folders.length > 0) return new tbSync.FolderData(this, folders[0].folderID);
    return null;
  }

  getFolderFromCache(setting, value) {
    // ES6 supports variable keys by putting it into brackets
    let folders = tbSync.db.findFolders({[setting]: value, "cached": true}, {"accountID": this.accountID});
    if (folders.length > 0) return new tbSync.FolderData(this, folders[0].folderID);
    return null;
  }

  createNewFolder() {
    return new tbSync.FolderData(this, tbSync.db.addFolder(this.accountID));
  }

  // get data objects
  get providerData() {
    return new tbSync.ProviderData(
      this.getAccountProperty("provider"),
    );
  }

  get syncData() {
    return tbSync.core.getSyncDataObject(this.accountID);
  }

  // shortcuts
  sync(syncDescription = {}) {
    tbSync.core.syncAccount(this.accountID, syncDescription);
  }

  isSyncing() {
    return tbSync.core.isSyncing(this.accountID);
  }

  isEnabled() {
    return tbSync.core.isEnabled(this.accountID);
  }

  isConnected() {
    return tbSync.core.isConnected(this.accountID);
  }

  getAccountProperty(field) {
    return tbSync.db.getAccountProperty(this.accountID, field);
  }

  setAccountProperty(field, value) {
    tbSync.db.setAccountProperty(this.accountID, field, value);
    Services.obs.notifyObservers(null, "tbsync.observer.manager.reloadAccountSetting", JSON.stringify({accountID: this.accountID, setting: field}));
  }

  resetAccountProperty(field) {
    tbSync.db.resetAccountProperty(this.accountID, field);
    Services.obs.notifyObservers(null, "tbsync.observer.manager.reloadAccountSetting", JSON.stringify({accountID: this.accountID, setting: field}));
  }
}

var FolderData = class {
  constructor(accountData, folderID) {
    this._accountData = accountData;
    this._folderID = folderID;
    this._target = null;

    if (!tbSync.db.folders[accountData.accountID].hasOwnProperty(folderID)) {
      throw new Error("A folder with ID <" + folderID + "> does not exist for the given account. Failed to create FolderData.");
    }
  }

  get folderID() {
    return this._folderID;
  }

  get accountID() {
    return this._accountData.accountID;
  }

  getDefaultFolderEntries() { // remove
    return tbSync.providers.getDefaultFolderEntries(this.accountID);
  }

  getFolderProperty(field) {
    return tbSync.db.getFolderProperty(this.accountID, this.folderID, field);
  }

  setFolderProperty(field, value) {
    tbSync.db.setFolderProperty(this.accountID, this.folderID, field, value);
  }

  resetFolderProperty(field) {
    tbSync.db.resetFolderProperty(this.accountID, this.folderID, field);
  }

  sync(aSyncDescription = {}) {
    let syncDescription = {};
    Object.assign(syncDescription, aSyncDescription);

    syncDescription.syncFolders = [this];
    this.accountData.sync(syncDescription);
  }

  isSyncing() {
    let syncdata = this.accountData.syncData;
    return (syncdata.currentFolderData && syncdata.currentFolderData.folderID == this.folderID);
  }

  getFolderStatus() {
    let status = "";

    if (this.getFolderProperty("selected")) {
      //default
      status = tbSync.getString("status." + this.getFolderProperty("status"), this.accountData.getAccountProperty("provider")).split("||")[0];

      switch (this.getFolderProperty("status").split(".")[0]) { //the status may have a sub-decleration
        case "success":
        case "modified":
          status = status + ": " + this.getFolderProperty("targetName");
          break;

        case "pending":
          //add extra info if this folder is beeing synced
          if (this.isSyncing()) {
            let syncdata = this.accountData.syncData;
            status = tbSync.getString("status.syncing", this.accountData.getAccountProperty("provider"));
            if (["send","eval","prepare"].includes(syncdata._syncstate.split(".")[0]) && (syncdata.progressData.todo + syncdata.progressData.done) > 0) {
              //add progress information
              status = status + " (" + syncdata.progressData.done + (syncdata.progressData.todo > 0 ? "/" + syncdata.progressData.todo : "") + ")";
            }
          }
          break;
      }
    } else {
      //remain empty if not selected
    }
    return status;
  }

  // get data objects
  get accountData() {
    return this._accountData;
  }

  get targetData() {
    // targetData can not be set during construction, because targetType has not been set
    // create it on the fly - re-create it, if targetType changed
    if (!this._target || this._target.targetType != this.getFolderProperty("targetType")) {
      switch (this.getFolderProperty("targetType")) {
        case "":
          throw new Error("Property <targetType> not set for this folder.");

        case "calendar":
          this._target = new tbSync.lightning.TargetData(this);
          break;

        case "addressbook":
          this._target = new tbSync.addressbook.TargetData(this);
          break;

        default:
          this._target = new tbSync.providers[this.accountData.getAccountProperty("provider")].targets[this.getFolderProperty("targetType")].TargetData(this);
      }
    }

    return this._target;
  }

  // Removes the folder and its target. If the target should be
  // kept  as a stale/unconnected item, provide a suffix, which
  // will be added to its name, to indicate, that it is no longer
  // managed by TbSync.
  remove(keepStaleTargetSuffix = "") {
    let target = this.getFolderProperty("target");
    if (target) {
      if (keepStaleTargetSuffix) {
        let changes = tbSync.db.getItemsFromChangeLog(target, 0, "_by_user");
        tbSync.db.clearChangeLog(target);
        this.targetData.appendStaleSuffix(keepStaleTargetSuffix, changes);
      } else {
        this.targetData.removeTarget();
      }
    }
    this.resetFolderProperty("target");
    this.setFolderProperty("cached", true);
  }
}

// there is only one syncdata object per account which contains the current state of the sync
var SyncData = class {
  constructor(accountID) {

    //internal (private, not to be touched by provider)
    this._syncstate = "accountdone";
    this._accountData = new tbSync.AccountData(accountID);
    this._progressData = new tbSync.ProgessData();
    this._currentFolderData = null;
  }

  //all functions provider should use should be in here
  //providers should not modify properties directly
  //when getSyncDataObj is used never change the folder id as a sync may be going on!

  _setCurrentFolderData(folderData) {
    this._currentFolderData = folderData;
  }
  _clearCurrentFolderData() {
    this._currentFolderData = null;
  }

  get eventLogInfo() {
    return new EventLogInfo(
      this.accountData.getAccountProperty("provider"),
      this.accountData.getAccountProperty("accountname"),
      this.accountData.accountID,
      this.currentFolderData ? this.currentFolderData.getFolderProperty("foldername") : "",
    );
  }

  get currentFolderData() {
    return this._currentFolderData;
  }

  get accountData() {
    return this._accountData;
  }

  get progressData() {
    return this._progressData;
  }

  setSyncState(syncstate) {
    //set new syncstate
    let msg = "State: " + syncstate + ", Account: " + this.accountData.getAccountProperty("accountname");
    if (this.currentFolderData) msg += ", Folder: " + this.currentFolderData.getFolderProperty("foldername");

    if (syncstate.split(".")[0] == "send") {
      //add timestamp to be able to display timeout countdown
      syncstate = syncstate + "||" + Date.now();
    }

    this._syncstate = syncstate;
    tbSync.dump("setSyncState", msg);

    Services.obs.notifyObservers(null, "tbsync.observer.manager.updateSyncstate", this.accountData.accountID);
  }

  getSyncState(includingTimeStamp = false) {
    return includingTimeStamp ? this._syncstate : this._syncstate.split("||")[0];
  }
}

// simple dumper, who can dump to file or console
var dump = function (what, aMessage) {
  if (tbSync.prefs.getBoolPref("log.toconsole")) {
    Services.console.logStringMessage("[TbSync] " + what + " : " + aMessage);
  }

  if (this.prefs.getBoolPref("log.tofile")) {
    let now = new Date();
    tbSync.io.appendToFile("debug.log", "** " + now.toString() + " **\n[" + what + "] : " + aMessage + "\n\n");
  }
}

// get localized string from core or provider (if possible)
var getString = function (msg, provider) {
  let success = false;
  let localized = msg;

  //spezial treatment of strings with :: like status.httperror::403
  let parts = msg.split("::");

  // if a provider is given, try to get the string from the provider
  if (provider && tbSync.providers.loadedProviders.hasOwnProperty(provider)) {
    try {
      localized = tbSync.providers.loadedProviders[provider].bundle.GetStringFromName(parts[0]);
      success = true;
    } catch (e) {}
  }

  // if we did not yet succeed, request the tbsync bundle
  if (!success) {
    try {
      localized = tbSync.bundle.GetStringFromName(parts[0]);
      success = true;
    } catch (e) {}
  }

  //replace placeholders in returned string
  if (success) {
    for (let i = 0; i<parts.length; i++) {
      let regex = new RegExp( "##replace\."+i+"##", "g");
      localized = localized.replace(regex, parts[i]);
    }
  }

  return localized;
}

var generateUUID = function () {
  const uuidGenerator  = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
  return uuidGenerator.generateUUID().toString().replace(/[{}]/g, '');
}
<|endoftext|>


<commit_before>Game = {

    pause : function() {
        var text = document.getElementById('gameStatus');
        text.innerHTML = "paused";
        this.status = 'paused';
    },

    resume : function(){
        var text = document.getElementById('gameStatus');
        text.innerHTML = "playing";
        this.status = 'playing';
    },

    isPaused :function(){
        return this.status == 'paused';
    },

    isCompleted :function(){
        return this.status == 'complete';
    },

    isPlayable :function(){
        return this.playable == 'playable';
    },

    processTracking : function(repsToDo, sequencePosition, recordings){

        let repCount = this.repsDone;
        if(sequencePosition === this.sequence){
            repCount-=1;
        }

        let start = (repCount === 1 &&  sequencePosition === 1);
        let end = (repCount === repsToDo &&  sequencePosition === this.sequence);

        var temp = { record : { rep : repCount, sequence: sequencePosition, angles : recordings }, start : start, end : end };
        this.webworker.postMessage(temp);

    },

    init : function(){
        this.repsDone = 1;
        this.sequence = 2;
        this.score = 0;

        this.webworker = new Worker('../../fingerSeparating/js/dataProcessing.js');
        this.webworker.addEventListener('message',  function (e) {

            let str = "";
            let json = JSON.stringify(e.data.record);
            if(e.data.start === true){
                str = '{ "exerciseRecord" : [' + json+ ',';
            }else if(e.data.end === true){
                str = json + ']}'
            }else{
                str = json + ','
            }

            document.getElementById('json').insertAdjacentHTML( 'beforeend', str );

            if (e.data.end ===true){
                let jsonString = document.getElementById('json').innerHTML;
                console.log(jsonString);
                jsonString.replace(/\\n/g, "\\n")
                    .replace(/\\'/g, "\\'")
                    .replace(/\\"/g, '\\"')
                    .replace(/\\&/g, "\\&")
                    .replace(/\\r/g, "\\r")
                    .replace(/\\t/g, "\\t")
                    .replace(/\\b/g, "\\b")
                    .replace(/\\f/g, "\\f");
                let obj = JSON.parse(jsonString);
                console.log(obj);

            }
        });

        this.gl = Main.gl;
        this.speed = 1;
        this.bucket = new Bucket();
        this.bucket.setSize(this.gl.drawingBufferWidth * 0.1, this.gl.drawingBufferHeight * 0.15);
        //this.bucket.setDefaultPosition(this.gl.drawingBufferWidth/2, this.gl.drawingBufferHeight * 0.075);
        this.bucket.create(this.gl.drawingBufferWidth/2, this.gl.drawingBufferHeight * 0.075 ,4);

        this.droplets = [];
        this.leader = 0;
        for(let index = 0; index < this.sequence; index++){
            if(index == 0){
                this.droplets[index] = new Drop();
                this.droplets[index].setCenter(this.gl.drawingBufferWidth / 2, this.gl.drawingBufferHeight * 0.90);
                this.droplets[index].setSize(this.gl.drawingBufferHeight * 0.15);
                this.droplets[index].setColor([1.0, 0.5, 0.0],[0.24, 0.522, 0.863]);
            }else{
                this.droplets[index] = new Drop();
                let center = this.droplets[index -1].getCenter();
                this.droplets[index].setCenter(center.x, center.y + (this.gl.drawingBufferHeight * 0.15) +  (this.gl.drawingBufferHeight * 0.1));
                this.droplets[index].setSize(this.gl.drawingBufferHeight * 0.15);
                this.droplets[index].setColor([1.0, 0.5, 0.0],[0.24, 0.522, 0.863]);
            }
        }
        this.status = 'paused';
        this.playable = 'playable';
    },

    separateLid : function(distance){
        return this.bucket.separateLids(distance);
    },

    tick : function(theta){
        let lastPosition = this.leader;
        for(let index = this.leader; index < this.sequence; index++){
            this.droplets[index].tick(theta);
        }
        let miss = this.bucket.dropLidCollision(this.droplets[this.leader]);
        let goal = this.bucket.dropContentCollision(this.droplets[this.leader]);
        if(miss || goal){
            this.leader = (this.leader + 1) % this.sequence;
            if(this.leader == 0){
                this.repsDone++;
                if(this.repsDone <= repsToDo){
                    for (let index = 0; index < this.sequence; index++) {
                        if (index == 0){
                            this.droplets[index].setCenter(this.gl.drawingBufferWidth / 2, this.gl.drawingBufferHeight * 0.90);
                            this.droplets[index].setSize(this.gl.drawingBufferHeight * 0.15);
                        }else{
                            let center = this.droplets[index - 1].getCenter();
                            this.droplets[index].setCenter(center.x, center.y + (this.gl.drawingBufferHeight * 0.15) +  (this.gl.drawingBufferHeight * 0.1));
                            this.droplets[index].setSize(this.gl.drawingBufferHeight * 0.15);
                        }
                    }
                }else{
                    this.status = "complete";
                }
            }
            if(goal){
                this.score++;
            }
        }
        return lastPosition + 1;
    },

    distanceCheck : function(){
        return (this.bucket.distanceFromDrop(this.droplets[this.leader])) <= (this.gl.drawingBufferHeight * 0.1);
    },

    drawScene : function(){
        this.gl.clearColor(0.24, 0.522, 0.863, 1);
        this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
        for(let index = this.leader; index < this.sequence; index++){
            this.droplets[index].draw(this.gl);
        }
        this.bucket.draw(this.gl);
    }
};<commit_msg>handling of data processing completed.<commit_after>Game = {

    pause : function() {
        var text = document.getElementById('gameStatus');
        text.innerHTML = "paused";
        this.status = 'paused';
    },

    resume : function(){
        var text = document.getElementById('gameStatus');
        text.innerHTML = "playing";
        this.status = 'playing';
    },

    isPaused :function(){
        return this.status == 'paused';
    },

    isCompleted :function(){
        return this.status == 'complete';
    },

    isPlayable :function(){
        return this.playable == 'playable';
    },

    processTracking : function(repsToDo, sequencePosition, recordings){

        let repCount = this.repsDone;
        if(sequencePosition === this.sequence){
            repCount-=1;
        }

        let start = (repCount === 1 &&  sequencePosition === 1);
        let end = (repCount === repsToDo &&  sequencePosition === this.sequence);

        var temp = { record : { rep : repCount, sequence: sequencePosition, angles : recordings }, start : start, end : end };
        this.webworker.postMessage(temp);

    },

    init : function(){
        this.repsDone = 1;
        this.sequence = 2;
        this.score = 0;

        this.webworker = new Worker('../../fingerSeparating/js/dataProcessing.js');
        this.webworker.addEventListener('message',  function (e) {

            let str = "";
            let json = JSON.stringify(e.data.record);
            if(e.data.start === true){
                str = '{ "exerciseRecord" : [' + json+ ',';
            }else if(e.data.end === true){
                let cookie = document.cookie.split('=');
                str = json + '], "' + cookie[0] + '" : "' + cookie[1] +'" }';
            }else{
                str = json + ',';
            }

            document.getElementById('json').insertAdjacentHTML( 'beforeend', str );

            if (e.data.end ===true){

                let jsonString = document.getElementById('json').innerHTML;
                let request = new XMLHttpRequest();
                let url = window.location.href;
                let index = url.lastIndexOf('/');
                url = url.substring(0,index) + '/submitData.php';
                request.open("POST", url, true);
                request.setRequestHeader("Content-type","application/json");
                request.send(jsonString);
                request.onreadystatechange = function(){
                    if (request.readyState == 4 && request.status == 200){
                        console.log(request.responseText);
                        if(request.responseText == 1){
                            console.log("dasfdsfadfdf");
                            let redirect = window.location.href;
                            let index2 = redirect.lastIndexOf('/exercises/fingerSeparating');
                            redirect = redirect.substring(0,index2);
                            console.log(redirect);
                            window.location.href = redirect;
                        }
                    }
                };
            }
        });

        this.gl = Main.gl;
        this.speed = 1;
        this.bucket = new Bucket();
        this.bucket.setSize(this.gl.drawingBufferWidth * 0.1, this.gl.drawingBufferHeight * 0.15);
        //this.bucket.setDefaultPosition(this.gl.drawingBufferWidth/2, this.gl.drawingBufferHeight * 0.075);
        this.bucket.create(this.gl.drawingBufferWidth/2, this.gl.drawingBufferHeight * 0.075 ,4);

        this.droplets = [];
        this.leader = 0;
        for(let index = 0; index < this.sequence; index++){
            if(index == 0){
                this.droplets[index] = new Drop();
                this.droplets[index].setCenter(this.gl.drawingBufferWidth / 2, this.gl.drawingBufferHeight * 0.90);
                this.droplets[index].setSize(this.gl.drawingBufferHeight * 0.15);
                this.droplets[index].setColor([1.0, 0.5, 0.0],[0.24, 0.522, 0.863]);
            }else{
                this.droplets[index] = new Drop();
                let center = this.droplets[index -1].getCenter();
                this.droplets[index].setCenter(center.x, center.y + (this.gl.drawingBufferHeight * 0.15) +  (this.gl.drawingBufferHeight * 0.1));
                this.droplets[index].setSize(this.gl.drawingBufferHeight * 0.15);
                this.droplets[index].setColor([1.0, 0.5, 0.0],[0.24, 0.522, 0.863]);
            }
        }
        this.status = 'paused';
        this.playable = 'playable';
    },

    separateLid : function(distance){
        return this.bucket.separateLids(distance);
    },

    tick : function(theta){
        let lastPosition = this.leader;
        for(let index = this.leader; index < this.sequence; index++){
            this.droplets[index].tick(theta);
        }
        let miss = this.bucket.dropLidCollision(this.droplets[this.leader]);
        let goal = this.bucket.dropContentCollision(this.droplets[this.leader]);
        if(miss || goal){
            this.leader = (this.leader + 1) % this.sequence;
            if(this.leader == 0){
                this.repsDone++;
                if(this.repsDone <= repsToDo){
                    for (let index = 0; index < this.sequence; index++) {
                        if (index == 0){
                            this.droplets[index].setCenter(this.gl.drawingBufferWidth / 2, this.gl.drawingBufferHeight * 0.90);
                            this.droplets[index].setSize(this.gl.drawingBufferHeight * 0.15);
                        }else{
                            let center = this.droplets[index - 1].getCenter();
                            this.droplets[index].setCenter(center.x, center.y + (this.gl.drawingBufferHeight * 0.15) +  (this.gl.drawingBufferHeight * 0.1));
                            this.droplets[index].setSize(this.gl.drawingBufferHeight * 0.15);
                        }
                    }
                }else{
                    this.status = "complete";
                }
            }
            if(goal){
                this.score++;
            }
        }
        return lastPosition + 1;
    },

    distanceCheck : function(){
        return (this.bucket.distanceFromDrop(this.droplets[this.leader])) <= (this.gl.drawingBufferHeight * 0.1);
    },

    drawScene : function(){
        this.gl.clearColor(0.24, 0.522, 0.863, 1);
        this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
        for(let index = this.leader; index < this.sequence; index++){
            this.droplets[index].draw(this.gl);
        }
        this.bucket.draw(this.gl);
    }
};<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import PlayButton from 'components/buttons/PlayButton';
import styled from 'styled-components';
import { formatPlaytime } from 'helpers/format';
import { H1 } from 'components/styles/Headings';
import { pure } from 'recompose';
import { prop } from 'styled-tools';
import ArtworkGrid from './ArtworkGrid';

const Wrapper = styled.div`
  display: flex;
  padding: 15px 10px;
  margin-bottom: 20px;
`;

const Subtitle = styled.span`
  display: block;
  font-size: ${prop('theme.fontSize.subtitle')};
  color: ${prop('theme.colors.reverse.primaryText')};
  font-weight: 300;
  margin-bottom: 10px;
`;

const Title = styled(H1)`
  margin-bottom: 0.5em;
  font-weight: 600;
`;

const TimelineHeader = ({ timeline, tracks, timelineId }) => (
  <Wrapper>
    <ArtworkGrid tracks={tracks} />

      <Subtitle>{timeline.type || 'timeline'}</Subtitle>
      <Title>{timeline.title}</Title>
      {timeline.kind === 'timeline' &&
        <Subtitle>
          Created by {timeline.user.username} ● {timeline.tracks.length} tracks,
          {formatPlaytime(timeline.duration)}
        </Subtitle>}
      {tracks.length > 0 &&
        <PlayButton trackId={tracks[0].id} timelineId={timelineId} />}

  </Wrapper>
);
TimelineHeader.propTypes = {
  timeline: PropTypes.object.isRequired,
  timelineId: PropTypes.string.isRequired,
  tracks: PropTypes.arrayOf(PropTypes.object),
};

export default pure(TimelineHeader);
<commit_msg>fix default type<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import PlayButton from 'components/buttons/PlayButton';
import styled from 'styled-components';
import { formatPlaytime } from 'helpers/format';
import { H1 } from 'components/styles/Headings';
import { pure } from 'recompose';
import { prop } from 'styled-tools';
import ArtworkGrid from './ArtworkGrid';

const Wrapper = styled.div`
  display: flex;
  padding: 15px 10px;
  margin-bottom: 20px;
`;

const Subtitle = styled.span`
  display: block;
  font-size: ${prop('theme.fontSize.subtitle')};
  color: ${prop('theme.colors.reverse.primaryText')};
  font-weight: 300;
  margin-bottom: 10px;
`;

const Title = styled(H1)`
  margin-bottom: 0.5em;
  font-weight: 600;
`;

const TimelineHeader = ({ timeline, tracks, timelineId }) => (
  <Wrapper>
    <ArtworkGrid tracks={tracks} />

      <Subtitle>{timeline.type || 'playlist'}</Subtitle>
      <Title>{timeline.title}</Title>
      {timeline.kind === 'timeline' &&
        <Subtitle>
          Created by {timeline.user.username} ● {timeline.tracks.length} tracks,
          {formatPlaytime(timeline.duration)}
        </Subtitle>}
      {tracks.length > 0 &&
        <PlayButton trackId={tracks[0].id} timelineId={timelineId} />}

  </Wrapper>
);
TimelineHeader.propTypes = {
  timeline: PropTypes.object.isRequired,
  timelineId: PropTypes.string.isRequired,
  tracks: PropTypes.arrayOf(PropTypes.object),
};

export default pure(TimelineHeader);
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var authentication = require('../authentication');
var request = require('request-promise');
var url = require('url');

// Simple route middleware to ensure user is authenticated.
//   Use this route middleware on any resource that needs to be protected.  If
//   the request is authenticated (typically via a persistent login session),
//   the request will proceed.  Otherwise, the user will be redirected to the
//   login page.
function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next()
  }
  res.status(401).send({
    authUri: authentication.getAuthUri(),
    msg: 'Authentication required.'
  });
}

router.post('/logout', function(req, res) {
  req.session.destroy();
  return res.send({});
});

router.get('/session', function(req, res) {
  if (req.user) {
    res.send({userId: req.user.id});
  } else {
    res.status(401).send({
      authUri: authentication.getAuthUri(),
      msg: 'Authentication required.'
    });
  }
});

var getDocuments = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/documents',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting documents: ', err);
      });
    } else {
      console.log('GET /api/documents error: ', data);
    }
  });
};

var getElementList = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/documents/d/' + req.query.documentId + "/w/" + req.query.workspaceId + '/elements',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/documents/elements error: ', data);
    }
  });
};

var getPartsList = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/parts/d/' + req.query.documentId + "/w/" + req.query.workspaceId,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getPartsList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/parts/workspace error: ', data);
    }
  });
};

// NOTE - this interface will be deprecated in early July 2015. Export
// functions will be moved to the relevant resources (parts,
// partstudios, assemblies)
var getStl = function(req, res) {
  var url = 'https://partner.dev.onshape.com/api/documents/d/' + req.query.documentId +
      '/w/' + req.query.workspaceId + '/e/' + req.query.stlElementId +'/export/' +
      '?format=STL&mode=' + 'text'  +
      '&scale=1&units=inch';
  if (req.query.angleTolerance !== '' && req.query.chordTolerance !== '') {
    url += '&angleTolerance=' + req.query.angleTolerance +'&chordTolerance=' + req.query.chordTolerance;
  }
  if (req.query.partId != null) {
    console.log("** STL for partId " + req.query.partId);
  }
  else {
    console.log("** STL - no partId");
  }

  request.get({
    uri: url,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getStl(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/parts/workspace error: ', data);
    }
  });
};

router.get('/documents', getDocuments);
router.get('/elements', getElementList);
router.get('/stl', getStl);
router.get('/parts', getPartsList);

module.exports = router;
<commit_msg>API Update<commit_after>var express = require('express');
var router = express.Router();
var authentication = require('../authentication');
var request = require('request-promise');
var url = require('url');

// Simple route middleware to ensure user is authenticated.
//   Use this route middleware on any resource that needs to be protected.  If
//   the request is authenticated (typically via a persistent login session),
//   the request will proceed.  Otherwise, the user will be redirected to the
//   login page.
function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next()
  }
  res.status(401).send({
    authUri: authentication.getAuthUri(),
    msg: 'Authentication required.'
  });
}

router.post('/logout', function(req, res) {
  req.session.destroy();
  return res.send({});
});

router.get('/session', function(req, res) {
  if (req.user) {
    res.send({userId: req.user.id});
  } else {
    res.status(401).send({
      authUri: authentication.getAuthUri(),
      msg: 'Authentication required.'
    });
  }
});

var getDocuments = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/documents',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getDocuments(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting documents: ', err);
      });
    } else {
      console.log('GET /api/documents error: ', data);
    }
  });
};

var getElementList = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/documents/d/' + req.query.documentId + "/w/" + req.query.workspaceId + '/elements',
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getElementList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/documents/elements error: ', data);
    }
  });
};

var getPartsList = function(req, res) {
  request.get({
    uri: 'https://partner.dev.onshape.com/api/parts/d/' + req.query.documentId + "/w/" + req.query.workspaceId,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getPartsList(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/parts/workspace error: ', data);
    }
  });
};

// NOTE - this interface will be deprecated in early July 2015. Export
// functions will be moved to the relevant resources (parts,
// partstudios, assemblies)
var getStl = function(req, res) {
  var url;
  if (req.query.partId != null) {
    url = 'https://partner.dev.onshape.com/api/parts/d/' + req.query.documentId +
    '/w/' + req.query.workspaceId + '/e/' + req.query.stlElementId +'/partid/'+ req.query.partId + '/stl/' +
    '?mode=' + 'text'  +
    '&scale=1&units=inch';
    console.log("** STL for partId " + req.query.partId);
  }
  else {
    res.send("ok");
    return;
  }

  if (req.query.angleTolerance !== '' && req.query.chordTolerance !== '') {
    url += '&angleTolerance=' + req.query.angleTolerance +'&chordTolerance=' + req.query.chordTolerance;
  }

  request.get({
    uri: url,
    headers: {
      'Authorization': 'Bearer ' + req.user.accessToken
    }
  }).then(function(data) {
    res.send(data);
  }).catch(function(data) {
    if (data.statusCode === 401) {
      authentication.refreshOAuthToken(req, res).then(function() {
        getStl(req, res);
      }).catch(function(err) {
        console.log('Error refreshing token or getting elements: ', err);
      });
    } else {
      console.log('GET /api/parts/workspace error: ', data);
    }
  });
};

router.get('/documents', getDocuments);
router.get('/elements', getElementList);
router.get('/stl', getStl);
router.get('/parts', getPartsList);

module.exports = router;
<|endoftext|>


<commit_before>// start from http://www.quirksmode.org/js/cookies.html
function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}
// end from http://www.quirksmode.org/js/cookies.html

function zpad_left(tmp, n) {
	var pad = ''
	for(var i = tmp.length; i < n; i++)
		pad += '0';
	return pad + tmp;
}

function nice_time(tmp) {
	neg = tmp < 0;
	if(neg) tmp = -tmp;
	var sec = parseInt(tmp % 60);
	tmp /= 60;
	var min = parseInt(tmp % 60);
	var hrs = parseInt(tmp / 60);
	if(hrs == 0)
		var ret = min.toString() + ':' + zpad_left(sec.toString(), 2);
	else
		var ret = hrs.toString() + ':' +
			  zpad_left(min.toString(), 2) + ':' +
			  zpad_left(sec.toString(), 2);
	if(neg) ret = '-' + ret;
	return ret;
}

function _tr(data) {
	n_tr = document.createElement('tr');
	for(var i = 0; i < data.length; i++) {
		n_td = document.createElement('td');
		n_td.appendChild(document.createTextNode(data[i]));
		n_tr.appendChild(n_td);
	}
	return n_tr;
}

function Main() {
	this.focus_queryField = function() {
		$("#queryField").focus();
	}
	this.on_scroll = function() {
		var me = this;
		if(this.scroll_semaphore != 0)
			return;
		if(!this.showing_results)
			return;
		var diff = $(document).height() -
			   $(document).scrollTop() -
			   $(window).height();
		if (diff <= 0) {
			this.fill_resultsTable();
			setTimeout(function() {
				me.on_scroll();
			},0)
		}
	}
	this.up_scroll_semaphore = function() {
		this.scroll_semaphore += 1;
		if(this.scroll_semaphore == 0)
			this.on_scroll();
	};
	this.down_scroll_semaphore = function() {
		this.scroll_semaphore -= 1;
	};
	this.on_loginForm_keyDown = function(e) {
		if(e.which == 27) {
			$.unblockUI();
		} else if(e.which == 13) {
			$.unblockUI();
			createCookie('user', $('#loginFormUser').val());
			createCookie('pass', $('#loginFormPass').val());
			this.request_media(this.pendingRequest);
		}
	};
	this.run = function() {
		var me = this;
		$.blockUI.defaults.applyPlatformOpacityRules = false;
		this.loginForm = $('#loginForm');
		this.loginForm.hide();
		$("#loginFormUser").keydown(function(e) {
				me.on_loginForm_keyDown(e);
			});
		$("#loginFormPass").keydown(function(e){
				me.on_loginForm_keyDown(e);
			});
		this.queryCheck = /^[a-z0-9 ]*$/;
		this.queryReplace = /[^a-z0-9 ]/g;
		this.focus_queryField();
		//$("#queryField").blur(function(){
		//	setTimeout(function() { me.focus_queryField(); }, 0);
		//});
		$(document).scroll(function() { me.on_scroll(); });
		$(window).focus(this.focus_queryField);
		$("#resultsBar").hide();
		$("#requestsBar").focus(this.focus_queryField);
		$("#queryField").keypress(function(e){
			return me.on_queryField_keyPress(e);
		});
		$("#queryField").keydown(function(e){
			setTimeout(function() { me.check_queryField(); }, 0);
		});
		this.showing_results = false;
		this.fetch_media();
		this.fetch_requests();
		this.fetch_playing();
		this.fetching_media = false;
		this.fetching_requests = false;
		this.fetching_playing = false;
		this.got_media = false;
		this.got_requests = false;
		this.got_playing = false;
		this.update_requests = false;
		this.update_results = false;
		this.updating_times = false;
		this.current_query = '';
		this.results_offset = null;
		this.scroll_semaphore = 0;
	};

	this.do_updates = function() {
		var me = this;
		if(this.update_requests) {
			this.update_requests = false;
			$("#requestsTable").empty();
			this.fill_requestsTable();
		}
		if(this.update_results) {
			$("#resultsTable").empty();
			this.results_offset = 0;
			this.fill_resultsTable();
			setTimeout(function() {
				me.on_scroll();
			}, 0);
			this.update_results = false;
		}
		if(this.got_playing && !this.updating_times) {
			this.updating_times = true;
			setInterval(function() {
				me.update_times();
			}, 1000);
		}
	};

	this.update_times = function() {
		var me = this;
		var diff = (this.playing_endTime
			    - new Date().getTime() / 1000.0
			    - this.playing_serverTime
			    + this.playing_requestTime);
		$('#requestsTable tr').each(function(i, tr){
			var offset = $(tr).data('offset');
			$('.time', tr).text(offset == null ? ''
					: nice_time(offset + diff));
		});
		if(diff <= 0) {
			this.fetch_requests();
			this.fetch_playing();
		}
	};

	this.do_query = function() {
		var cq = this.current_query;
		for(var s = cq.length;
		    !this.qc[cq.slice(0, s)];
		    s--);
		for(var i = s; i < cq.length; i++) {
			var from = cq.slice(0, i);
			var to = cq.slice(0, i + 1);
			var k = 0;
			this.qc[to] = [];
			for(var j = 0; j < this.qc[from].length; j++) {
				if(this.qc[from][j][1].indexOf(to) != -1) {
					this.qc[to][k] = this.qc[from][j];
					k += 1;
				}
			}
		}
	};

	this.fill_resultsTable = function() {
		var me = this;
		var t = $("#resultsTable");
		var cq = this.current_query;
		if(!this.got_media)
			return;
		this.do_query();
		var got = 0;
		for(; this.results_offset < this.qc[cq].length; this.results_offset++) {
			got += 1;
			var i = this.results_offset;
			var m = this.media['_'+this.qc[cq][i][0]];
			var tr = _tr([m[0], m[1]]);
			$(tr).data('key', this.qc[cq][i][0]);
			$('td:eq(0)',tr).addClass('artist');
			$('td:eq(1)',tr).addClass('title');
			$(tr).click(function() {
					$("#queryField").val("");
					me.check_queryField();
					$("#queryField").focus();
					me.request_media($(this).data('key'));
				});
			t.append(tr);
			if(got == 10) break;
		}
		this.results_offset++;
	};

	this.fill_requestsTable = function() {
		var t = $("#requestsTable");
		var start = (this.got_playing ? -1 : 0);
		var end = (this.got_requests ? this.requests.length : 0);
		var ctime = null;
		for(var i = start; i < end; i++) {
			var m = (i == -1 ? this.playing_media
				: this.requests[i].media);
			var b = (i == -1 ? this.playing_requestedBy
				: this.requests[i].by);
			if(!b) b = 'marietje';
			var txt_a = m;
			var txt_t = '';
			if(this.got_media) {
				txt_a = this.media['_'+m][0];
				txt_t = this.media['_'+m][1];
			}
			tr = _tr([b, txt_a, txt_t, (ctime == null ? '' : ctime)]);
			$(tr).data('offset', ctime);
			ctime = (i == -1 ? 0 :
				(this.got_media ?
				 ctime + this.media['_'+m][2] : 0));
			$('td:eq(0)',tr).addClass('by');
			$('td:eq(1)',tr).addClass('artist');
			$('td:eq(2)',tr).addClass('title');
			$('td:eq(3)',tr).addClass('time');
			t.append(tr);
		}
	};

	this.show_loginForm = function() {
		var me =this;
		setTimeout(function() {
			$.blockUI({message: me.loginForm });
		}, 1000);
	};

	this.request_media = function(key) {
		this.pendingRequest = key;
		var me = this;
		if(readCookie('user') == null ||
		   readCookie('pass') == null) {
			this.show_loginForm();
			return;
		}
		$.get("/request/"+readCookie('user') + "/" +
				  readCookie('pass') + "/" +
				  key.toString(), function (doc) {
				me.on_requested_media(doc);
			});
	};

	this.on_requested_media = function(doc) {
		var code = $(doc.firstChild).attr('code');
		if(code == 'wrong-login') {
			this.show_loginForm();
			return;
		} else if (code == 'ok') {
			this.fetch_requests();
			$.growlUI('Success', 'Your request was succesfull');
		} else if (code == 'denied') {
			$.growlUI('Denied', $(doc.firstChild).attr('message'));
		}
	};

	this.check_queryField = function(e) {
		var me = this;
		var q = $("#queryField").val();
		if(!this.queryCheck.test(q)) {
			q = q.toLowerCase().replace(this.queryReplace, '');
			$("#queryField").val(q);
		}
		if(q == this.current_query)
			return;
		this.current_query = q;
		_cb = function() { me.up_scroll_semaphore(); };
		if(q == '' && this.showing_results){
			this.down_scroll_semaphore();
			this.down_scroll_semaphore();
			$('#resultsBar').hide('fast', _cb);
			$('#requestsBar').show('fast', _cb);
			this.showing_results = false;
		} else if (q != '' && !this.showing_results) {
			this.down_scroll_semaphore();
			this.down_scroll_semaphore();
			$('#resultsBar').show('fast', _cb);
			$('#requestsBar').hide('fast', _cb);
			this.showing_results = true;
		}
		if(q != '') {
			this.update_results = true;
			this.do_updates();
		}

	};

	this.on_queryField_keyPress = function(e) {
		var me = this;
		if(e.which == 21) // C-u
			$("#queryField").val('');
		setTimeout(function() { me.check_queryField(); }, 0);
	};

	this.fetch_media = function() {
		var me = this;
		if(this.fetching_media) return;
		this.fetching_media = true;
		$.getJSON('/media', function(req) {
			me.on_got_media(req);
		});
	};
	this.fetch_requests = function() {
		var me = this;
		if(this.fetching_requests) return;
		this.fetching_requests = true;
		$.get('/requests', function(req) {
			me.on_got_requests(req);
		});
	};
	this.fetch_playing = function() {
		var me = this;
		if(this.fetching_playing) return;
		this.fetching_playing = true;
		$.get('/playing', function(req) {
			me.on_got_playing(req);
		});
	};

	this.on_got_media = function(req) {
		var me = this;
		this.got_media = true;
		this.fetching_media = false;
		this.media = req;
		this.qc = {'': []};
		var i = 0;
		for(var _k in req) {
			var cr = this.queryReplace;
			var k = _k.slice(1);
			me.qc[''][i++] = [
				k,
				req[_k][0].toLowerCase().replace(cr, '') + '|' +
				req[_k][1].toLowerCase().replace(cr, '')];
		};
		this.update_requests = true;
		this.update_results = true;
		this.do_updates();
	};
	this.on_got_requests = function(req) {
		var me = this;
		this.got_requests = true;
		this.fetching_requests = false;
		this.requests = [];
		$("request", req).each(function(i, r) {
			m = $(r);
			me.requests[i] = {
				media: m.attr('media'),
				by: m.attr('by')
			};
		});
		this.update_requests = true;
		this.do_updates();
	};
	this.on_got_playing = function(req) {
		this.got_playing = true;
		this.fetching_playing = false;
		var m = $(req.firstChild);
		this.playing_media = m.attr('media');
		this.playing_requestedBy = m.attr('requestedBy');
		this.playing_endTime = parseFloat(m.attr('endTime'));
		this.playing_serverTime = parseFloat(m.attr('serverTime'));
		this.playing_requestTime = new Date().getTime() / 1000.0;
		this.update_requests = true;
		this.do_updates();
	};
}

main = new Main();
$(document).ready(function(){main.run();});

<commit_msg>ajax: add catch_once and raise<commit_after>// start from http://www.quirksmode.org/js/cookies.html
function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}
// end from http://www.quirksmode.org/js/cookies.html

function zpad_left(tmp, n) {
	var pad = ''
	for(var i = tmp.length; i < n; i++)
		pad += '0';
	return pad + tmp;
}

function nice_time(tmp) {
	neg = tmp < 0;
	if(neg) tmp = -tmp;
	var sec = parseInt(tmp % 60);
	tmp /= 60;
	var min = parseInt(tmp % 60);
	var hrs = parseInt(tmp / 60);
	if(hrs == 0)
		var ret = min.toString() + ':' + zpad_left(sec.toString(), 2);
	else
		var ret = hrs.toString() + ':' +
			  zpad_left(min.toString(), 2) + ':' +
			  zpad_left(sec.toString(), 2);
	if(neg) ret = '-' + ret;
	return ret;
}

function _tr(data) {
	n_tr = document.createElement('tr');
	for(var i = 0; i < data.length; i++) {
		n_td = document.createElement('td');
		n_td.appendChild(document.createTextNode(data[i]));
		n_tr.appendChild(n_td);
	}
	return n_tr;
}

function Main() {
	this.focus_queryField = function() {
		$("#queryField").focus();
	}
	this.on_scroll = function() {
		var me = this;
		if(this.scroll_semaphore != 0)
			return;
		if(!this.showing_results)
			return;
		var diff = $(document).height() -
			   $(document).scrollTop() -
			   $(window).height();
		if (diff <= 0) {
			this.fill_resultsTable();
			setTimeout(function() {
				me.on_scroll();
			},0)
		}
	}
	this.up_scroll_semaphore = function() {
		this.scroll_semaphore += 1;
		if(this.scroll_semaphore == 0)
			this.on_scroll();
	};
	this.down_scroll_semaphore = function() {
		this.scroll_semaphore -= 1;
	};
	this.on_loginForm_keyDown = function(e) {
		if(e.which == 27) {
			$.unblockUI();
		} else if(e.which == 13) {
			$.unblockUI();
			createCookie('user', $('#loginFormUser').val());
			createCookie('pass', $('#loginFormPass').val());
			this.raise('new_credentials');
		}
	};
	this.raise = function(ev) {
		for (var i = 0; i < this.handlers[ev].length; i++) {
			this.handlers[ev][i]();
		}
		this.handlers[ev] = [];
	};
	this.catch_once = function(ev, h) {
		this.handlers[ev][this.handlers[ev].length] = function() {
			h();
		};
	};
	this.run = function() {
		var me = this;
		$.blockUI.defaults.applyPlatformOpacityRules = false;
		this.handlers = {new_credentials: []};
		this.loginForm = $('#loginForm');
		this.loginForm.hide();
		$("#loginFormUser").keydown(function(e) {
				me.on_loginForm_keyDown(e);
			});
		$("#loginFormPass").keydown(function(e){
				me.on_loginForm_keyDown(e);
			});
		this.queryCheck = /^[a-z0-9 ]*$/;
		this.queryReplace = /[^a-z0-9 ]/g;
		this.focus_queryField();
		//$("#queryField").blur(function(){
		//	setTimeout(function() { me.focus_queryField(); }, 0);
		//});
		$(document).scroll(function() { me.on_scroll(); });
		$(window).focus(this.focus_queryField);
		$("#resultsBar").hide();
		$("#requestsBar").focus(this.focus_queryField);
		$("#queryField").keypress(function(e){
			return me.on_queryField_keyPress(e);
		});
		$("#queryField").keydown(function(e){
			setTimeout(function() { me.check_queryField(); }, 0);
		});
		this.showing_results = false;
		this.fetch_media();
		this.fetch_requests();
		this.fetch_playing();
		this.fetching_media = false;
		this.fetching_requests = false;
		this.fetching_playing = false;
		this.got_media = false;
		this.got_requests = false;
		this.got_playing = false;
		this.update_requests = false;
		this.update_results = false;
		this.updating_times = false;
		this.current_query = '';
		this.results_offset = null;
		this.scroll_semaphore = 0;
	};

	this.do_updates = function() {
		var me = this;
		if(this.update_requests) {
			this.update_requests = false;
			$("#requestsTable").empty();
			this.fill_requestsTable();
		}
		if(this.update_results) {
			$("#resultsTable").empty();
			this.results_offset = 0;
			this.fill_resultsTable();
			setTimeout(function() {
				me.on_scroll();
			}, 0);
			this.update_results = false;
		}
		if(this.got_playing && !this.updating_times) {
			this.updating_times = true;
			setInterval(function() {
				me.update_times();
			}, 1000);
		}
	};

	this.update_times = function() {
		var me = this;
		var diff = (this.playing_endTime
			    - new Date().getTime() / 1000.0
			    - this.playing_serverTime
			    + this.playing_requestTime);
		$('#requestsTable tr').each(function(i, tr){
			var offset = $(tr).data('offset');
			$('.time', tr).text(offset == null ? ''
					: nice_time(offset + diff));
		});
		if(diff <= 0) {
			this.fetch_requests();
			this.fetch_playing();
		}
	};

	this.do_query = function() {
		var cq = this.current_query;
		for(var s = cq.length;
		    !this.qc[cq.slice(0, s)];
		    s--);
		for(var i = s; i < cq.length; i++) {
			var from = cq.slice(0, i);
			var to = cq.slice(0, i + 1);
			var k = 0;
			this.qc[to] = [];
			for(var j = 0; j < this.qc[from].length; j++) {
				if(this.qc[from][j][1].indexOf(to) != -1) {
					this.qc[to][k] = this.qc[from][j];
					k += 1;
				}
			}
		}
	};

	this.fill_resultsTable = function() {
		var me = this;
		var t = $("#resultsTable");
		var cq = this.current_query;
		if(!this.got_media)
			return;
		this.do_query();
		var got = 0;
		for(; this.results_offset < this.qc[cq].length; this.results_offset++) {
			got += 1;
			var i = this.results_offset;
			var m = this.media['_'+this.qc[cq][i][0]];
			var tr = _tr([m[0], m[1]]);
			$(tr).data('key', this.qc[cq][i][0]);
			$('td:eq(0)',tr).addClass('artist');
			$('td:eq(1)',tr).addClass('title');
			$(tr).click(function() {
					$("#queryField").val("");
					me.check_queryField();
					$("#queryField").focus();
					me.request_media($(this).data('key'));
				});
			t.append(tr);
			if(got == 10) break;
		}
		this.results_offset++;
	};

	this.fill_requestsTable = function() {
		var t = $("#requestsTable");
		var start = (this.got_playing ? -1 : 0);
		var end = (this.got_requests ? this.requests.length : 0);
		var ctime = null;
		for(var i = start; i < end; i++) {
			var m = (i == -1 ? this.playing_media
				: this.requests[i].media);
			var b = (i == -1 ? this.playing_requestedBy
				: this.requests[i].by);
			if(!b) b = 'marietje';
			var txt_a = m;
			var txt_t = '';
			if(this.got_media) {
				txt_a = this.media['_'+m][0];
				txt_t = this.media['_'+m][1];
			}
			tr = _tr([b, txt_a, txt_t, (ctime == null ? '' : ctime)]);
			$(tr).data('offset', ctime);
			ctime = (i == -1 ? 0 :
				(this.got_media ?
				 ctime + this.media['_'+m][2] : 0));
			$('td:eq(0)',tr).addClass('by');
			$('td:eq(1)',tr).addClass('artist');
			$('td:eq(2)',tr).addClass('title');
			$('td:eq(3)',tr).addClass('time');
			t.append(tr);
		}
	};

	this.show_loginForm = function() {
		var me =this;
		setTimeout(function() {
			$.blockUI({message: me.loginForm });
		}, 1000);
	};

	this.request_media = function(key) {
		var me = this;
		if(readCookie('user') == null ||
		   readCookie('pass') == null) {
			this.catch_once('new_credentials', function() {
				me.request_media(key);
			});
			this.show_loginForm();
			return;
		}
		$.get("/request/"+readCookie('user') + "/" +
				  readCookie('pass') + "/" +
				  key.toString(), function (doc) {
				me.on_requested_media(doc);
			});
	};

	this.on_requested_media = function(doc) {
		var code = $(doc.firstChild).attr('code');
		if(code == 'wrong-login') {
			this.show_loginForm();
			return;
		} else if (code == 'ok') {
			this.fetch_requests();
			$.growlUI('Success', 'Your request was succesfull');
		} else if (code == 'denied') {
			$.growlUI('Denied', $(doc.firstChild).attr('message'));
		}
	};

	this.check_queryField = function(e) {
		var me = this;
		var q = $("#queryField").val();
		if(!this.queryCheck.test(q)) {
			q = q.toLowerCase().replace(this.queryReplace, '');
			$("#queryField").val(q);
		}
		if(q == this.current_query)
			return;
		this.current_query = q;
		_cb = function() { me.up_scroll_semaphore(); };
		if(q == '' && this.showing_results){
			this.down_scroll_semaphore();
			this.down_scroll_semaphore();
			$('#resultsBar').hide('fast', _cb);
			$('#requestsBar').show('fast', _cb);
			this.showing_results = false;
		} else if (q != '' && !this.showing_results) {
			this.down_scroll_semaphore();
			this.down_scroll_semaphore();
			$('#resultsBar').show('fast', _cb);
			$('#requestsBar').hide('fast', _cb);
			this.showing_results = true;
		}
		if(q != '') {
			this.update_results = true;
			this.do_updates();
		}

	};

	this.on_queryField_keyPress = function(e) {
		var me = this;
		if(e.which == 21) // C-u
			$("#queryField").val('');
		setTimeout(function() { me.check_queryField(); }, 0);
	};

	this.fetch_media = function() {
		var me = this;
		if(this.fetching_media) return;
		this.fetching_media = true;
		$.getJSON('/media', function(req) {
			me.on_got_media(req);
		});
	};
	this.fetch_requests = function() {
		var me = this;
		if(this.fetching_requests) return;
		this.fetching_requests = true;
		$.get('/requests', function(req) {
			me.on_got_requests(req);
		});
	};
	this.fetch_playing = function() {
		var me = this;
		if(this.fetching_playing) return;
		this.fetching_playing = true;
		$.get('/playing', function(req) {
			me.on_got_playing(req);
		});
	};

	this.on_got_media = function(req) {
		var me = this;
		this.got_media = true;
		this.fetching_media = false;
		this.media = req;
		this.qc = {'': []};
		var i = 0;
		for(var _k in req) {
			var cr = this.queryReplace;
			var k = _k.slice(1);
			me.qc[''][i++] = [
				k,
				req[_k][0].toLowerCase().replace(cr, '') + '|' +
				req[_k][1].toLowerCase().replace(cr, '')];
		};
		this.update_requests = true;
		this.update_results = true;
		this.do_updates();
	};
	this.on_got_requests = function(req) {
		var me = this;
		this.got_requests = true;
		this.fetching_requests = false;
		this.requests = [];
		$("request", req).each(function(i, r) {
			m = $(r);
			me.requests[i] = {
				media: m.attr('media'),
				by: m.attr('by')
			};
		});
		this.update_requests = true;
		this.do_updates();
	};
	this.on_got_playing = function(req) {
		this.got_playing = true;
		this.fetching_playing = false;
		var m = $(req.firstChild);
		this.playing_media = m.attr('media');
		this.playing_requestedBy = m.attr('requestedBy');
		this.playing_endTime = parseFloat(m.attr('endTime'));
		this.playing_serverTime = parseFloat(m.attr('serverTime'));
		this.playing_requestTime = new Date().getTime() / 1000.0;
		this.update_requests = true;
		this.do_updates();
	};
}

main = new Main();
$(document).ready(function(){main.run();});

<|endoftext|>


<commit_before>'use strict';

var instance;

class ValidationProvider {

    constructor( engine, types ) {

        this.engine = engine;

        this.types = types;
    }

    validate( values, schema, options ) {

        var result = this.engine.validate( values, schema, options );

        if( result.error ) {

            throw { statusCode: 400, name: result.error.name, message: result.error };
        }

        return result.value;
    }

    static getInstance() {

        if( !instance ) {

            // future
            // if( process.env.VANDIUM_VALIDATION_PROVIDER !== 'lov' ) {
            //
            //     try {

                    // joi might not be present
                    //require( 'joi' );

                    // joi exists - use it
                    instance = require( './joi_provider' );
            //     }
            //     catch( err ) {
            //
            //     }
            // }
            //
            // // fall back to our joi provider
            // return require( './lov_provider' );
        }

        return instance;
    }
}

module.exports = ValidationProvider;
<commit_msg>reverted back to original code<commit_after>'use strict';

var instance;

class ValidationProvider {

    constructor( engine, types ) {

        this.engine = engine;

        this.types = types;
    }

    validate( values, schema, options ) {

        var result = this.engine.validate( values, schema, options );

        if( result.error ) {

            throw result.error;
        }

        return result.value;
    }

    static getInstance() {

        if( !instance ) {

            // future
            // if( process.env.VANDIUM_VALIDATION_PROVIDER !== 'lov' ) {
            //
            //     try {

                    // joi might not be present
                    //require( 'joi' );

                    // joi exists - use it
                    instance = require( './joi_provider' );
            //     }
            //     catch( err ) {
            //
            //     }
            // }
            //
            // // fall back to our joi provider
            // return require( './lov_provider' );
        }

        return instance;
    }
}

module.exports = ValidationProvider;
<|endoftext|>


<commit_before>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

// First add Base and a couple of other objects that are not automatically
// exported to exports (Numerical, Key, etc), then inject all exports into
// PaperScope, and create the initial paper object, all in one statement:
/*#*/ if (__options.environment == 'browser') {

paper = new (PaperScope.inject(Base.exports, {
	// Mark fields as enumeralbe so PaperScope.inject can pick them up
	enumerable: true,
	Base: Base,
	Numerical: Numerical,
	DomElement: DomElement,
	DomEvent: DomEvent,
	Http: Http,
	Key: Key
}))();

// Support AMD (e.g. require.js)
// Use named module AMD syntax since there are other unnamed calls to define()
// inside the built library (from inlined Acorn / Esprima) that apparently
// confuse the require.js optimizer.
if (typeof define === 'function' && define.amd)
	define('paper', paper);

/*#*/ } else if (__options.environment == 'node') {

paper = new (PaperScope.inject(Base.exports, {
	// Mark fields as enumeralbe so PaperScope.inject can pick them up
	enumerable: true,
	Base: Base,
	Numerical: Numerical,
	DomElement: DomElement,
	// Export dom/node.js stuff too
	XMLSerializer: XMLSerializer,
	DOMParser: DOMParser,
	Canvas: Canvas
}))();

// Export the paper scope.
module.exports = paper;

/*#*/ } // __options.environment == 'node'
<commit_msg>fix spelling mistakes.<commit_after>/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2014, Juerg Lehni & Jonathan Puckey
 * http://scratchdisk.com/ & http://jonathanpuckey.com/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */

// First add Base and a couple of other objects that are not automatically
// exported to exports (Numerical, Key, etc), then inject all exports into
// PaperScope, and create the initial paper object, all in one statement:
/*#*/ if (__options.environment == 'browser') {

paper = new (PaperScope.inject(Base.exports, {
	// Mark fields as enumerable so PaperScope.inject can pick them up
	enumerable: true,
	Base: Base,
	Numerical: Numerical,
	DomElement: DomElement,
	DomEvent: DomEvent,
	Http: Http,
	Key: Key
}))();

// Support AMD (e.g. require.js)
// Use named module AMD syntax since there are other unnamed calls to define()
// inside the built library (from inlined Acorn / Esprima) that apparently
// confuse the require.js optimizer.
if (typeof define === 'function' && define.amd)
	define('paper', paper);

/*#*/ } else if (__options.environment == 'node') {

paper = new (PaperScope.inject(Base.exports, {
	// Mark fields as enumerable so PaperScope.inject can pick them up
	enumerable: true,
	Base: Base,
	Numerical: Numerical,
	DomElement: DomElement,
	// Export dom/node.js stuff too
	XMLSerializer: XMLSerializer,
	DOMParser: DOMParser,
	Canvas: Canvas
}))();

// Export the paper scope.
module.exports = paper;

/*#*/ } // __options.environment == 'node'
<|endoftext|>


<commit_before>var express = require('express');
var async = require('async');
var api = express.Router();
var constants = require('../constants');
var config = require('../config');
var request = require('request');
var rc_secret = config.RECAPTCHA_SECRET_KEY;
var multer = require('multer')(
{
    inMemory: true,
    fileSize: 100 * 1024 * 1024, // no larger than 100mb
});
var queue = require('../store/queue');
var rQueue = queue.getQueue('request');
var queries = require('../store/queries');
var buildMatch = require('../store/buildMatch');
var buildPlayer = require('../store/buildPlayer');
var buildStatus = require('../store/buildStatus');
const crypto = require('crypto');
module.exports = function(db, redis, cassandra)
{
    api.get('/items', function(req, res)
    {
        res.json(constants.items[req.query.name]);
    });
    api.get('/abilities', function(req, res)
    {
        res.json(constants.abilities[req.query.name]);
    });
    api.get('/metadata', function(req, res, cb)
    {
        async.parallel(
        {
            banner: function(cb)
            {
                redis.get("banner", cb);
            },
            cheese: function(cb)
            {
                redis.get("cheese_goal", function(err, result)
                {
                    return cb(err,
                    {
                        cheese: result,
                        goal: config.GOAL
                    });
                });
            },
            user: function(cb)
            {
                cb(null, req.user);
            },
            navbar_pages: function(cb)
            {
                cb(null, constants.navbar_pages);
            },
            player_pages: function(cb)
            {
                cb(null, constants.player_pages);
            },
            match_pages: function(cb)
            {
                cb(null, constants.match_pages);
            },
            player_fields: function(cb)
            {
                cb(null, constants.player_fields);
            },
        }, function(err, result)
        {
            if (err)
            {
                return cb(err);
            }
            res.json(result);
        });
    });
    api.get('/matches/:match_id/:info?', function(req, res, cb)
    {
        buildMatch(
        {
            db: db,
            redis: redis,
            cassandra: cassandra,
            match_id: req.params.match_id
        }, function(err, match)
        {
            if (err)
            {
                return cb(err);
            }
            if (!match)
            {
                return cb();
            }
            res.json(match);
        });
    });
    api.get('/players/:account_id/:info?/:subkey?', function(req, res, cb)
    {
        buildPlayer(
        {
            db: db,
            redis: redis,
            cassandra: cassandra,
            account_id: req.params.account_id,
            info: req.params.info,
            subkey: req.params.subkey,
            query: req.query
        }, function(err, player)
        {
            if (err)
            {
                return cb(err);
            }
            if (!player)
            {
                return cb();
            }
            res.json(player);
        });
    });
    api.get('/distributions');
    api.get('/picks/:n');
    api.get('/rankings/:hero_id');
    api.get('/status', function(req, res, cb)
    {
        buildStatus(db, redis, function(err, status)
        {
            if (err)
            {
                return cb(err);
            }
            res.json(status);
        });
    });
    //TODO @albertcui owns mmstats
    api.get('/mmstats');
    api.get('/banner');
    api.get('/cheese', function(req, res)
    {
        //TODO implement this
        res.json(
        {
            cheese: 1,
            goal: 2
        });
    });
    api.get('/search', function(req, res, cb)
    {
        if (!req.query.q)
        {
            return cb(400);
        }
        queries.searchPlayer(db, req.query.q, function(err, result)
        {
            if (err)
            {
                return cb(err);
            }
            res.json(result);
        });
    });
    api.get('/health/:metric?', function(req, res, cb)
    {
        redis.hgetall('health', function(err, result)
        {
            if (err)
            {
                return cb(err);
            }
            for (var key in result)
            {
                result[key] = JSON.parse(result[key]);
            }
            if (!req.params.metric)
            {
                res.json(result);
            }
            else
            {
                var single = result[req.params.metric];
                var healthy = single.metric < single.threshold;
                res.status(healthy ? 200 : 500).json(single);
            }
        });
    });
    api.post('/request_job', multer.single("replay_blob"), function(req, res, next)
    {
        request.post("https://www.google.com/recaptcha/api/siteverify",
        {
            form:
            {
                secret: rc_secret,
                response: req.body.response
            }
        }, function(err, resp, body)
        {
            if (err)
            {
                return next(err);
            }
            try
            {
                body = JSON.parse(body);
            }
            catch (err)
            {
                return res.render(
                {
                    error: err
                });
            }
            var match_id = Number(req.body.match_id);
            var match;
            if (!body.success && config.ENABLE_RECAPTCHA && !req.file)
            {
                console.log('failed recaptcha');
                return res.json(
                {
                    error: "Recaptcha Failed!"
                });
            }
            else if (req.file)
            {
                console.log(req.file);
                //var key = req.file.originalname + Date.now();
                //var key = Math.random().toString(16).slice(2);
                const hash = crypto.createHash('md5');
                hash.update(req.file.buffer);
                var key = hash.digest('hex');
                redis.setex(new Buffer('upload_blob:' + key), 60 * 60, req.file.buffer);
                match = {
                    replay_blob_key: key
                };
            }
            else if (match_id && !Number.isNaN(match_id))
            {
                match = {
                    match_id: match_id
                };
            }
            if (match)
            {
                console.log(match);
                queue.addToQueue(rQueue, match,
                {
                    attempts: 1
                }, function(err, job)
                {
                    res.json(
                    {
                        error: err,
                        job:
                        {
                            jobId: job.jobId,
                            data: job.data
                        }
                    });
                });
            }
            else
            {
                res.json(
                {
                    error: "Invalid input."
                });
            }
        });
    });
    api.get('/request_job', function(req, res, cb)
    {
        rQueue.getJob(req.query.id).then(function(job)
        {
            if (job)
            {
                job.getState().then(function(state)
                {
                    return res.json(
                    {
                        jobId: job.jobId,
                        data: job.data,
                        state: state,
                        progress: job.progress()
                    });
                }).catch(cb);
            }
            else
            {
                res.json(
                {
                    state: "failed"
                });
            }
        }).catch(cb);
    });
    return api;
};
<commit_msg>remove some endpoints<commit_after>var express = require('express');
var async = require('async');
var api = express.Router();
var constants = require('../constants');
var config = require('../config');
var request = require('request');
var rc_secret = config.RECAPTCHA_SECRET_KEY;
var multer = require('multer')(
{
    inMemory: true,
    fileSize: 100 * 1024 * 1024, // no larger than 100mb
});
var queue = require('../store/queue');
var rQueue = queue.getQueue('request');
var queries = require('../store/queries');
var buildMatch = require('../store/buildMatch');
var buildPlayer = require('../store/buildPlayer');
var buildStatus = require('../store/buildStatus');
const crypto = require('crypto');
module.exports = function(db, redis, cassandra)
{
    api.get('/items', function(req, res)
    {
        res.json(constants.items[req.query.name]);
    });
    api.get('/abilities', function(req, res)
    {
        res.json(constants.abilities[req.query.name]);
    });
    api.get('/metadata', function(req, res, cb)
    {
        async.parallel(
        {
            banner: function(cb)
            {
                redis.get("banner", cb);
            },
            cheese: function(cb)
            {
                redis.get("cheese_goal", function(err, result)
                {
                    return cb(err,
                    {
                        cheese: result,
                        goal: config.GOAL
                    });
                });
            },
            user: function(cb)
            {
                cb(null, req.user);
            },
            navbar_pages: function(cb)
            {
                cb(null, constants.navbar_pages);
            },
            player_pages: function(cb)
            {
                cb(null, constants.player_pages);
            },
            match_pages: function(cb)
            {
                cb(null, constants.match_pages);
            },
            player_fields: function(cb)
            {
                cb(null, constants.player_fields);
            },
        }, function(err, result)
        {
            if (err)
            {
                return cb(err);
            }
            res.json(result);
        });
    });
    api.get('/matches/:match_id/:info?', function(req, res, cb)
    {
        buildMatch(
        {
            db: db,
            redis: redis,
            cassandra: cassandra,
            match_id: req.params.match_id
        }, function(err, match)
        {
            if (err)
            {
                return cb(err);
            }
            if (!match)
            {
                return cb();
            }
            res.json(match);
        });
    });
    api.get('/players/:account_id/:info?/:subkey?', function(req, res, cb)
    {
        buildPlayer(
        {
            db: db,
            redis: redis,
            cassandra: cassandra,
            account_id: req.params.account_id,
            info: req.params.info,
            subkey: req.params.subkey,
            query: req.query
        }, function(err, player)
        {
            if (err)
            {
                return cb(err);
            }
            if (!player)
            {
                return cb();
            }
            res.json(player);
        });
    });
    api.get('/distributions');
    api.get('/picks/:n');
    api.get('/rankings/:hero_id');
    api.get('/status', function(req, res, cb)
    {
        buildStatus(db, redis, function(err, status)
        {
            if (err)
            {
                return cb(err);
            }
            res.json(status);
        });
    });
    //TODO @albertcui owns mmstats
    api.get('/mmstats');
    api.get('/search', function(req, res, cb)
    {
        if (!req.query.q)
        {
            return cb(400);
        }
        queries.searchPlayer(db, req.query.q, function(err, result)
        {
            if (err)
            {
                return cb(err);
            }
            res.json(result);
        });
    });
    api.get('/health/:metric?', function(req, res, cb)
    {
        redis.hgetall('health', function(err, result)
        {
            if (err)
            {
                return cb(err);
            }
            for (var key in result)
            {
                result[key] = JSON.parse(result[key]);
            }
            if (!req.params.metric)
            {
                res.json(result);
            }
            else
            {
                var single = result[req.params.metric];
                var healthy = single.metric < single.threshold;
                res.status(healthy ? 200 : 500).json(single);
            }
        });
    });
    api.post('/request_job', multer.single("replay_blob"), function(req, res, next)
    {
        request.post("https://www.google.com/recaptcha/api/siteverify",
        {
            form:
            {
                secret: rc_secret,
                response: req.body.response
            }
        }, function(err, resp, body)
        {
            if (err)
            {
                return next(err);
            }
            try
            {
                body = JSON.parse(body);
            }
            catch (err)
            {
                return res.render(
                {
                    error: err
                });
            }
            var match_id = Number(req.body.match_id);
            var match;
            if (!body.success && config.ENABLE_RECAPTCHA && !req.file)
            {
                console.log('failed recaptcha');
                return res.json(
                {
                    error: "Recaptcha Failed!"
                });
            }
            else if (req.file)
            {
                console.log(req.file);
                //var key = req.file.originalname + Date.now();
                //var key = Math.random().toString(16).slice(2);
                const hash = crypto.createHash('md5');
                hash.update(req.file.buffer);
                var key = hash.digest('hex');
                redis.setex(new Buffer('upload_blob:' + key), 60 * 60, req.file.buffer);
                match = {
                    replay_blob_key: key
                };
            }
            else if (match_id && !Number.isNaN(match_id))
            {
                match = {
                    match_id: match_id
                };
            }
            if (match)
            {
                console.log(match);
                queue.addToQueue(rQueue, match,
                {
                    attempts: 1
                }, function(err, job)
                {
                    res.json(
                    {
                        error: err,
                        job:
                        {
                            jobId: job.jobId,
                            data: job.data
                        }
                    });
                });
            }
            else
            {
                res.json(
                {
                    error: "Invalid input."
                });
            }
        });
    });
    api.get('/request_job', function(req, res, cb)
    {
        rQueue.getJob(req.query.id).then(function(job)
        {
            if (job)
            {
                job.getState().then(function(state)
                {
                    return res.json(
                    {
                        jobId: job.jobId,
                        data: job.data,
                        state: state,
                        progress: job.progress()
                    });
                }).catch(cb);
            }
            else
            {
                res.json(
                {
                    state: "failed"
                });
            }
        }).catch(cb);
    });
    return api;
};
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var Base = require('./base')
  , utils = require('../utils');

/**
 * Expose `Markdown`.
 */

exports = module.exports = Markdown;

/**
 * Initialize a new `Markdown` reporter.
 *
 * @param {Runner} runner
 * @api public
 */

function Markdown(runner) {
  Base.call(this, runner);

  var self = this
    , stats = this.stats
    , total = runner.total
    , level = 0;

  function title(str) {
    return Array(level).join('#') + ' ' + str;
  }

  runner.on('suite', function(suite){
    ++level;
    process.stdout.write(title(suite.title) + '\n');
  });

  runner.on('suite end', function(suite){
    --level;
  });

  runner.on('pass', function(test){
    var code = utils.escape(clean(test.fn.toString()));
    process.stdout.write('\n ' + test.title + '.\n');
    process.stdout.write('\n```js');
    process.stdout.write(code + '\n');
    process.stdout.write('```\n\n');
  });
}

/**
 * Strip the function definition from `str`,
 * and re-indent for pre whitespace.
 */

function clean(str) {
  str = str
    .replace(/^function *\(.*\) *{/, '')
    .replace(/\s+\}$/, '');

  var spaces = str.match(/^\n?( *)/)[1].length
    , re = new RegExp('^ {' + spaces + '}', 'gm');

  str = str.replace(re, '');

  return str;
}<commit_msg>fixed escaping in markdown reporter<commit_after>
/**
 * Module dependencies.
 */

var Base = require('./base');

/**
 * Expose `Markdown`.
 */

exports = module.exports = Markdown;

/**
 * Initialize a new `Markdown` reporter.
 *
 * @param {Runner} runner
 * @api public
 */

function Markdown(runner) {
  Base.call(this, runner);

  var self = this
    , stats = this.stats
    , total = runner.total
    , level = 0;

  function title(str) {
    return Array(level).join('#') + ' ' + str;
  }

  runner.on('suite', function(suite){
    ++level;
    process.stdout.write(title(suite.title) + '\n');
  });

  runner.on('suite end', function(suite){
    --level;
  });

  runner.on('pass', function(test){
    var code = clean(test.fn.toString());
    process.stdout.write('\n ' + test.title + '.\n');
    process.stdout.write('\n```js');
    process.stdout.write(code + '\n');
    process.stdout.write('```\n\n');
  });
}

/**
 * Strip the function definition from `str`,
 * and re-indent for pre whitespace.
 */

function clean(str) {
  str = str
    .replace(/^function *\(.*\) *{/, '')
    .replace(/\s+\}$/, '');

  var spaces = str.match(/^\n?( *)/)[1].length
    , re = new RegExp('^ {' + spaces + '}', 'gm');

  str = str.replace(re, '');

  return str;
}<|endoftext|>