<commit_before>/*
Copyright 2006-2007, Open Source Applications Foundation

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

//Wait a specified number of milliseconds
windmill.controller.waits.sleep = function (paramObj, obj) {
  windmill.waiting = true;
  //if a number of milliseconds werent provided in a int format
  if ((paramObj.milliseconds == "") || (parseInt(paramObj.milliseconds, 10) == NaN)){
    paramObj.milliseconds = 5000;
  }

  done = function(){
    windmill.waiting = false;
    windmill.continueLoop();
    //we passed the id in the parms object of the action in the ide
    var aid = paramObj.aid;
    delete paramObj.aid;
    //set the result in the ide
    windmill.xhr.setWaitBgAndReport(aid,true,obj);
  }
  setTimeout('done()', paramObj.milliseconds);
};

windmill.controller.waits.forJS = function (paramObj, obj, pageLoad) {
  _this = this;

  //we passed the id in the parms object of the action in the ide
  var jsTest = windmill.jsTest;
  var aid = paramObj.aid;
  delete paramObj.aid;
  var count = 0;
  var p = paramObj || {};
  var timeout = 8000;
  var isJsTest = (p.origin == 'js');
  var jsCode = p.js || p.test;

  // If we get the weird string "NaN" (yes, the actual
  // string, "NaN" :)) value from the IDE, or some other
  // unusable string , just use the default value of 20 seconds
  if (p.timeout) {
    if (parseInt(p.timeout, 10) != NaN){
      timeout = p.timeout;
    }
  }

  //implement windmill safe waits
  //most browser javascript interpreters time out when the wait is greater than 60 seconds
  if ((windmill.safeWaits) && (timeout > 60000)){
    timeout = 60000;
  }

  //lookup method
  var lookup = function () {
    if (count >= timeout) {
      // JS tests -- report error and return control either to
      // the array-test loop, or the normal test loop, by calling
      // the passed-in callback
      if (isJsTest) {
        var msg = 'Wait timed out after ' + timeout + ' seconds.';
        jsTest.waitsCallback.call(jsTest, p.testName, new Error(msg));
        return;
      }
      else {
        if (pageLoad){
          windmill.loaded();
          windmill.continueLoop();
        }
        else { windmill.continueLoop(); }
      }
      windmill.xhr.setWaitBgAndReport(aid,false,obj);
      return false;
    }
    count += 100;

    // Get a result
    var result;
    try {
      if (typeof jsCode == 'string') {
        result = eval(jsCode);
      }
      else if (typeof jsCode == 'function' ||
          (fleegix.isIE && jsCode.toString().indexOf('function') == 0)) {
        result = jsCode();
      }
      else {
        throw new Error('waits.forJS js property must be a function, or string to eval.');
      }
    }
    catch (e) {
      // JS tests -- report error and return control either to
      // the array-test loop, or the normal test loop, by calling
      // the passed-in callback
      if (isJsTest) {
        jsTest.waitsCallback.call(jsTest, p.testName, e);
        return; // Don't keep looping! :)
      }
      else {
        throw e;
      }
    }
    result = !!result; // Make sure we've got a Boolean

    if (!result){ var x = setTimeout(lookup, 100); }
    else {
        c = function () {
          // JS tests -- return control either to the array-test loop,
          // or the normal test loop, by calling the passed-in callback
          if (isJsTest) {
            jsTest.waitsCallback.call(jsTest, p.testName);
          }
          else{
             if (pageLoad){ windmill.loaded(); }
             else{ windmill.continueLoop(); }
          }

           //set the result in the ide
           if (windmill.chatty){
             windmill.xhr.setWaitBgAndReport(aid,true,obj);
           }
        }
      if ((windmill.browser.isSafari) || (windmill.browser.current_ua.indexOf('firefox/2') != -1)){
        setTimeout(c, 1500);
      }
      else{ setTimeout(c, 800); }
    }
  }

  //start the looking up
  lookup();
};

windmill.controller.waits.forJSTrue = windmill.controller.waits.forJS;

//wait for an element to show up on the page
//if it doesn't after a provided timeout, defaults to 20 seconds
windmill.controller.waits.forElement = function (paramObj,obj) {
    var p = paramObj || {};
    var f = function () {
      try { return lookupNode(p); }
      catch(err){}
    };
    p.test = f;
    return windmill.controller.waits.forJS(p, obj);
};

//wait for an element to show up on the page
//if it doesn't after a provided timeout, defaults to 20 seconds
windmill.controller.waits.forElementProperty = function (paramObj,obj) {
    var p = paramObj || {};
    var vArray = p.option.split('|');

    //if there is a timeout
    if (vArray[2]){
      paramObj.timeout = vArray[3];
    }
    //function
    var f = function () {
      try {
        var node = lookupNode(p);
        var value = eval ('node.' + vArray[0]+';');

        if (value == vArray[1]){
          return true;
        }
      }
      catch(err){}
    };
    p.test = f;
    return windmill.controller.waits.forJS(p, obj);
};

//wait for an element to show up on the page
//if it doesn't after a provided timeout, defaults to 20 seconds
windmill.controller.waits.forNotElement = function (paramObj,obj) {
    var p = paramObj || {};
    var f = function () {
      try{
        var node = lookupNode(p);
        return !node;
      }
      catch(err){
        // looking up the node failed, so notElement is "true"
        return true;
      }
    };
    p.test = f;
    return windmill.controller.waits.forJS(p, obj);
};

//This is more of an internal function used by wait and click events
//To know when to try and reattach the listeners
//But if users wanted this manually they could use it
windmill.controller.waits.forPageLoad = function (paramObj,obj) {

  var p = paramObj || {};
  var sl = function(){
    var f = function () {
      //If the document.domain can't be accessed
      try {
        var v = windmill.testWin().document.domain;
      }catch(err){
        document.domain = windmill.docDomain;
      }
      //check to see if we can get the window body
      try {
        var d = windmill.testWin().document.body.style;
      }catch(err){ d = null;}

      if (d != null){
        return true;
      }
      return false;
    };
    p.test = f;

    return windmill.controller.waits.forJS(p, obj, true);
  }
  setTimeout(sl, 500);
  //we can't access the body, so now wait for the loading
  //setTimeout(sl, 0);
}

//wait for an element to show up on the page
//if it doesn't after a provided timeout, defaults to 20 seconds
windmill.controller.waits._forNotTitleAttach = function (paramObj, obj) {
    var p = paramObj || {};
    var f = function () {
      try {
        windmill.setEnv();
        if (windmill.testWin().document.title != p.title){
          var d = windmill.testWin().document.body.style;
          windmill.start();
          return true;
        }
        return false;
      } catch(err){
        return false;
      }
    };
    p.test = f;
    p.timeout = 60000;
    return windmill.controller.waits.forJS(p, obj, true);
};
<commit_msg>waits for JS should pull from the globally configurable timeout if it isn't passed in<commit_after>/*
Copyright 2006-2007, Open Source Applications Foundation

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

//Wait a specified number of milliseconds
windmill.controller.waits.sleep = function (paramObj, obj) {
  windmill.waiting = true;
  //if a number of milliseconds werent provided in a int format
  if ((paramObj.milliseconds == "") || (parseInt(paramObj.milliseconds, 10) == NaN)){
    paramObj.milliseconds = 5000;
  }

  done = function(){
    windmill.waiting = false;
    windmill.continueLoop();
    //we passed the id in the parms object of the action in the ide
    var aid = paramObj.aid;
    delete paramObj.aid;
    //set the result in the ide
    windmill.xhr.setWaitBgAndReport(aid,true,obj);
  }
  setTimeout('done()', paramObj.milliseconds);
};

windmill.controller.waits.forJS = function (paramObj, obj, pageLoad) {
  _this = this;

  //we passed the id in the parms object of the action in the ide
  var jsTest = windmill.jsTest;
  var aid = paramObj.aid;
  delete paramObj.aid;
  var count = 0;
  var p = paramObj || {};
  var timeout = windmill.timeout;
  var isJsTest = (p.origin == 'js');
  var jsCode = p.js || p.test;

  // If we get the weird string "NaN" (yes, the actual
  // string, "NaN" :)) value from the IDE, or some other
  // unusable string , just use the default value of 20 seconds
  if (p.timeout) {
    if (parseInt(p.timeout, 10) != NaN){
      timeout = p.timeout;
    }
  }

  //implement windmill safe waits
  //most browser javascript interpreters time out when the wait is greater than 60 seconds
  if ((windmill.safeWaits) && (timeout > 60000)){
    timeout = 60000;
  }

  //lookup method
  var lookup = function () {
    if (count >= timeout) {
      // JS tests -- report error and return control either to
      // the array-test loop, or the normal test loop, by calling
      // the passed-in callback
      if (isJsTest) {
        var msg = 'Wait timed out after ' + timeout + ' seconds.';
        jsTest.waitsCallback.call(jsTest, p.testName, new Error(msg));
        return;
      }
      else {
        if (pageLoad){
          windmill.loaded();
          windmill.continueLoop();
        }
        else { windmill.continueLoop(); }
      }
      windmill.xhr.setWaitBgAndReport(aid,false,obj);
      return false;
    }
    count += 100;

    // Get a result
    var result;
    try {
      if (typeof jsCode == 'string') {
        result = eval(jsCode);
      }
      else if (typeof jsCode == 'function' ||
          (fleegix.isIE && jsCode.toString().indexOf('function') == 0)) {
        result = jsCode();
      }
      else {
        throw new Error('waits.forJS js property must be a function, or string to eval.');
      }
    }
    catch (e) {
      // JS tests -- report error and return control either to
      // the array-test loop, or the normal test loop, by calling
      // the passed-in callback
      if (isJsTest) {
        jsTest.waitsCallback.call(jsTest, p.testName, e);
        return; // Don't keep looping! :)
      }
      else {
        throw e;
      }
    }
    result = !!result; // Make sure we've got a Boolean

    if (!result){ var x = setTimeout(lookup, 100); }
    else {
        c = function () {
          // JS tests -- return control either to the array-test loop,
          // or the normal test loop, by calling the passed-in callback
          if (isJsTest) {
            jsTest.waitsCallback.call(jsTest, p.testName);
          }
          else{
             if (pageLoad){ windmill.loaded(); }
             else{ windmill.continueLoop(); }
          }

           //set the result in the ide
           if (windmill.chatty){
             windmill.xhr.setWaitBgAndReport(aid,true,obj);
           }
        }
      if ((windmill.browser.isSafari) || (windmill.browser.current_ua.indexOf('firefox/2') != -1)){
        setTimeout(c, 1500);
      }
      else{ setTimeout(c, 800); }
    }
  }

  //start the looking up
  lookup();
};

windmill.controller.waits.forJSTrue = windmill.controller.waits.forJS;

//wait for an element to show up on the page
//if it doesn't after a provided timeout, defaults to 20 seconds
windmill.controller.waits.forElement = function (paramObj,obj) {
    var p = paramObj || {};
    var f = function () {
      try { return lookupNode(p); }
      catch(err){}
    };
    p.test = f;
    return windmill.controller.waits.forJS(p, obj);
};

//wait for an element to show up on the page
//if it doesn't after a provided timeout, defaults to 20 seconds
windmill.controller.waits.forElementProperty = function (paramObj,obj) {
    var p = paramObj || {};
    var vArray = p.option.split('|');

    //if there is a timeout
    if (vArray[2]){
      paramObj.timeout = vArray[3];
    }
    //function
    var f = function () {
      try {
        var node = lookupNode(p);
        var value = eval ('node.' + vArray[0]+';');

        if (value == vArray[1]){
          return true;
        }
      }
      catch(err){}
    };
    p.test = f;
    return windmill.controller.waits.forJS(p, obj);
};

//wait for an element to show up on the page
//if it doesn't after a provided timeout, defaults to 20 seconds
windmill.controller.waits.forNotElement = function (paramObj,obj) {
    var p = paramObj || {};
    var f = function () {
      try{
        var node = lookupNode(p);
        return !node;
      }
      catch(err){
        // looking up the node failed, so notElement is "true"
        return true;
      }
    };
    p.test = f;
    return windmill.controller.waits.forJS(p, obj);
};

//This is more of an internal function used by wait and click events
//To know when to try and reattach the listeners
//But if users wanted this manually they could use it
windmill.controller.waits.forPageLoad = function (paramObj,obj) {

  var p = paramObj || {};
  var sl = function(){
    var f = function () {
      //If the document.domain can't be accessed
      try {
        var v = windmill.testWin().document.domain;
      }catch(err){
        document.domain = windmill.docDomain;
      }
      //check to see if we can get the window body
      try {
        var d = windmill.testWin().document.body.style;
      }catch(err){ d = null;}

      if (d != null){
        return true;
      }
      return false;
    };
    p.test = f;

    return windmill.controller.waits.forJS(p, obj, true);
  }
  setTimeout(sl, 500);
  //we can't access the body, so now wait for the loading
  //setTimeout(sl, 0);
}

//wait for an element to show up on the page
//if it doesn't after a provided timeout, defaults to 20 seconds
windmill.controller.waits._forNotTitleAttach = function (paramObj, obj) {
    var p = paramObj || {};
    var f = function () {
      try {
        windmill.setEnv();
        if (windmill.testWin().document.title != p.title){
          var d = windmill.testWin().document.body.style;
          windmill.start();
          return true;
        }
        return false;
      } catch(err){
        return false;
      }
    };
    p.test = f;
    p.timeout = 60000;
    return windmill.controller.waits.forJS(p, obj, true);
};
<|endoftext|>


<commit_before>// Punctuation
// (Both ASCII and Japanese)
// http://www.localizingjapan.com/blog/2012/01/20/regular-expressions-for-japanese-text/
// Include full width characters?
// Exclude the -, ?, / marks, they're used in some dates
var puncRegex = /[!"#$%&()*+,.:;<=>@[\\\]^_`{|}~\u3000-\u303F]/g;

module.exports = {
    extraRules: [
        [/\bca\b|circa|c\s*\d/, function(match, date) {
            date.circa = true;
        }]
    ],

    dateRules: [
        [/(\d{4})s?[-\/](\d{4})(?:\s|$)/, function(match, date) {
            date.start = match[1];
            date.end = match[2];
        }],
        [/(\d{4}) (?:and|or|to|through) (\d{4})/, function(match, date) {
            date.start = match[1];
            date.end = match[2];
        }],
        [/(\d{4})s?[-\/](\d{4})s/, function(match, date) {
            date.start = match[1];
            date.end = match[2].substr(0, 3) + "9";
        }],
        [/(\d{4})s?[-\/](\d{2})s/, function(match, date) {
            date.start = match[1];
            date.end = match[1].substr(0, 2) +
                match[2].substr(2, 1) + "9";
        }],
        [/(\d{4})s?[-\/](\d{2})(?:\s|$)/, function(match, date) {
            date.start = match[1];
            date.end = match[1].substr(0, 2) + match[2];
        }],
        [/(\d{4})s/, function(match, date) {
            date.start = match[1];
            date.end = match[1].substr(0, 3) + "9";
        }],
        [/(\d{4})/, function(match, date) {
            date.start = match[1];
            date.end = match[1];
        }]
    ],

    setTestMode: function(mode) {
        this.dateRules.forEach(function(rule) {
            if (mode) {
                rule[0] = (new RegExp(rule[0].source
                    .replace(/\\d/g, "X")));
            } else {
                rule[0] = (new RegExp(rule[0].source
                    .replace(/X/g, "\\d")));
            }
        });
    },

    parse: function(str) {
        var date = {};
        str = this.cleanString(str);

        for (var i = 0; i < this.dateRules.length; i++) {
            var rule = this.dateRules[i];
            var match = rule[0].exec(str);
            if (match) {
                rule[1](match, date);

                for (var prop in date) {
                    if (typeof date[prop] === "string") {
                        date[prop] = parseFloat(date[prop]);
                    }
                }
                break;
            }
        }

        return date;
    },

    cleanString: function(str) {
        str = str.toLowerCase();
        str = this.stripPunctuation(str);
        return str;
    },

    stripPunctuation: function(str) {
        return str.replace(puncRegex, " ")
            // Convert 1820's to 1820s
            .replace(/(\d+)'s/g, "$1s")
            // Convert wide dash to hyphen
            .replace(/–/g, "-")
            // Strip out extra whitespace
            .replace(/\s+-\s+/g, "-")
            .replace(/\s+/, " ")
            .trim();
    }
};<commit_msg>Add in circa detection and detection of a few Xth century strings.<commit_after>// Punctuation
// (Both ASCII and Japanese)
// http://www.localizingjapan.com/blog/2012/01/20/regular-expressions-for-japanese-text/
// Include full width characters?
// Exclude the -, ?, / marks, they're used in some dates
var puncRegex = /[!"#$%&()*+,.:;<=>@[\\\]^_`{|}~\u3000-\u303F]/g;

module.exports = {
    extraRules: [
        [/\bca\b|circa|c\s*\d/, function(match, date) {
            date.circa = true;
        }]
    ],

    dateRules: [
        [/(\d{2})th[-\/](\d{2})th century/, function(match, date) {
            date.start = (parseFloat(match[1]) - 1) * 100;
            date.end = ((parseFloat(match[2]) - 1) * 100) + 99;
        }],
        [/(\d{2})th century/, function(match, date) {
            date.start = (parseFloat(match[1]) - 1) * 100;
            date.end = ((parseFloat(match[1]) - 1) * 100) + 99;
        }],
        [/(\d{4})s?[-\/](\d{4})(?:\s|$)/, function(match, date) {
            date.start = match[1];
            date.end = match[2];
        }],
        [/(\d{4}) (?:and|or|to|through) (\d{4})/, function(match, date) {
            date.start = match[1];
            date.end = match[2];
        }],
        [/(\d{4})s?[-\/](\d{4})s/, function(match, date) {
            date.start = match[1];
            date.end = match[2].substr(0, 3) + "9";
        }],
        [/(\d{4})s?[-\/](\d{2})s/, function(match, date) {
            date.start = match[1];
            date.end = match[1].substr(0, 2) +
                match[2].substr(2, 1) + "9";
        }],
        [/(\d{4})s?[-\/](\d{2})(?:\s|$)/, function(match, date) {
            date.start = match[1];
            date.end = match[1].substr(0, 2) + match[2];
        }],
        [/(\d{4})s/, function(match, date) {
            date.start = match[1];
            date.end = match[1].substr(0, 3) + "9";
        }],
        [/(\d{4})/, function(match, date) {
            date.start = match[1];
            date.end = match[1];
        }]
    ],

    setTestMode: function(mode) {
        this.dateRules.forEach(function(rule) {
            if (mode) {
                rule[0] = (new RegExp(rule[0].source
                    .replace(/\\d/g, "X")));
            } else {
                rule[0] = (new RegExp(rule[0].source
                    .replace(/X/g, "\\d")));
            }
        });
    },

    parse: function(str) {
        var date = {};
        str = this.cleanString(str);

        for (var i = 0; i < this.dateRules.length; i++) {
            var rule = this.dateRules[i];
            var match = rule[0].exec(str);
            if (match) {
                rule[1](match, date);

                for (var prop in date) {
                    if (typeof date[prop] === "string") {
                        date[prop] = parseFloat(date[prop]);
                    }
                }
                break;
            }
        }

        for (var i = 0; i < this.extraRules.length; i++) {
            var rule = this.extraRules[i];
            var match = rule[0].exec(str);
            if (match) {
                rule[1](match, date);
            }
        }

        return date;
    },

    cleanString: function(str) {
        str = str.toLowerCase();
        str = this.stripPunctuation(str);
        return str;
    },

    stripPunctuation: function(str) {
        return str.replace(puncRegex, " ")
            // Convert 1820's to 1820s
            .replace(/(\d+)'s/g, "$1s")
            // Convert wide dash to hyphen
            .replace(/–/g, "-")
            // Strip out extra whitespace
            .replace(/\s+-\s+/g, "-")
            .replace(/\s+/, " ")
            .trim();
    }
};<|endoftext|>


<commit_before>this.recline = this.recline || {};

// Models module following classic module pattern
recline.Model = function($) {

var my = {};

// A Dataset model.
//
// Other than standard list of Backbone attributes it has two important attributes:
//
// * currentDocuments: a DocumentList containing the Documents we have currently loaded for viewing (you update currentDocuments by calling getRows)
// * docCount: total number of documents in this dataset (obtained on a fetch for this Dataset)
my.Dataset = Backbone.Model.extend({
  __type__: 'Dataset',
  initialize: function() {
    this.currentDocuments = new my.DocumentList();
    this.docCount = null;
  },

  // AJAX method with promise API to get rows (documents) from the backend.
  //
  // Resulting DocumentList are used to reset this.currentDocuments and are
  // also returned.
  //
  // :param numRows: passed onto backend getDocuments.
  // :param start: passed onto backend getDocuments.
  //
  // this does not fit very well with Backbone setup. Backbone really expects you to know the ids of objects your are fetching (which you do in classic RESTful ajax-y world). But this paradigm does not fill well with data set up we have here.
  // This also illustrates the limitations of separating the Dataset and the Backend
  getDocuments: function(numRows, start) {
    var self = this;
    var dfd = $.Deferred();
    this.backend.getDocuments(this.id, numRows, start).then(function(rows) {
      var docs = _.map(rows, function(row) {
        return new my.Document(row);
      });
      self.currentDocuments.reset(docs);
      dfd.resolve(self.currentDocuments);
    });
    return dfd.promise();
  },

  toTemplateJSON: function() {
    var data = this.toJSON();
    data.docCount = this.docCount;
    return data;
  }
});

my.Document = Backbone.Model.extend({
  __type__: 'Document'
});

my.DocumentList = Backbone.Collection.extend({
  __type__: 'DocumentList',
  // webStore: new WebStore(this.url),
  model: my.Document
});

// Backends section
// ================

my.setBackend = function(backend) {
  Backbone.sync = backend.sync;
};

// Backend which just caches in memory
//
// Does not need to be a backbone model but provides some conveniences
my.BackendMemory = Backbone.Model.extend({
  // Initialize a Backend with a local in-memory dataset.
  //
  // NB: We can handle one and only one dataset at a time.
  //
  // :param dataset: the data for a dataset on which operations will be
  // performed. Its form should be a hash with metadata and data
  // attributes.
  //
  // - metadata: hash of key/value attributes of any kind (but usually with title attribute)
  // - data: hash with 2 keys:
  //  - headers: list of header names/labels
  //  - rows: list of hashes, each hash being one row. A row *must* have an id attribute which is unique.
  //
  //  Example of data:
  //
  //        {
  //            headers: ['x', 'y', 'z']
  //          , rows: [
  //              {id: 0, x: 1, y: 2, z: 3}
  //            , {id: 1, x: 2, y: 4, z: 6}
  //          ]
  //        };
  initialize: function(dataset) {
    // deep copy
    this._datasetAsData = $.extend(true, {}, dataset);
    _.bindAll(this, 'sync');
  },
  getDataset: function() {
    var dataset = new my.Dataset({
      id: this._datasetAsData.metadata.id
    });
    // this is a bit weird but problem is in sync this is set to parent model object so need to give dataset a reference to backend explicitly
    dataset.backend = this;
    return dataset;
  },
  sync: function(method, model, options) {
    var self = this;
    if (method === "read") {
      var dfd = $.Deferred();
      // this switching on object type is rather horrible
      // think may make more sense to do work in individual objects rather than in central Backbone.sync
      if (model.__type__ == 'Dataset') {
        var dataset = model;
        var rawDataset = this._datasetAsData;
        dataset.set(rawDataset.metadata);
        dataset.set({
          headers: rawDataset.data.headers
          });
        dataset.docCount = rawDataset.data.rows.length;
        dfd.resolve(dataset);
      }
      return dfd.promise();
    } else if (method === 'update') {
      var dfd = $.Deferred();
      if (model.__type__ == 'Document') {
        _.each(this._datasetAsData.data.rows, function(row, idx) {
          if(row.id === model.id) {
            self._datasetAsData.data.rows[idx] = model.toJSON();
          }
        });
        dfd.resolve(model);
      }
      return dfd.promise();
    } else if (method === 'delete') {
      var dfd = $.Deferred();
      if (model.__type__ == 'Document') {
        this._datasetAsData.data.rows = _.reject(this._datasetAsData.data.rows, function(row) {
          return (row.id === model.id);
        });
        dfd.resolve(model);
      }
      return dfd.promise();
    } else {
      alert('Not supported: sync on BackendMemory with method ' + method + ' and model ' + model);
    }
  },
  getDocuments: function(datasetId, numRows, start) {
    if (start === undefined) {
      start = 0;
    }
    if (numRows === undefined) {
      numRows = 10;
    }
    var dfd = $.Deferred();
    rows = this._datasetAsData.data.rows;
    var results = rows.slice(start, start+numRows);
    dfd.resolve(results);
    return dfd.promise();
 }
});

// Webstore Backend for connecting to the Webstore
//
// Designed to only attach to one dataset and one dataset only ...
// Could generalize to support attaching to different datasets
my.BackendWebstore = Backbone.Model.extend({
  // require url attribute in initialization data
  initialize: function() {
    this.webstoreTableUrl = this.get('url');
  },
  getDataset: function(id) {
    var dataset = new my.Dataset({
      id: id
    });
    dataset.backend = this;
    return dataset;
  },
  sync: function(method, model, options) {
    if (method === "read") {
      // this switching on object type is rather horrible
      // think may make more sense to do work in individual objects rather than in central Backbone.sync
      if (this.__type__ == 'Dataset') {
        var dataset = this;
        // get the schema and return
        var base = this.backend.get('url');
        var schemaUrl = base + '/schema.json';
        var jqxhr = $.ajax({
          url: schemaUrl,
          dataType: 'jsonp',
          jsonp: '_callback'
          });
        var dfd = $.Deferred();
        jqxhr.then(function(schema) {
          headers = _.map(schema.data, function(item) {
            return item.name;
          });
          dataset.set({
            headers: headers
          });
          dataset.docCount = schema.count;
          dfd.resolve(dataset, jqxhr);
        });
        return dfd.promise();
      }
    }
  },
  getDocuments: function(datasetId, numRows, start) {
    if (start === undefined) {
      start = 0;
    }
    if (numRows === undefined) {
      numRows = 10;
    }
    var base = this.get('url');
    var jqxhr = $.ajax({
      url: base + '.json',
      dataType: 'jsonp',
      jsonp: '_callback',
      cache: true
      });
    var dfd = $.Deferred();
    jqxhr.then(function(results) {
      dfd.resolve(results.data);
    });
    return dfd.promise();
 }
});

return my;

}(jQuery);

<commit_msg>[#8,Webstore][xs]: respect numDocs constraint in getDocuments.<commit_after>this.recline = this.recline || {};

// Models module following classic module pattern
recline.Model = function($) {

var my = {};

// A Dataset model.
//
// Other than standard list of Backbone attributes it has two important attributes:
//
// * currentDocuments: a DocumentList containing the Documents we have currently loaded for viewing (you update currentDocuments by calling getRows)
// * docCount: total number of documents in this dataset (obtained on a fetch for this Dataset)
my.Dataset = Backbone.Model.extend({
  __type__: 'Dataset',
  initialize: function() {
    this.currentDocuments = new my.DocumentList();
    this.docCount = null;
  },

  // AJAX method with promise API to get rows (documents) from the backend.
  //
  // Resulting DocumentList are used to reset this.currentDocuments and are
  // also returned.
  //
  // :param numRows: passed onto backend getDocuments.
  // :param start: passed onto backend getDocuments.
  //
  // this does not fit very well with Backbone setup. Backbone really expects you to know the ids of objects your are fetching (which you do in classic RESTful ajax-y world). But this paradigm does not fill well with data set up we have here.
  // This also illustrates the limitations of separating the Dataset and the Backend
  getDocuments: function(numRows, start) {
    var self = this;
    var dfd = $.Deferred();
    this.backend.getDocuments(this.id, numRows, start).then(function(rows) {
      var docs = _.map(rows, function(row) {
        return new my.Document(row);
      });
      self.currentDocuments.reset(docs);
      dfd.resolve(self.currentDocuments);
    });
    return dfd.promise();
  },

  toTemplateJSON: function() {
    var data = this.toJSON();
    data.docCount = this.docCount;
    return data;
  }
});

my.Document = Backbone.Model.extend({
  __type__: 'Document'
});

my.DocumentList = Backbone.Collection.extend({
  __type__: 'DocumentList',
  // webStore: new WebStore(this.url),
  model: my.Document
});

// Backends section
// ================

my.setBackend = function(backend) {
  Backbone.sync = backend.sync;
};

// Backend which just caches in memory
//
// Does not need to be a backbone model but provides some conveniences
my.BackendMemory = Backbone.Model.extend({
  // Initialize a Backend with a local in-memory dataset.
  //
  // NB: We can handle one and only one dataset at a time.
  //
  // :param dataset: the data for a dataset on which operations will be
  // performed. Its form should be a hash with metadata and data
  // attributes.
  //
  // - metadata: hash of key/value attributes of any kind (but usually with title attribute)
  // - data: hash with 2 keys:
  //  - headers: list of header names/labels
  //  - rows: list of hashes, each hash being one row. A row *must* have an id attribute which is unique.
  //
  //  Example of data:
  //
  //        {
  //            headers: ['x', 'y', 'z']
  //          , rows: [
  //              {id: 0, x: 1, y: 2, z: 3}
  //            , {id: 1, x: 2, y: 4, z: 6}
  //          ]
  //        };
  initialize: function(dataset) {
    // deep copy
    this._datasetAsData = $.extend(true, {}, dataset);
    _.bindAll(this, 'sync');
  },
  getDataset: function() {
    var dataset = new my.Dataset({
      id: this._datasetAsData.metadata.id
    });
    // this is a bit weird but problem is in sync this is set to parent model object so need to give dataset a reference to backend explicitly
    dataset.backend = this;
    return dataset;
  },
  sync: function(method, model, options) {
    var self = this;
    if (method === "read") {
      var dfd = $.Deferred();
      // this switching on object type is rather horrible
      // think may make more sense to do work in individual objects rather than in central Backbone.sync
      if (model.__type__ == 'Dataset') {
        var dataset = model;
        var rawDataset = this._datasetAsData;
        dataset.set(rawDataset.metadata);
        dataset.set({
          headers: rawDataset.data.headers
          });
        dataset.docCount = rawDataset.data.rows.length;
        dfd.resolve(dataset);
      }
      return dfd.promise();
    } else if (method === 'update') {
      var dfd = $.Deferred();
      if (model.__type__ == 'Document') {
        _.each(this._datasetAsData.data.rows, function(row, idx) {
          if(row.id === model.id) {
            self._datasetAsData.data.rows[idx] = model.toJSON();
          }
        });
        dfd.resolve(model);
      }
      return dfd.promise();
    } else if (method === 'delete') {
      var dfd = $.Deferred();
      if (model.__type__ == 'Document') {
        this._datasetAsData.data.rows = _.reject(this._datasetAsData.data.rows, function(row) {
          return (row.id === model.id);
        });
        dfd.resolve(model);
      }
      return dfd.promise();
    } else {
      alert('Not supported: sync on BackendMemory with method ' + method + ' and model ' + model);
    }
  },
  getDocuments: function(datasetId, numRows, start) {
    if (start === undefined) {
      start = 0;
    }
    if (numRows === undefined) {
      numRows = 10;
    }
    var dfd = $.Deferred();
    rows = this._datasetAsData.data.rows;
    var results = rows.slice(start, start+numRows);
    dfd.resolve(results);
    return dfd.promise();
 }
});

// Webstore Backend for connecting to the Webstore
//
// Designed to only attach to one dataset and one dataset only ...
// Could generalize to support attaching to different datasets
my.BackendWebstore = Backbone.Model.extend({
  // require url attribute in initialization data
  initialize: function() {
    this.webstoreTableUrl = this.get('url');
  },
  getDataset: function(id) {
    var dataset = new my.Dataset({
      id: id
    });
    dataset.backend = this;
    return dataset;
  },
  sync: function(method, model, options) {
    if (method === "read") {
      // this switching on object type is rather horrible
      // think may make more sense to do work in individual objects rather than in central Backbone.sync
      if (this.__type__ == 'Dataset') {
        var dataset = this;
        // get the schema and return
        var base = this.backend.get('url');
        var schemaUrl = base + '/schema.json';
        var jqxhr = $.ajax({
          url: schemaUrl,
          dataType: 'jsonp',
          jsonp: '_callback'
          });
        var dfd = $.Deferred();
        jqxhr.then(function(schema) {
          headers = _.map(schema.data, function(item) {
            return item.name;
          });
          dataset.set({
            headers: headers
          });
          dataset.docCount = schema.count;
          dfd.resolve(dataset, jqxhr);
        });
        return dfd.promise();
      }
    }
  },
  getDocuments: function(datasetId, numRows, start) {
    if (start === undefined) {
      start = 0;
    }
    if (numRows === undefined) {
      numRows = 10;
    }
    var base = this.get('url');
    var jqxhr = $.ajax({
      url: base + '.json?_limit=' + numRows,
      dataType: 'jsonp',
      jsonp: '_callback',
      cache: true
      });
    var dfd = $.Deferred();
    jqxhr.then(function(results) {
      dfd.resolve(results.data);
    });
    return dfd.promise();
 }
});

return my;

}(jQuery);

<|endoftext|>


<commit_before>//IMPORTS
var Twit = require("twit");
var timer = require("timer");
var mongodb = require("mongodb");
var Geode =require('geode');
var conf = require('./config');
var util = require('util')
var io = require('socket.io').listen(conf.sockets.port-1); // temp for test

module.exports = function(con, bd, twit) {

   // Twitter credentials
   var T = new Twit(twit["watchFireZar"]);

   // Twitter rates
   var time = 15000*60, maxRate = 180, pending;

   // Tweet class definition
   function Tweet(user, text, coordinates) {
      this.user = user;
      this.text = text;
      this.coordinates = coordinates;
   }

   // City properties
   function City(id, area, coordinates, countryCode) {
      this.id = id;
      this.coordinates = coordinates;
      this.noise = 0;
      this.area = area;
      this.tweets = [];
      this.countryCode = countryCode;
   }

   // Extract city names from hotspots
   function parseHotSpots(cities, hotspots, callback) {
      var geo = new Geode('watchFire', {language: 'en', country : 'US'});
      var p, name, code, pending = hotspots.length;
      for (var i in hotspots) {
         p = hotspots[i];
         geo.findNearby({lat:p.coordinates.coordinates[1], lng:p.coordinates.coordinates[0]}, function(err, results) {
            if (!err && results.geonames) {
               name = results.geonames[0].name;
               code = results.geonames[0].countryCode;
               cities[name] = new City(p._id, round(p.coordinates.coordinates), p.coordinates, code);
            }
            if (pending--) {
               callback(cities);
            }
         });
      }
   }

   // Open twitter stream listening for all cities with hotspots
   function openTwitterStreams(cities) {

      // Define watch symbols to search on twitter
      var watchSymbols = [], tweet, keyword;
      for (var city in cities) {
         if (cities[city].countryCode in conf.keywords) {
            keyword = conf.keywords[cities[city].countryCode]+" "+city;
         } else {
            keyword = "fire "+city;
         }

         // Query and future regexp for streaming
         watchSymbols.push(keyword);
         cities[city].regexp = new RegExp(city, "gi");

         // Buff tweets related to hotspot in this city
         if (pending > 0) {
            pending--;
            T.get('search/tweets', {q: symbol, count: 100}, function(err, reply) {
               if (err) { console.log(err); return }
               var t, tweet;
               for (t in reply.statuses) {
                  tweet = reply.statuses[t];
                  cities[city].tweets.push(new Tweet(tweet.user.screen_name, tweet.text, tweet.coordinates||cities[city].coordinates));
               }
               cities[city].noise += reply.statuses.length;
            });
         }
      }

      // Once the initial search is done, we connect to streaming API
      this.stream = T.stream("statuses/filter", {track: watchSymbols.toString()});
      this.stream.on("tweet", function(t) {
         console.log(" >>> received tweet: " + t.text);
         var tweet, c;
         for (c in cities) {
            // Since we are listening in a single stream for every hotspot, we need to
            // filter and find the correct one.
            if (t.text.match(cities[c].regexp)) {
               tweet = new Tweet(t.user.screen_name, t.text, t.coordinates||cities[c].coordinates);
               // if we want to buff more tweets, this is the place
               // Emit tweet to appropiate listener
               io.sockets.emit("tweet"+cities[c].id, tweet);
               cities[city].noise++;
               break;
            }
         }
      });
   }

   // Update noise to database
   var notify = function(coord, noise) {
//	   FIXME:
//      new mongodb.Collection(con, bd.HOT_SPOTS).update({coordenadas:coord}, {$inc:{noise: noise}});
   }

   // Checks social noise
   var checkNoise = function(cities) {
      console.log("  checking noise...")
      for (var i in cities) {
         if (cities[i].noise > 20) {
            notify(cities[i].coordinates, cities[i].noise);
         }
      }
   }

   // Create a surface from coordinates
   var round = function(coords) {
      var c = 0.5;
      return [Math.floor(coords[0]*10)/10-c, Math.floor(coords[1]*10)/10-c, Math.floor(coords[0]*10)/10+c, Math.floor(coords[0]*10)/10+c];
   }

   // Return object
   return {
      cities : {},
      init : function(hotspots) {
         console.log("init twitta");
         var that = this;
         this.destroy();
         // Starts structures
         parseHotSpots(this.cities, hotspots, openTwitterStreams);
         // Check if has been enought noise about a hotspot
         this.checker = setInterval(checkNoise, 20000, that.cities);
         // Periodically reset number of tweets we can send
         this.rates = setInterval(function(){pending = maxRate}, time);
         // Set and open sockets
         io.configure(function(){io.set('resource','/tweets')});
         io.on('connection', function(client) {
            // This socket return tweets based on a point
            client.on('fire', function(data) {
               // emit this.cities[city].tweets
               console.log(data);
            });
         });
      },
      destroy : function() {
         clearInterval(this.checker);
         if (this.stream) this.stream.close();
      },
      rates : null,
      checker : null,
      stream : null
   }

}
<commit_msg>add callbacks join before watchSymbols<commit_after>//IMPORTS
var Twit = require("twit");
var timer = require("timer");
var mongodb = require("mongodb");
var Geode =require('geode');
var conf = require('./config');
var util = require('util')
var io = require('socket.io').listen(conf.sockets.port-1); // temp for test

module.exports = function(con, bd, twit) {

   // Twitter credentials
   var T = new Twit(twit["watchFireZar"]);

   // Twitter rates
   var time = 15000*60, maxRate = 180, pendingRequests;

   // Tweet class definition
   function Tweet(user, text, coordinates) {
      this.user = user;
      this.text = text;
      this.coordinates = coordinates;
   }

   // City properties
   function City(id, area, coordinates, countryCode) {
      this.id = id;
      this.coordinates = coordinates;
      this.noise = 0;
      this.area = area;
      this.tweets = [];
      this.countryCode = countryCode;
   }

   // Extract city names from hotspots
   function parseHotSpots(cities, hotspots, callback) {
      var geo = new Geode('watchFire', {language: 'en', country : 'US'});
      var p, name, code, pending = hotspots.length;
      for (var i in hotspots) {
         p = hotspots[i];
         geo.findNearby({lat:p.coordinates.coordinates[1], lng:p.coordinates.coordinates[0]}, function(err, results) {
            if (!err && results.geonames) {
               name = results.geonames[0].name;
               code = results.geonames[0].countryCode;
               cities[name] = new City(p._id, round(p.coordinates.coordinates), p.coordinates, code);
            }
            if (pending--) {
               callback(cities);
            }
         });
      }
   }

   // Open twitter stream listening for all cities with hotspots
   function openTwitterStreams(cities) {

      // Define watch symbols to search on twitter
      var watchSymbols = [], tweet, keyword;
      for (var city in cities) {
         if (cities[city].countryCode in conf.keywords) {
            keyword = conf.keywords[cities[city].countryCode]+" "+city;
         } else {
            keyword = "fire "+city;
         }

         // Query and future regexp for streaming
         watchSymbols.push(keyword);
         cities[city].regexp = new RegExp(city, "gi");

         // Buff tweets related to hotspot in this city
         if (pendingRequests > 0) {
            pendingRequests--;
            T.get('search/tweets', {q: symbol, count: 100}, function(err, reply) {
               if (err) { console.log(err); return }
               var t, tweet;
               for (t in reply.statuses) {
                  tweet = reply.statuses[t];
                  cities[city].tweets.push(new Tweet(tweet.user.screen_name, tweet.text, tweet.coordinates||cities[city].coordinates));
               }
               cities[city].noise += reply.statuses.length;
            });
         }

         // We need to join for callbaks
         if (watchSymbols.length == cities.length) {
            // Once the initial search is done, we connect to streaming API
            this.stream = T.stream("statuses/filter", {track: watchSymbols.toString()});
            this.stream.on("tweet", function(t) {
               console.log(" >>> received tweet: " + t.text);
               var tweet, c;
               for (c in cities) {
                  // Since we are listening in a single stream for every hotspot, we need to
                  // filter and find the correct one.
                  if (t.text.match(cities[c].regexp)) {
                     tweet = new Tweet(t.user.screen_name, t.text, t.coordinates||cities[c].coordinates);
                     // if we want to buff more tweets, this is the place
                     // Emit tweet to appropiate listener
                     io.sockets.emit("tweet"+cities[c].id, tweet);
                     cities[city].noise++;
                     break;
                  }
               }
            });
         }
      }

   }

   // Update noise to database
   var notify = function(coord, noise) {
//	   FIXME:
//      new mongodb.Collection(con, bd.HOT_SPOTS).update({coordenadas:coord}, {$inc:{noise: noise}});
   }

   // Checks social noise
   var checkNoise = function(cities) {
      console.log("  checking noise...")
      for (var i in cities) {
         if (cities[i].noise > 20) {
            notify(cities[i].coordinates, cities[i].noise);
         }
      }
   }

   // Create a surface from coordinates
   var round = function(coords) {
      var c = 0.5;
      return [Math.floor(coords[0]*10)/10-c, Math.floor(coords[1]*10)/10-c, Math.floor(coords[0]*10)/10+c, Math.floor(coords[0]*10)/10+c];
   }

   // Return object
   return {
      cities : {},
      init : function(hotspots) {
         console.log("init twitta");
         var that = this;
         this.destroy();
         // Starts structures
         parseHotSpots(this.cities, hotspots, openTwitterStreams);
         // Check if has been enought noise about a hotspot
         this.checker = setInterval(checkNoise, 20000, that.cities);
         // Periodically reset number of tweets we can send
         this.rates = setInterval(function(){pendingRequests = maxRate}, time);
         // Set and open sockets
         io.configure(function(){io.set('resource','/tweets')});
         io.on('connection', function(client) {
            // This socket return tweets based on a point
            client.on('fire', function(data) {
               // emit this.cities[city].tweets
               console.log(data);
            });
         });
      },
      destroy : function() {
         clearInterval(this.checker);
         if (this.stream) this.stream.close();
      },
      rates : null,
      checker : null,
      stream : null
   }

}
<|endoftext|>


<commit_before>/** MODULE INTERFACE
 *@method {function} -
 */
module.exports = {
    createRelationships: createRelationships
};

/*----------------------------------------------------------------------------*/

/** Creates an object containing all the possible neighbor relationships of a zone
 * @param {object} neighbors -
 * @param {function} changeGetterSetter -
 * @returns {object} neighborRelationships -
 */
function createRelationships(neighbors, changeGetterSetter) {
    function createNeighbor(location) {
        var neighbor = neighbors[location] || { port: 0 };
        neighbor = changeGetterSetter('neighbor', location, neighbor);
        // return neighbor;
        return {
            value: Object.create({}, {
                server: neighbor
            })
        };
    }

    var neighborRelationships = {
        // XY plane, lower Z
        'xl-yl-zl': createNeighbor('xl-yl-zl'),
        'xl-ym-zl': createNeighbor('xl-ym-zl'),
        'xl-yh-zl': createNeighbor('xl-yh-zl'),
        'xm-yl-zl': createNeighbor('xm-yl-zl'),
        'xm-ym-zl': createNeighbor('xm-ym-zl'),
        'xm-yh-zl': createNeighbor('xm-yh-zl'),
        'xh-yl-zl': createNeighbor('xh-yl-zl'),
        'xh-ym-zl': createNeighbor('xh-ym-zl'),
        'xh-yh-zl': createNeighbor('xh-yh-zl'),
        // XY plane, middle Z
        'xl-yl-zm': createNeighbor('xl-yl-zm'),
        'xl-ym-zm': createNeighbor('xl-ym-zm'),
        'xl-yh-zm': createNeighbor('xl-yh-zm'),
        'xm-yl-zm': createNeighbor('xm-yl-zm'),
        // 'xm-ym-zm': not included because it is the zone itself
        'xm-yh-zm': createNeighbor('xm-yh-zm'),
        'xh-yl-zm': createNeighbor('xh-yl-zm'),
        'xh-ym-zm': createNeighbor('xh-ym-zm'),
        'xh-yh-zm': createNeighbor('xh-yh-zm'),
        // XY plane, higher Z
        'xl-yl-zh': createNeighbor('xl-yl-zh'),
        'xl-ym-zh': createNeighbor('xl-ym-zh'),
        'xl-yh-zh': createNeighbor('xl-yh-zh'),
        'xm-yl-zh': createNeighbor('xm-yl-zh'),
        'xm-ym-zh': createNeighbor('xm-ym-zh'),
        'xm-yh-zh': createNeighbor('xm-yh-zh'),
        'xh-yl-zh': createNeighbor('xh-yl-zh'),
        'xh-ym-zh': createNeighbor('xh-ym-zh'),
        'xh-yh-zh': createNeighbor('xh-yh-zh'),
    };

    return neighborRelationships;
}<commit_msg>Replaced the default neighbor value for null<commit_after>/** MODULE INTERFACE
 *@method {function} -
 */
module.exports = {
    createRelationships: createRelationships
};

/*----------------------------------------------------------------------------*/

/** Creates an object containing all the possible neighbor relationships of a zone
 * @param {object} neighbors -
 * @param {function} changeGetterSetter -
 * @returns {object} neighborRelationships -
 */
function createRelationships(neighbors, changeGetterSetter) {
    function createNeighbor(location) {
        var neighbor = neighbors[location] || null;
        neighbor = changeGetterSetter('neighbor', location, neighbor);
        // return neighbor;
        return {
            value: Object.create({}, {
                server: neighbor
            })
        };
    }

    var neighborRelationships = {
        // XY plane, lower Z
        'xl-yl-zl': createNeighbor('xl-yl-zl'),
        'xl-ym-zl': createNeighbor('xl-ym-zl'),
        'xl-yh-zl': createNeighbor('xl-yh-zl'),
        'xm-yl-zl': createNeighbor('xm-yl-zl'),
        'xm-ym-zl': createNeighbor('xm-ym-zl'),
        'xm-yh-zl': createNeighbor('xm-yh-zl'),
        'xh-yl-zl': createNeighbor('xh-yl-zl'),
        'xh-ym-zl': createNeighbor('xh-ym-zl'),
        'xh-yh-zl': createNeighbor('xh-yh-zl'),
        // XY plane, middle Z
        'xl-yl-zm': createNeighbor('xl-yl-zm'),
        'xl-ym-zm': createNeighbor('xl-ym-zm'),
        'xl-yh-zm': createNeighbor('xl-yh-zm'),
        'xm-yl-zm': createNeighbor('xm-yl-zm'),
        // 'xm-ym-zm': not included because it is the zone itself
        'xm-yh-zm': createNeighbor('xm-yh-zm'),
        'xh-yl-zm': createNeighbor('xh-yl-zm'),
        'xh-ym-zm': createNeighbor('xh-ym-zm'),
        'xh-yh-zm': createNeighbor('xh-yh-zm'),
        // XY plane, higher Z
        'xl-yl-zh': createNeighbor('xl-yl-zh'),
        'xl-ym-zh': createNeighbor('xl-ym-zh'),
        'xl-yh-zh': createNeighbor('xl-yh-zh'),
        'xm-yl-zh': createNeighbor('xm-yl-zh'),
        'xm-ym-zh': createNeighbor('xm-ym-zh'),
        'xm-yh-zh': createNeighbor('xm-yh-zh'),
        'xh-yl-zh': createNeighbor('xh-yl-zh'),
        'xh-ym-zh': createNeighbor('xh-ym-zh'),
        'xh-yh-zh': createNeighbor('xh-yh-zh'),
    };

    return neighborRelationships;
}<|endoftext|>


<commit_before>/**
 * New conception of audio player for web.
 *
 * @author Yauheni Pakala
 * @copyright 2017 MIT License
 * @version 0.1.0
 */
(function (_w, _d) {
	'use strict';

	// consts

	var MUZUS_SELECTOR = '.muzus',
		MUZUS_PLAY = 'muzus-play',
		MUZUS_PAUSE = 'muzus-pause',
		MUZUS_TRACK = 'muzus-track',
		MUZUS_PROGRESS = 'muzus-progress',
		MUZUS_PROGRESS_TIME_HINT = 'muzus-progress-time-hint',
		TRACK_ERROR = -1,
		TRACK_STOPED = 0,
		TRACK_PLAYING = 1,
		TRACK_PAUSED = 2;

	// helpers

	function toFormatedString (seconds) {
		var h = parseInt(seconds / 60 / 60),
			m = parseInt(seconds / 60 % 60),
			s = parseInt(seconds % 60);

		return (h ? h + ':' : '') + ((h && (m < 10)) ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
	}

	function createElement (tagName, className, parentElement) {
		var e = _d.createElement(tagName);
		e.className = className;
		if (typeof parentElement !== 'undefined') {
			parentElement.appendChild(e);
		}
		return e;
	}

	function createRangeElement (className, parentElement) {
		var e = createElement('input', className, parentElement);
		e.type = 'range';
		e.max = 100;
		e.min = 0;
		e.step = 0.01;
		e.value = 0;
		return e;
	}

	function createAudioElement () {
		var e = createElement('audio');
		e.preload = 'metadata';
		e.type = 'audio/mpeg';
		e.volume = 1;
		return e;
	}

	// classes

	function Player (element) {

		// private

		var _currentTrack = null,
			_trackList = [],
			_options = getPlayerOptionsFromElement(element),
			_player = createAudioElement();

		// setup player

		_player.onplaying = function () {
			_currentTrack.setEndTime(_player.duration);
		};
		_player.ontimeupdate = function () {
			if (_player.duration > 0) {
				_currentTrack.setProgress((_player.currentTime / _player.duration) * 100);
				_currentTrack.setCurrentTime(_player.currentTime);
			}
		};
		_player.onprogress = function () {
			if (_player.duration > 0) {
				var value = (_player.buffered.end(_player.buffered.length - 1) / _player.duration) * 100;
				_currentTrack.setBuffer(value);
			}
		};
		_player.onended = nextTrack;
		_player.onerror = function (e) {
			_currentTrack.error(e);
			stopPlayer();
			_currentTrack = null;
		};

		// TODO:
		var trackElements = element.querySelectorAll('a');
		for (var i = 0; i < trackElements.length; i++) {
			var trackElement = trackElements[i];
			var track = new Track(i, trackElement);
			track.setClickHandler(trackClickHandler);
			track.setChangeProgressHandler(trackProgressChangedHandler);

			_trackList.push(track);

			preloadTrack(track);
		}

		// private methods

		function trackClickHandler (track) {
			switch (track.getState()) {
				case TRACK_PLAYING:
					_currentTrack.pause();
					_player.pause();
				break;
				case TRACK_PAUSED:
					_currentTrack.play();
					_player.play();
				break;
				case TRACK_ERROR:
					return;
				break;
				default:
					startPlayTrack(track);
				break;
			}
		}

		function trackProgressChangedHandler (value) {
			if (_player.duration) {
				_player.currentTime = (value * _player.duration) / 100;
			} else {
				value = 0;
			}
		}

		function nextTrack () {
			var currentTrackIndex = _currentTrack.id,
				nextTrackIndex = currentTrackIndex < _trackList.length - 1 ? currentTrackIndex + 1 : 0;

			if (_trackList.length == 1) {
				stopPlayer();
				return;
			}
			if (nextTrackIndex < currentTrackIndex && !_options.isRepeat) {
				stopPlayer();
				return;
			}

			startPlayTrack(_trackList[nextTrackIndex]);
		}

		function startPlayTrack (track) {
			if (!!_currentTrack) {
				_currentTrack.stop();
			}
			_currentTrack = track;

			if (track.getState() === TRACK_ERROR)
			{
				nextTrack();
				return;
			}

			_player.src = _currentTrack.src;
			_currentTrack.play();
			_player.play();
		}

		function stopPlayer () {
			_player.pause();
			_player.currentTime = 0;

			_currentTrack.stop();
		}

		function preloadTrack (track) {
			var preloader = createAudioElement();
			preloader.volume = 0;
			preloader.src = track.src;
			preloader.onplaying = function () {
				preloader.pause();
				track.setCurrentTime(0);
				track.setEndTime(preloader.duration);
				preloader = null;
			};
			preloader.onerror = track.error;
			_w.setTimeout(function () {
				preloader.play();
			}, 100);
		}

		function getPlayerOptionsFromElement (playerElement) {
			return {
				isRepeatEnabled: playerElement.getAttribute('data-repeat') || false
			}
		}
	}

	function Track (id, element) {

		var _titleHtml = element.innerHTML,
			_src = element.href;

		// replace element

		var newElement = createElement('div', MUZUS_TRACK);
		element.parentNode.replaceChild(newElement, element);

		// private

		var _currentState = TRACK_STOPED,
			_duration = 0,
			_infoRow = createElement('div', 'muzus-info', newElement),
			_playButtonWrapper = createElement('span', 'muzus-play-wrapper', _infoRow),
			_playButton = createElement('span', MUZUS_PLAY, _playButtonWrapper),
			_titleLabel = createElement('span', 'muzus-title', _infoRow),
			_timeBlock = createElement('span', 'muzus-time', _infoRow),
			_currentTimeLabel = createElement('span', 'muzus-time-current', _timeBlock),
			_endTimeLabel = createElement('span', 'muzus-time-end', _timeBlock),
			_progressBlock = createElement('div', MUZUS_PROGRESS + ' muzus-progress-hide', newElement),
			_progressBuffer = createElement('div', 'muzus-progress-buffer', _progressBlock),
			_progressProcess = createElement('div', 'muzus-progress-process', _progressBlock),
			_progressSpinner = createRangeElement('muzus-progress-spinner', _progressBlock),
			_progressTimeHint = createElement('div', MUZUS_PROGRESS_TIME_HINT, _progressBlock),
			_self = {};

		// public

		_self.id = id;
		_self.src = _src;
		_self.play = function () {
			if (_currentState === TRACK_ERROR) return;

			_currentState = TRACK_PLAYING;
			newElement.className = MUZUS_TRACK + ' muzus-track-active';
			_playButton.className = MUZUS_PAUSE;
			_progressBlock.className = MUZUS_PROGRESS;
		};
		_self.pause = function () {
			if (_currentState === TRACK_ERROR) return;

			_currentState = TRACK_PAUSED;
			newElement.className = MUZUS_TRACK + ' muzus-track-paused';
			_playButton.className = MUZUS_PLAY;
		};
		_self.stop = function () {
			if (_currentState === TRACK_ERROR) return;

			_currentState = TRACK_STOPED;
			newElement.className = MUZUS_TRACK;
			_playButton.className = MUZUS_PLAY;
			_progressBlock.className = MUZUS_PROGRESS + ' muzus-progress-hide';

			_self.setCurrentTime(0);
			_self.setProgress(0);
			_self.setBuffer(0);
			_self.hideProgressTimeHint();
		};
		_self.getState = function () {
			return _currentState;
		};
		_self.setCurrentTime = function (time) {
			_currentTimeLabel.innerText = toFormatedString(time);
		};
		_self.setEndTime = function (time) {
			_duration = time;
			_endTimeLabel.innerText = toFormatedString(time);
		};
		_self.setProgress = function (percent) {
			_progressProcess.style.width = percent + '%';
			_progressSpinner.value = percent;
		};
		_self.setBuffer = function (percent) {
			_progressBuffer.style.width = percent + '%';
		};
		_self.hideProgressTimeHint = function () {
			_progressTimeHint.className = MUZUS_PROGRESS_TIME_HINT;
		};
		_self.setClickHandler = function (handler) {
			_playButtonWrapper.addEventListener('click', function () {
				handler(_self);
			});
		};
		_self.setChangeProgressHandler = function(handler) {
			_progressSpinner.addEventListener('input', function (e) {
				if (_currentState > 0  && _duration > 0) {
					handler(e.target.value);
				}
			});
		};
		_self.error = function (e) {
			if (_currentState === TRACK_ERROR) return;

			_currentState = TRACK_ERROR;
			newElement.className = MUZUS_TRACK + ' muzus-track-error';

			if (!!e && !!e.srcElement) {
				_w.console.error('MUZUS error:', e.srcElement.src, e.srcElement.error);
			}
		}

		// setup controls

		_titleLabel.innerHTML = _titleHtml;

		if (!_muzus.isMobile()) {
			_progressSpinner.addEventListener('mouseover', function () {
				if (_currentState > 0 && _duration > 0) {
					_progressTimeHint.className = MUZUS_PROGRESS_TIME_HINT + ' muzus-progress-time-hint-show';
				}
			});
			_progressSpinner.addEventListener('mouseout', _self.hideProgressTimeHint);
			_progressSpinner.addEventListener('mousemove', function (e) {
				if (_currentState > 0  && _duration > 0) {
					var time = _duration * e.offsetX / _progressSpinner.offsetWidth;
					_progressTimeHint.innerText = toFormatedString(time);
					_progressTimeHint.style.left = e.offsetX + 'px';
				}
			});
		}

		return _self;
	}

	var _muzus = {
		autoInit: true,
		init: function () {
			var _muzusDeclarations = _d.querySelectorAll(MUZUS_SELECTOR);

			for (var i = 0; i < _muzusDeclarations.length; i++) {
				new Player(_muzusDeclarations[i]);
			}
		},
		isMobile: function () {
			return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(_w.navigator.userAgent);
		}
	};

	return function () {

		if (!!_w.Muzus) {
			if (typeof _w.Muzus.autoInit === 'boolean') {
				_muzus.autoInit = _w.Muzus.autoInit;
			}
			if (typeof _w.Muzus.isMobile === 'function') {
				_muzus.isMobile = _w.Muzus.isMobile;
			}
		}

		if (_muzus.autoInit) {
			_muzus.init();
		}

		_w.Muzus = _muzus;
	};

}(window, document)());
<commit_msg>Fix options prop<commit_after>/**
 * New conception of audio player for web.
 *
 * @author Yauheni Pakala
 * @copyright 2017 MIT License
 * @version 0.1.0
 */
(function (_w, _d) {
	'use strict';

	// consts

	var MUZUS_SELECTOR = '.muzus',
		MUZUS_PLAY = 'muzus-play',
		MUZUS_PAUSE = 'muzus-pause',
		MUZUS_TRACK = 'muzus-track',
		MUZUS_PROGRESS = 'muzus-progress',
		MUZUS_PROGRESS_TIME_HINT = 'muzus-progress-time-hint',
		TRACK_ERROR = -1,
		TRACK_STOPED = 0,
		TRACK_PLAYING = 1,
		TRACK_PAUSED = 2;

	// helpers

	function toFormatedString (seconds) {
		var h = parseInt(seconds / 60 / 60),
			m = parseInt(seconds / 60 % 60),
			s = parseInt(seconds % 60);

		return (h ? h + ':' : '') + ((h && (m < 10)) ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
	}

	function createElement (tagName, className, parentElement) {
		var e = _d.createElement(tagName);
		e.className = className;
		if (typeof parentElement !== 'undefined') {
			parentElement.appendChild(e);
		}
		return e;
	}

	function createRangeElement (className, parentElement) {
		var e = createElement('input', className, parentElement);
		e.type = 'range';
		e.max = 100;
		e.min = 0;
		e.step = 0.01;
		e.value = 0;
		return e;
	}

	function createAudioElement () {
		var e = createElement('audio');
		e.preload = 'metadata';
		e.type = 'audio/mpeg';
		e.volume = 1;
		return e;
	}

	// classes

	function Player (element) {

		// private

		var _currentTrack = null,
			_trackList = [],
			_options = getPlayerOptionsFromElement(element),
			_player = createAudioElement();

		// setup player

		_player.onplaying = function () {
			_currentTrack.setEndTime(_player.duration);
		};
		_player.ontimeupdate = function () {
			if (_player.duration > 0) {
				_currentTrack.setProgress((_player.currentTime / _player.duration) * 100);
				_currentTrack.setCurrentTime(_player.currentTime);
			}
		};
		_player.onprogress = function () {
			if (_player.duration > 0) {
				var value = (_player.buffered.end(_player.buffered.length - 1) / _player.duration) * 100;
				_currentTrack.setBuffer(value);
			}
		};
		_player.onended = nextTrack;
		_player.onerror = function (e) {
			_currentTrack.error(e);
			stopPlayer();
			_currentTrack = null;
		};

		// TODO:
		var trackElements = element.querySelectorAll('a');
		for (var i = 0; i < trackElements.length; i++) {
			var trackElement = trackElements[i];
			var track = new Track(i, trackElement);
			track.setClickHandler(trackClickHandler);
			track.setChangeProgressHandler(trackProgressChangedHandler);

			_trackList.push(track);

			preloadTrack(track);
		}

		// private methods

		function trackClickHandler (track) {
			switch (track.getState()) {
				case TRACK_PLAYING:
					_currentTrack.pause();
					_player.pause();
				break;
				case TRACK_PAUSED:
					_currentTrack.play();
					_player.play();
				break;
				case TRACK_ERROR:
					return;
				break;
				default:
					startPlayTrack(track);
				break;
			}
		}

		function trackProgressChangedHandler (value) {
			if (_player.duration) {
				_player.currentTime = (value * _player.duration) / 100;
			} else {
				value = 0;
			}
		}

		function nextTrack () {
			var currentTrackIndex = _currentTrack.id,
				nextTrackIndex = currentTrackIndex < _trackList.length - 1 ? currentTrackIndex + 1 : 0;

			if (_trackList.length == 1) {
				stopPlayer();
				return;
			}
			if (nextTrackIndex < currentTrackIndex && !_options.isRepeat) {
				stopPlayer();
				return;
			}

			startPlayTrack(_trackList[nextTrackIndex]);
		}

		function startPlayTrack (track) {
			if (!!_currentTrack) {
				_currentTrack.stop();
			}
			_currentTrack = track;

			if (track.getState() === TRACK_ERROR)
			{
				nextTrack();
				return;
			}

			_player.src = _currentTrack.src;
			_currentTrack.play();
			_player.play();
		}

		function stopPlayer () {
			_player.pause();
			_player.currentTime = 0;

			_currentTrack.stop();
		}

		function preloadTrack (track) {
			var preloader = createAudioElement();
			preloader.volume = 0;
			preloader.src = track.src;
			preloader.onplaying = function () {
				preloader.pause();
				track.setCurrentTime(0);
				track.setEndTime(preloader.duration);
				preloader = null;
			};
			preloader.onerror = track.error;
			_w.setTimeout(function () {
				preloader.play();
			}, 100);
		}

		function getPlayerOptionsFromElement (playerElement) {
			return {
				isRepeat: playerElement.getAttribute('data-repeat') || false
			}
		}
	}

	function Track (id, element) {

		var _titleHtml = element.innerHTML,
			_src = element.href;

		// replace element

		var newElement = createElement('div', MUZUS_TRACK);
		element.parentNode.replaceChild(newElement, element);

		// private

		var _currentState = TRACK_STOPED,
			_duration = 0,
			_infoRow = createElement('div', 'muzus-info', newElement),
			_playButtonWrapper = createElement('span', 'muzus-play-wrapper', _infoRow),
			_playButton = createElement('span', MUZUS_PLAY, _playButtonWrapper),
			_titleLabel = createElement('span', 'muzus-title', _infoRow),
			_timeBlock = createElement('span', 'muzus-time', _infoRow),
			_currentTimeLabel = createElement('span', 'muzus-time-current', _timeBlock),
			_endTimeLabel = createElement('span', 'muzus-time-end', _timeBlock),
			_progressBlock = createElement('div', MUZUS_PROGRESS + ' muzus-progress-hide', newElement),
			_progressBuffer = createElement('div', 'muzus-progress-buffer', _progressBlock),
			_progressProcess = createElement('div', 'muzus-progress-process', _progressBlock),
			_progressSpinner = createRangeElement('muzus-progress-spinner', _progressBlock),
			_progressTimeHint = createElement('div', MUZUS_PROGRESS_TIME_HINT, _progressBlock),
			_self = {};

		// public

		_self.id = id;
		_self.src = _src;
		_self.play = function () {
			if (_currentState === TRACK_ERROR) return;

			_currentState = TRACK_PLAYING;
			newElement.className = MUZUS_TRACK + ' muzus-track-active';
			_playButton.className = MUZUS_PAUSE;
			_progressBlock.className = MUZUS_PROGRESS;
		};
		_self.pause = function () {
			if (_currentState === TRACK_ERROR) return;

			_currentState = TRACK_PAUSED;
			newElement.className = MUZUS_TRACK + ' muzus-track-paused';
			_playButton.className = MUZUS_PLAY;
		};
		_self.stop = function () {
			if (_currentState === TRACK_ERROR) return;

			_currentState = TRACK_STOPED;
			newElement.className = MUZUS_TRACK;
			_playButton.className = MUZUS_PLAY;
			_progressBlock.className = MUZUS_PROGRESS + ' muzus-progress-hide';

			_self.setCurrentTime(0);
			_self.setProgress(0);
			_self.setBuffer(0);
			_self.hideProgressTimeHint();
		};
		_self.getState = function () {
			return _currentState;
		};
		_self.setCurrentTime = function (time) {
			_currentTimeLabel.innerText = toFormatedString(time);
		};
		_self.setEndTime = function (time) {
			_duration = time;
			_endTimeLabel.innerText = toFormatedString(time);
		};
		_self.setProgress = function (percent) {
			_progressProcess.style.width = percent + '%';
			_progressSpinner.value = percent;
		};
		_self.setBuffer = function (percent) {
			_progressBuffer.style.width = percent + '%';
		};
		_self.hideProgressTimeHint = function () {
			_progressTimeHint.className = MUZUS_PROGRESS_TIME_HINT;
		};
		_self.setClickHandler = function (handler) {
			_playButtonWrapper.addEventListener('click', function () {
				handler(_self);
			});
		};
		_self.setChangeProgressHandler = function(handler) {
			_progressSpinner.addEventListener('input', function (e) {
				if (_currentState > 0  && _duration > 0) {
					handler(e.target.value);
				}
			});
		};
		_self.error = function (e) {
			if (_currentState === TRACK_ERROR) return;

			_currentState = TRACK_ERROR;
			newElement.className = MUZUS_TRACK + ' muzus-track-error';

			if (!!e && !!e.srcElement) {
				_w.console.error('MUZUS error:', e.srcElement.src, e.srcElement.error);
			}
		}

		// setup controls

		_titleLabel.innerHTML = _titleHtml;

		if (!_muzus.isMobile()) {
			_progressSpinner.addEventListener('mouseover', function () {
				if (_currentState > 0 && _duration > 0) {
					_progressTimeHint.className = MUZUS_PROGRESS_TIME_HINT + ' muzus-progress-time-hint-show';
				}
			});
			_progressSpinner.addEventListener('mouseout', _self.hideProgressTimeHint);
			_progressSpinner.addEventListener('mousemove', function (e) {
				if (_currentState > 0  && _duration > 0) {
					var time = _duration * e.offsetX / _progressSpinner.offsetWidth;
					_progressTimeHint.innerText = toFormatedString(time);
					_progressTimeHint.style.left = e.offsetX + 'px';
				}
			});
		}

		return _self;
	}

	var _muzus = {
		autoInit: true,
		init: function () {
			var _muzusDeclarations = _d.querySelectorAll(MUZUS_SELECTOR);

			for (var i = 0; i < _muzusDeclarations.length; i++) {
				new Player(_muzusDeclarations[i]);
			}
		},
		isMobile: function () {
			return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(_w.navigator.userAgent);
		}
	};

	return function () {

		if (!!_w.Muzus) {
			if (typeof _w.Muzus.autoInit === 'boolean') {
				_muzus.autoInit = _w.Muzus.autoInit;
			}
			if (typeof _w.Muzus.isMobile === 'function') {
				_muzus.isMobile = _w.Muzus.isMobile;
			}
		}

		if (_muzus.autoInit) {
			_muzus.init();
		}

		_w.Muzus = _muzus;
	};

}(window, document)());
<|endoftext|>


<commit_before>let term = require('terminal-kit').terminal;
let request = require('request');

module.exports = function(container) {

	return new Promise(function(resolve, reject) {

		//
		//	1.	Ask for the API Key
		//
		ask_for_the_api_key(container)
			.then(function(container) {

				//
				//	1.	Get the company user database
				//
				return get_company_users(container)

			}).then(function(container) {

				//
				//	1.	Save only the data that we need, which is:
				//
				//		- email
				//		- url to avatar
				//
				return discard_unnecesary_data(container)

			}).then(function(container) {

				//
				//	->	Move to the next chain
				//
				return resolve(container)

			}).catch(function(error) {

				//
				//	->	Crash if something goes wrong
				//
				return reject(error)

			});

	});
};

//  _____    _____     ____    __  __   _____    _____   ______    _____
// |  __ \  |  __ \   / __ \  |  \/  | |_   _|  / ____| |  ____|  / ____|
// | |__) | | |__) | | |  | | | \  / |   | |   | (___   | |__    | (___
// |  ___/  |  _  /  | |  | | | |\/| |   | |    \___ \  |  __|    \___ \
// | |      | | \ \  | |__| | | |  | |  _| |_   ____) | | |____   ____) |
// |_|      |_|  \_\  \____/  |_|  |_| |_____| |_____/  |______| |_____/
//

//
//	Ask for the API Key that the user can generate in their account
//
function ask_for_the_api_key(container)
{
	return new Promise(function(resolve, reject) {

		//
		//	1.	Ask input from the user
		//
		term.yellow("\tPlease enter your Bamboo API Key: ");

		//
		//	2.	Process the user input
		//
		term.inputField({}, function(error, api_key) {

			//
			//	1.	Save the URL
			//
			container.service_api_key = api_key;

			//
			//	-> Move to the next chain
			//
			return resolve(container);

		});

	});
}

//
//	Retrieve every employee for a specific account
//
function get_company_users(container)
{
	return new Promise(function(resolve, reject) {

		//
		//	1.	The basic options for the request.
		//
		let option = {
			url: "https://api.bamboohr.com/api/gateway.php/sequr/v1/employees/directory",
			json: true,
			headers: {
				Accept: 'application/json'
			}

		}

		//
		//  2.	Make a request
		//
		request.get(option, function(r_error, response, body) {

			//
			//	1.	Check if there were no internal errors
			//
			if(r_error)
			{
				return reject(r_error);
			}

			//
			//	2. Check if the server didn't have any issues
			//
			if(response.statusCode >= 300)
			{
				let message = "BambooHR request failed with status code: "
							  + response.statusCode

				let error = new Error(message);

				return reject(error);
			}

			//
			//	3.	Save the raw body which is just pure XML - deal with it.
			//
			container.employee_json = body;

			//
			//	->	Move to the next chain
			//
			return resolve(container);

		}).auth(container.service_api_key, 'x', true)

	});
}

//
//	Keep only the data that we care about
//
function discard_unnecesary_data(container)
{
	return new Promise(function(resolve, reject) {

		//
		//	1.	Hold the final data in tmp array
		//
		let tmp_array = [];

		//
		//	2.	Loop over the result and traverse the convoluted JSON that we
		//		got back
		//
		container.employee_json.directory.employees.forEach(function(data) {

			data.employee.forEach(function(something, index) {

				//
				//	1.	Add what we care to the tmp array
				//
				tmp_array.push({
					email: something.field[8]["_"],
					photo: something.field[14]["_"]
				})

			});

		});

		//
		//	3. Save the result
		//
		container.clean_users = tmp_array

		//
		//	4.	Delete the JSON data since we won't need it anymore to
		//		be mindful of the user memory since, this array could hold
		//		a bunch of megabytes
		//
		delete container.employee_json;

		//
		//	-> Move to the next chain
		//
		return resolve(container);

	});
}<commit_msg>Fixed #11<commit_after>let term = require('terminal-kit').terminal;
let request = require('request');

module.exports = function(container) {

	return new Promise(function(resolve, reject) {

		//
		//	1.	Ask for the API Key
		//
		ask_for_the_api_key(container)
			.then(function(container) {

				//
				//	1.	Get the company user database
				//
				return get_company_users(container)

			}).then(function(container) {

				//
				//	1.	Save only the data that we need, which is:
				//
				//		- email
				//		- url to avatar
				//
				return discard_unnecesary_data(container)

			}).then(function(container) {

				//
				//	->	Move to the next chain
				//
				return resolve(container)

			}).catch(function(error) {

				//
				//	->	Crash if something goes wrong
				//
				return reject(error)

			});

	});
};

//  _____    _____     ____    __  __   _____    _____   ______    _____
// |  __ \  |  __ \   / __ \  |  \/  | |_   _|  / ____| |  ____|  / ____|
// | |__) | | |__) | | |  | | | \  / |   | |   | (___   | |__    | (___
// |  ___/  |  _  /  | |  | | | |\/| |   | |    \___ \  |  __|    \___ \
// | |      | | \ \  | |__| | | |  | |  _| |_   ____) | | |____   ____) |
// |_|      |_|  \_\  \____/  |_|  |_| |_____| |_____/  |______| |_____/
//

//
//	Ask for the API Key that the user can generate in their account
//
function ask_for_the_api_key(container)
{
	return new Promise(function(resolve, reject) {

		//
		//	1.	Ask input from the user
		//
		term.yellow("\tPlease enter your Bamboo API Key: ");

		//
		//	2.	Process the user input
		//
		term.inputField({}, function(error, api_key) {

			//
			//	1.	Save the URL
			//
			container.service_api_key = api_key;

			//
			//	-> Move to the next chain
			//
			return resolve(container);

		});

	});
}

//
//	Retrieve every employee for a specific account
//
function get_company_users(container)
{
	return new Promise(function(resolve, reject) {

		//
		//	1.	The basic options for the request.
		//
		let option = {
			url: "https://api.bamboohr.com/api/gateway.php/sequr/v1/employees/directory",
			json: true,
			headers: {
				Accept: 'application/json'
			}

		}

		//
		//  2.	Make a request
		//
		request.get(option, function(r_error, response, body) {

			//
			//	1.	Check if there were no internal errors
			//
			if(r_error)
			{
				return reject(r_error);
			}

			//
			//	2. Check if the server didn't have any issues
			//
			if(response.statusCode >= 300)
			{
				let message = "BambooHR request failed with status code: "
							  + response.statusCode

				let error = new Error(message);

				return reject(error);
			}

			//
			//	3.	Save the raw body which is just pure XML - deal with it.
			//
			container.employees = body.employees;

			//
			//	->	Move to the next chain
			//
			return resolve(container);

		}).auth(container.service_api_key, 'x', true)

	});
}

//
//	Keep only the data that we care about
//
function discard_unnecesary_data(container)
{
	return new Promise(function(resolve, reject) {

		//
		//	1.	Hold the final data in tmp array
		//
		let tmp_array = [];

		//
		//	2.	Loop over the result and traverse the convoluted JSON that we
		//		got back
		//
		container.employees.forEach(function(data) {

			//
			//	1.	Add what we care to the tmp array
			//
			tmp_array.push({
				email: data.workEmail,
				photo: data.photoUrl
			});

		});

		//
		//	3. Save the result
		//
		container.clean_users = tmp_array

		//
		//	4.	Delete the JSON data since we won't need it anymore to
		//		be mindful of the user memory since, this array could hold
		//		a bunch of megabytes
		//
		delete container.employees;

		//
		//	-> Move to the next chain
		//
		return resolve(container);

	});
}<|endoftext|>


<commit_before>/* jslint asi:true, browser:true */

if (typeof Lexis == "undefined") var Lexis = {};

var Dictionary = {
    forms: {},
    getHumanReadableWordClass: function(word_class) {
        if (!word_class) word_class = "";
        var class_list = word_class.split(" ");
        var class_item_list = null;
        var i = 0;
        var j = 0;
        var s = "";
        var q = null;
        for (i = 0; i < class_list.length; i++) {
            if (i) s += ", ";
            class_item_list = class_list[i].split(".");
            q = {};
            for (j = 0; j < class_item_list.length; j++) {
                q[class_item_list[j]] = true;
            }

            if (q.pfv) s += "perfective ";
            if (q.prog) s += "progressive ";
            if (q.cont) s += "continuous ";
            if (q["1"]) s += "first-person ";
            if (q["2"]) s += "second-person ";
            if (q["3"]) s += "third-person ";
            if (q.mod) {
                if (q.mir) s += "mirative ";
                else if (q.opt) s += "optative ";
                else if (q.hort) s += "hortative ";
                else if (q.perm) s += "permissive ";
                else if (q.jus) s += "jussive ";
                else if (q.int) s += "interrogative ";
                else s += "modal ";
            }
            if (q.det) {
                if (q.qnt) s += "quantifier ";
                else if (q.num) s += "numeral ";
                else if (q.dem) s += "demonstrative ";
                else s += "determiner";
            }
            if (q.post) s += "post-position";
            if (q.ptcl) s += "particle ";
            if (q.adj) s += "adjective ";
            if (q.adv) s += "adverb ";
            if (q.pron) s += "pronoun ";
            if (q.n) s += "noun ";
            if (q.v) s += "verb ";
            s.trim();
        }
        return s;
    },
    getLemmaFromId: function(id) {
        return Dictionary.lemmas[id.split(":")[0]][Number(id.split(":")[1])]
    },
    ids: [],
    init: function() {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.addEventListener("load", function() {Dictionary.load(document.documentElement.dataset.src + "?" + new Date().getTime())}, false);
        document.head.appendChild(script);
        script.src = "http://leaf.faint.xyz/langdev/!DATA!/master/!DATA!/LexisML/scripts/normalize.js";
    },
    lang: "",
    lemmas: {},
    lexis: undefined,
    load: function(src) {
        Dictionary.Requester.addEventListener("load", Dictionary.setup, false);
        Dictionary.Requester.open("get", src, true);
        Dictionary.Requester.overrideMimeType("text/xml");
        Dictionary.Requester.send();
    },
    Requester: new XMLHttpRequest(),
    setup: function() {
        Dictionary.lang = document.documentElement.lang;
        Dictionary.lexis = Dictionary.Requester.responseXML;
        Lexis.normalize(Dictionary.lexis);
        var i = 0;
        var j = 0;
        var elements = Dictionary.lexis.documentElement.children;
        var current_element;
        var current_lemma;
        var lemma_name;
        var lemma_id;
        var section_html;
        for (i = 0; i < elements.length; i++) {
            current_element = elements.item(i);
            switch (current_element.tagName) {
                case "meta":
                    switch (current_element.getAttribute("name")) {
                        case "title":
                            Dictionary.title = [current_element.getAttributeNS("http://www.w3.org/XML/1998/namespace", "lang"), current_element.textContent];
                            break;
                        case "splash":
                            Dictionary.splashes[Dictionary.splashes.length] = [current_element.getAttributeNS("http://www.w3.org/XML/1998/namespace", "lang"), current_element.textContent];
                            break;
                    }
                    break;
                case "affix":
                case "word":
                    lemma_name = current_element.getAttribute("lemma").replace(/:/g, "-").replace(/^-+|[0-9]+$/g, "");
                    if (Dictionary.lemmas[lemma_name] === undefined) Dictionary.lemmas[lemma_name] = [];
                    lemma_id = lemma_name + ":" + Dictionary.lemmas[lemma_name].length;
                    Dictionary.lemmas[lemma_name][Dictionary.lemmas[lemma_name].length] = {
                        type: current_element.tagName,
                        name: current_element.getAttribute("lemma"),
                        id: lemma_id,
                        word_class: null,
                        lang: current_element.getAttributeNS("http://www.w3.org/XML/1998/namespace", "lang"),
                        forms: current_element.getElementsByTagNameNS("http://leaf.faint.xyz/lexisml", "form"),
                        etymology: current_element.getElementsByTagNameNS("http://leaf.faint.xyz/lexisml", "etymology").item(0),
                        meanings: current_element.getElementsByTagNameNS("http://leaf.faint.xyz/lexisml", "meaning")
                    }
                    current_lemma = Dictionary.lemmas[lemma_name][Dictionary.lemmas[lemma_name].length];
                    for (j = 0; j < current_lemma.forms.length; j++) {
                        if (current_lemma.forms.item(j).textContent == current_lemma.name) {
                            current_lemma.word_class = current_lemma.forms.item(j).getAttribute("class");
                            break;
                        }
                    }
                    Dictionary.ids[Dictionary.ids.length] = lemma_id;
                    break;
            }
        }
        Dictionary.ids.sort(function (a, b) {return String(a).localeCompare(String(b));});
        var main_article = document.createElement("article");
        document.title = Dictionary.title[1];
        document.getElementsByTagName("title").item(0).lang = Dictionary.title[0];
        if (Dictionary.splashes.length) {
            i = Math.floor(Math.random()*Dictionary.splashes.length);
            main_article.innerHTML = "
" + Dictionary.title[1] + "

" + Dictionary.splashes[i][1] + "
";
        }
        else main_article.innerHTML = "
" + Dictionary.title[1] + "
";
        for (i = 0; i < Dictionary.ids.length; i++) {
            current_element = document.createElement("section");
            current_lemma = Dictionary.getLemmaFromId(Dictionary.ids[i]);
            current_element.lang = current_lemma.lang;
            current_element.id = Dictionary.ids[i];
            section_html = "";
            section_html += "
<dfn>" + current_lemma.name + "</dfn>
";
            if (current_lemma.type == "word") {
                if (current_lemma.word_class) {
                    section_html += "
" + Dictionary.getHumanReadableWordClass(current_lemma.word_class) + "
";
                    break;
                }
                section_html += "
";
                for (j = 0; j < current_lemma.forms.length; j++) {
                    if (current_lemma.forms.item(j).textContent != current_lemma.name) section_html += Dictionary.getHumanReadableWordClass(current_lemma.forms.item(j).getAttribute("class")) + " : " + current_lemma.forms.item(j).textContent + "";
                    if (j + 1 != current_lemma.forms.length) section_html += " ";
                }
                section_html += "
"
            }
            else if (current_lemma.type == "affix") {
                section_html += "
affix
";
            }
            section_html += "
";
            for (j = 0; j < current_lemma.meanings.length; j++) {
                section_html += "
";
                if (current_lemma.meanings.item(j).getAttribute("class") != current_lemma.word_class) section_html += "(" + Dictionary.getHumanReadableWordClass(current_lemma.meanings.item(j).getAttribute("class")) + ") ";
                section_html += current_lemma.meanings.item(j).textContent;
                section_html += "
";
            }
            section_html += "
";
            current_element.innerHTML = section_html;
            main_article.appendChild(current_element);
        }
        document.body.textContent = null;
        document.body.appendChild(document.createElement("main").appendChild(main_article).parentElement);
    },
    splashes: [],
    title: "",
    title_lang: ""
}

window.addEventListener("load", Dictionary.init, false);
<commit_msg>fix pt 2<commit_after>/* jslint asi:true, browser:true */

if (typeof Lexis == "undefined") var Lexis = {};

var Dictionary = {
    forms: {},
    getHumanReadableWordClass: function(word_class) {
        if (!word_class) word_class = "";
        var class_list = word_class.split(" ");
        var class_item_list = null;
        var i = 0;
        var j = 0;
        var s = "";
        var q = null;
        for (i = 0; i < class_list.length; i++) {
            if (i) s += ", ";
            class_item_list = class_list[i].split(".");
            q = {};
            for (j = 0; j < class_item_list.length; j++) {
                q[class_item_list[j]] = true;
            }

            if (q.pfv) s += "perfective ";
            if (q.prog) s += "progressive ";
            if (q.cont) s += "continuous ";
            if (q["1"]) s += "first-person ";
            if (q["2"]) s += "second-person ";
            if (q["3"]) s += "third-person ";
            if (q.mod) {
                if (q.mir) s += "mirative ";
                else if (q.opt) s += "optative ";
                else if (q.hort) s += "hortative ";
                else if (q.perm) s += "permissive ";
                else if (q.jus) s += "jussive ";
                else if (q.int) s += "interrogative ";
                else s += "modal ";
            }
            if (q.det) {
                if (q.qnt) s += "quantifier ";
                else if (q.num) s += "numeral ";
                else if (q.dem) s += "demonstrative ";
                else s += "determiner";
            }
            if (q.post) s += "post-position";
            if (q.ptcl) s += "particle ";
            if (q.adj) s += "adjective ";
            if (q.adv) s += "adverb ";
            if (q.pron) s += "pronoun ";
            if (q.n) s += "noun ";
            if (q.v) s += "verb ";
            s.trim();
        }
        return s;
    },
    getLemmaFromId: function(id) {
        return Dictionary.lemmas[id.split(":")[0]][Number(id.split(":")[1])]
    },
    ids: [],
    init: function() {
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.addEventListener("load", function() {Dictionary.load(document.documentElement.dataset.src + "?" + new Date().getTime())}, false);
        document.head.appendChild(script);
        script.src = "http://leaf.faint.xyz/langdev/!DATA!/master/!DATA!/LexisML/scripts/normalize.js";
    },
    lang: "",
    lemmas: {},
    lexis: undefined,
    load: function(src) {
        Dictionary.Requester.addEventListener("load", Dictionary.setup, false);
        Dictionary.Requester.open("get", src, true);
        Dictionary.Requester.overrideMimeType("text/xml");
        Dictionary.Requester.send();
    },
    Requester: new XMLHttpRequest(),
    setup: function() {
        Dictionary.lang = document.documentElement.lang;
        Dictionary.lexis = Dictionary.Requester.responseXML;
        Lexis.normalize(Dictionary.lexis);
        var i = 0;
        var j = 0;
        var elements = Dictionary.lexis.documentElement.children;
        var current_element;
        var current_lemma;
        var lemma_name;
        var lemma_id;
        var section_html;
        for (i = 0; i < elements.length; i++) {
            current_element = elements.item(i);
            switch (current_element.tagName) {
                case "meta":
                    switch (current_element.getAttribute("name")) {
                        case "title":
                            Dictionary.title = [current_element.getAttributeNS("http://www.w3.org/XML/1998/namespace", "lang"), current_element.textContent];
                            break;
                        case "splash":
                            Dictionary.splashes[Dictionary.splashes.length] = [current_element.getAttributeNS("http://www.w3.org/XML/1998/namespace", "lang"), current_element.textContent];
                            break;
                    }
                    break;
                case "affix":
                case "word":
                    lemma_name = current_element.getAttribute("lemma").replace(/:/g, "-").replace(/^-+|[0-9]+$/g, "");
                    if (Dictionary.lemmas[lemma_name] === undefined) Dictionary.lemmas[lemma_name] = [];
                    lemma_id = lemma_name + ":" + Dictionary.lemmas[lemma_name].length;
                    current_lemma = Dictionary.lemmas[lemma_name][Dictionary.lemmas[lemma_name].length] = {
                        type: current_element.tagName,
                        name: current_element.getAttribute("lemma"),
                        id: lemma_id,
                        word_class: null,
                        lang: current_element.getAttributeNS("http://www.w3.org/XML/1998/namespace", "lang"),
                        forms: current_element.getElementsByTagNameNS("http://leaf.faint.xyz/lexisml", "form"),
                        etymology: current_element.getElementsByTagNameNS("http://leaf.faint.xyz/lexisml", "etymology").item(0),
                        meanings: current_element.getElementsByTagNameNS("http://leaf.faint.xyz/lexisml", "meaning")
                    }
                    for (j = 0; j < current_lemma.forms.length; j++) {
                        if (current_lemma.forms.item(j).textContent == current_lemma.name) {
                            current_lemma.word_class = current_lemma.forms.item(j).getAttribute("class");
                            break;
                        }
                    }
                    Dictionary.ids[Dictionary.ids.length] = lemma_id;
                    break;
            }
        }
        Dictionary.ids.sort(function (a, b) {return String(a).localeCompare(String(b));});
        var main_article = document.createElement("article");
        document.title = Dictionary.title[1];
        document.getElementsByTagName("title").item(0).lang = Dictionary.title[0];
        if (Dictionary.splashes.length) {
            i = Math.floor(Math.random()*Dictionary.splashes.length);
            main_article.innerHTML = "
" + Dictionary.title[1] + "

" + Dictionary.splashes[i][1] + "
";
        }
        else main_article.innerHTML = "
" + Dictionary.title[1] + "
";
        for (i = 0; i < Dictionary.ids.length; i++) {
            current_element = document.createElement("section");
            current_lemma = Dictionary.getLemmaFromId(Dictionary.ids[i]);
            current_element.lang = current_lemma.lang;
            current_element.id = Dictionary.ids[i];
            section_html = "";
            section_html += "
<dfn>" + current_lemma.name + "</dfn>
";
            if (current_lemma.type == "word") {
                if (current_lemma.word_class) {
                    section_html += "
" + Dictionary.getHumanReadableWordClass(current_lemma.word_class) + "
";
                    break;
                }
                section_html += "
";
                for (j = 0; j < current_lemma.forms.length; j++) {
                    if (current_lemma.forms.item(j).textContent != current_lemma.name) section_html += Dictionary.getHumanReadableWordClass(current_lemma.forms.item(j).getAttribute("class")) + " : " + current_lemma.forms.item(j).textContent + "";
                    if (j + 1 != current_lemma.forms.length) section_html += " ";
                }
                section_html += "
"
            }
            else if (current_lemma.type == "affix") {
                section_html += "
affix
";
            }
            section_html += "
";
            for (j = 0; j < current_lemma.meanings.length; j++) {
                section_html += "
";
                if (current_lemma.meanings.item(j).getAttribute("class") != current_lemma.word_class) section_html += "(" + Dictionary.getHumanReadableWordClass(current_lemma.meanings.item(j).getAttribute("class")) + ") ";
                section_html += current_lemma.meanings.item(j).textContent;
                section_html += "
";
            }
            section_html += "
";
            current_element.innerHTML = section_html;
            main_article.appendChild(current_element);
        }
        document.body.textContent = null;
        document.body.appendChild(document.createElement("main").appendChild(main_article).parentElement);
    },
    splashes: [],
    title: "",
    title_lang: ""
}

window.addEventListener("load", Dictionary.init, false);
<|endoftext|>