<commit_before>/*
 *  Node.js test runner for running data-*.js tests with Duktape 'duk' command.
 *
 *  Reports discrepancies to console; fix them manually in data-*.js files.
 *  Expects a './duk' command in the current directory.  Example:
 *
 *    $ cp /path/to/duk ./duk
 *    $ node duktape.js
 */

var fs = require('fs');
var child_process = require('child_process');

var testCount = 0;
var testSuccess = 0;
var testOutOfDate = 0;

var dukCommand = './duk';

// Key for .res (e.g. test.res.duktape20), automatic based on Duktape.version.
var dukKey = (function () {
    var stdout = child_process.execFileSync(dukCommand, [ '-e', 'print(Duktape.version)' ], {
        encoding: 'utf-8'
    });
    var dukVersion = Number(stdout);
    console.log('Duktape version is: ' + dukVersion);
    return 'duktape' + (Math.floor(dukVersion / 10000)) + (Math.floor(dukVersion / 100 % 100));
})();
console.log('Duktape result key is: test.res.' + dukKey);

// Run test / subtests, recursively.  Report results, indicate data files
// which are out of date.
function runTest(parents, test, sublevel) {
    var testPath = parents.join(' -> ') + ' -> ' + test.name;

    if (typeof test.exec === 'function') {
        var src = test.exec.toString();
        var m = /^function\s*\w*\s*\(.*?\)\s*\{\s*\/\*([\s\S]*?)\*\/\s*\}$/m.exec(src);
        var evalcode;
        if (m) {
            evalcode = '(function test() {' + m[1] + '})();';
        } else {
            evalcode = '(' + src + ')()';
        }
        //console.log(evalcode);

        var script = 'var evalcode = ' + JSON.stringify(evalcode) + ';\n' +
                     'try {\n' +
                     '    var res = eval(evalcode);\n' +
                     '    if (res !== true && res !== 1) { throw new Error("failed: " + res); }\n' +
                     '    console.log("[SUCCESS]");\n' +
                     '} catch (e) {\n' +
                     '    console.log("[FAILURE]", e);\n' +
                     '    /*throw e;*/\n' +
                     '}\n';

        fs.writeFileSync('duktest.js', script);
        var stdout = child_process.execFileSync(dukCommand, [ 'duktest.js' ], {
            encoding: 'utf-8'
        });
        //console.log(stdout);

        var success = false;
        if (/^\[SUCCESS\]$/gm.test(stdout)) {
            success = true;
            testSuccess++;
        } else {
            //console.log(stdout);
        }
        testCount++;

        if (test.res) {
            if (test.res[dukKey] === success) {
                // Matches.
            } else if (test.res[dukKey] === void 0 && !success) {
                testOutOfDate++;
                console.log(testPath + ': test result missing, res: ' + test.res[dukKey] + ', actual: ' + success);
            } else {
                testOutOfDate++;
                console.log(testPath + ': test result out of date, res: ' + test.res[dukKey] + ', actual: ' + success);
            }
        } else {
            testOutOfDate++;
            console.log(testPath + ': test.res missing');
        }
    }
    if (test.subtests) {
        var newParents = parents.slice(0);
        newParents.push(test.name);
        test.subtests.forEach(function (v) { runTest(newParents, v, sublevel + 1); });
    }
}

fs.readdirSync('.').forEach(function (filename) {
    var m = /^(data-.*)\.js$/.exec(filename);
    if (!m) {
        return;
    }
    var suitename = m[1];

    console.log('');
    console.log('**** ' + suitename + ' ****');
    console.log('');
    var testsuite = require('./' + suitename);
    testsuite.tests.forEach(function (v) { runTest([ suitename ], v, 0); });
});

console.log(testCount + ' tests executed: ' + testSuccess + ' success, ' + (testCount - testSuccess) + ' fail');
console.log(testOutOfDate + ' tests are out of date (data-*.js file .res)');
<commit_msg>Add result inheritance support to duktape.js<commit_after>/*
 *  Node.js test runner for running data-*.js tests with Duktape 'duk' command.
 *
 *  Reports discrepancies to console; fix them manually in data-*.js files.
 *  Expects a './duk' command in the current directory.  Example:
 *
 *    $ cp /path/to/duk ./duk
 *    $ node duktape.js
 */

var fs = require('fs');
var child_process = require('child_process');

var testCount = 0;
var testSuccess = 0;
var testOutOfDate = 0;

var dukCommand = './duk';

var environments = JSON.parse(fs.readFileSync('environments.json').toString());

// Key for .res (e.g. test.res.duktape20), automatic based on Duktape.version.
var dukKey = (function () {
    var stdout = child_process.execFileSync(dukCommand, [ '-e', 'print(Duktape.version)' ], {
        encoding: 'utf-8'
    });
    var dukVersion = Number(stdout);
    console.log('Duktape version is: ' + dukVersion);
    return 'duktape' + (Math.floor(dukVersion / 10000)) + (Math.floor(dukVersion / 100 % 100));
})();
console.log('Duktape result key is: test.res.' + dukKey);

// List of keys for inheriting results from previous versions.
var dukKeyList = (function () {
    var res = [];
    for (var k in environments) {
        var env = environments[k];
        if (env.family !== 'Duktape') {
            continue;
        }
        res.push(k);
        if (k === dukKey) {
            // Include versions up to 'dukKey' but not newer.
            break;
        }
    }
    return res;
})();
console.log('Duktape key list for inheriting results is:', dukKeyList);

// Run test / subtests, recursively.  Report results, indicate data files
// which are out of date.
function runTest(parents, test, sublevel) {
    var testPath = parents.join(' -> ') + ' -> ' + test.name;

    if (typeof test.exec === 'function') {
        var src = test.exec.toString();
        var m = /^function\s*\w*\s*\(.*?\)\s*\{\s*\/\*([\s\S]*?)\*\/\s*\}$/m.exec(src);
        var evalcode;
        if (m) {
            evalcode = '(function test() {' + m[1] + '})();';
        } else {
            evalcode = '(' + src + ')()';
        }
        //console.log(evalcode);

        var script = 'var evalcode = ' + JSON.stringify(evalcode) + ';\n' +
                     'try {\n' +
                     '    var res = eval(evalcode);\n' +
                     '    if (res !== true && res !== 1) { throw new Error("failed: " + res); }\n' +
                     '    console.log("[SUCCESS]");\n' +
                     '} catch (e) {\n' +
                     '    console.log("[FAILURE]", e);\n' +
                     '    /*throw e;*/\n' +
                     '}\n';

        fs.writeFileSync('duktest.js', script);
        var stdout = child_process.execFileSync(dukCommand, [ 'duktest.js' ], {
            encoding: 'utf-8'
        });
        //console.log(stdout);

        var success = false;
        if (/^\[SUCCESS\]$/gm.test(stdout)) {
            success = true;
            testSuccess++;
        } else {
            //console.log(stdout);
        }
        testCount++;

        if (test.res) {
            // Take expected result from newest Duktape version not newer
            // than current version.
            var expect = void 0;
            dukKeyList.forEach(function (k) {
                if (test.res[k] !== void 0) {
                    expect = test.res[k];
                }
            });

            if (expect === success) {
                // Matches.
            } else if (expect === void 0 && !success) {
                testOutOfDate++;
                console.log(testPath + ': test result missing, res: ' + expect + ', actual: ' + success);
            } else {
                testOutOfDate++;
                console.log(testPath + ': test result out of date, res: ' + expect + ', actual: ' + success);
            }
        } else {
            testOutOfDate++;
            console.log(testPath + ': test.res missing');
        }
    }
    if (test.subtests) {
        var newParents = parents.slice(0);
        newParents.push(test.name);
        test.subtests.forEach(function (v) { runTest(newParents, v, sublevel + 1); });
    }
}

fs.readdirSync('.').forEach(function (filename) {
    var m = /^(data-.*)\.js$/.exec(filename);
    if (!m) {
        return;
    }
    var suitename = m[1];

    console.log('');
    console.log('**** ' + suitename + ' ****');
    console.log('');
    var testsuite = require('./' + suitename);
    testsuite.tests.forEach(function (v) { runTest([ suitename ], v, 0); });
});

console.log(testCount + ' tests executed: ' + testSuccess + ' success, ' + (testCount - testSuccess) + ' fail');
console.log(testOutOfDate + ' tests are out of date (data-*.js file .res)');
<|endoftext|>


<commit_before>'use strict';

const debug = require('debug')('strider-template:webapp');

module.exports = {
  // mongoose schema, if you need project-specific config
  config: {
    template: {
      environment: {type: String, default: 'Hi from `environment`'},
      prepare: {type: String, default: 'Hi from `prepare`'},
      test: {type: String, default: 'Hi from `test`'},
      deploy: {type: String, default: 'Hi from `deploy`'},
      cleanup: {type: String, default: 'Hi from `cleanup`'}
    }
  },
  // Define project-specific routes
  //   all routes created here are namespaced within /:org/:repo/api/:pluginid
  //   req.project is the current project
  //   req.accessLevel is the current user's access level for the project
  //      0 - anonymous, 1 - authed, 2 - admin / collaborator
  //   req.user is the current user
  //   req.pluginConfig() -> get the config for this plugin
  //   req.pluginConfig(config, cb(err)) -> set the config for this plugin
  routes: function (app, context) {
    debug(context);
  },
  // Define global routes
  //   all routes namespaced within /ext/:pluginid
  //   req.user is the current user
  //   req.user.account_level can be used for authorization
  //      0 - anonymous, 1 - authed, 2 - admin / collaborator
  globalRoutes: function (app, context) {
    app.get('/report', function (req, res) {
      res.json({report: 'hello'});
    });
    debug(context);
  },
  // Listen for global events
  //   all job-local events that begin with `plugin.` are proxied to
  //   the main strider eventemitter, so you can listen for them here.
  //   Other events include `job.new`, `job.done` and `browser.update`.
  listen: function (emitter, context) {
    debug(context);
  }
};
<commit_msg>reports endpoint<commit_after>'use strict';

module.exports = function (context, done) {
  context.app.get('/:org/:repo/report', function (req, res) {
    res.json({report: 'hello'});
  });
  done();
};
<|endoftext|>


<commit_before>/*
 * Analyze Controller.
 * This manages all actions executed from metrics explorer.
 */

define(['../../helpers/chart-helper'], function (chartHelper) {

  // Used for local storage, which is used to store our metrics selection.
  var STORED_APP_NAME = 'continuuity-analyze';

  // Used to query for available element types from REST.
  var AVAILABLE_TYPES = ['apps', 'streams', 'flows', 'mapreduce', 'datasets', 'procedures'];

  var Controller = Em.Controller.extend(Em.Evented, {

    elementModels: [],

    // Holds available element models.
    elementsCache: [],

    // Holds a per-type cache of available metrics.
    metricsCache: Em.Object.create(),

    // Holds the currently selected metrics.
    selected: Em.ArrayProxy.create({ content: [] }),

    // Holds temporary information from the 'Add Metric' form.
    configuring: Em.Object.extend({
      noSelection: function () {
        return this.get('element.name') === 'Elements' ||
          this.get('metric.name') === 'Metric Names';
      }.property('element', 'metric'),
      element: {
        name: 'Elements'
      },
      metric: {
        name: 'Metric Names'
      }
    }),

    init: function () {

      /*
       * Only 'extend' allows computed properties, as above.
       * Therefore we create / construct here.
       */
      this.set('configuring', this.get('configuring').create());

    },

    load: function (id) {

      var self = this;

      this.set('palette', new Rickshaw.Color.Palette({ scheme: 'colorwheel', interpolatedStopCount: 2  }));

      this.set('selected', Em.ArrayProxy.create({ content: [] }));

      /*
       * Prepopulate metrics selection from Local Storage if available.
       */
      if (window.localStorage) {

        var saved = localStorage.getItem(STORED_APP_NAME);
        if (saved) {
          this.set('selected.content', JSON.parse(saved).content);
        }

      }

      var self = this;

      this.get('selected').forEach(function (item, index) {

        item.color = self.get('palette').color();

      });

      function findElement(type, id) {

        var models = self.elementModels, i = models.length;
        while (i--) {
          if (models[i].type === type && models[i].id === id) {
            return models[i];
          }
        }
        return null;

      }

      // Needs time to find elements. Move to run loop.
      setTimeout(function () {

        $("#elementSelector").select2({
            containerCssClass: "analyze-configurator-element-select",
            placeholder: "Select Element",
            query: function(query) {

              var data = [];

              $.each(self.elementsCache, function(){

                var children = [];
                $.each(this.children, function () {
                  if(query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
                      children.push({id: this.id, text: this.text });
                  }
                });
                this.children = children;
                if (children.length) {
                  data.push(this);
                }
              });
              query.callback({results: data});

            }
        });
        $("#elementSelector").on('change', function (e) {

          if (e.added) {
            var id = e.added.id.split('|');
            var element = findElement(id[0], id[1]);
            self.selectElement(element);
          }

        });

        function filterMetrics(term, metrics) {

          var results = [];
          $.each(metrics, function () {
            if(term.length === 0 || this.text.toUpperCase().indexOf(term.toUpperCase()) >= 0 ){
                results.push({id: this.id, text: this.text });
            }
          });
          return results;

        }

        function getUserMetrics(model, term, done) {

          var context = model.get('context');
          var metrics = self.get('metricsList');

          self.HTTP.rest('metrics/user' + model.get('context'), function (response, status) {

            if (response.error) {

              Em.debug(response.error);

            } else {

              if (response.result.length) {

                var userMetrics = [], result = response.result, i = result.length;
                while (i--) {

                  var path = '/user' + context + '/' + window.encodeURIComponent(result[i].metric);
                  var j = metrics.length, found = false;

                  while (j--) {
                    if (metrics[j].id === path) {
                      found = true;
                    }
                  }

                  if (!found) {
                    userMetrics.push({
                      id: path,
                      text: result[i].metric
                    });
                  }
                }

                metrics = metrics.concat(userMetrics);
                self.set('metricsList', metrics);
                done({results: filterMetrics(term, metrics)});

              } else {

                done({results: filterMetrics(term, metrics)});

              }
            }
          });
        }

        $("#metricSelector").select2({
            placeholder: "Select Metric",
            query: function(query) {

              var model = self.configuring.element;
              var metrics = self.metricsCache.get(model.type);

              if (metrics) {

                // The element supports user-defined metrics. (Runnable)
                if (model.get('context')) {
                  getUserMetrics(model, query.term, query.callback);

                } else {
                  query.callback({results: filterMetrics(query.term, metrics)});

                }

              } else {

                self.HTTP.rest('metrics', 'system', model.type, function (metrics, status) {

                  var i = metrics.length;
                  while (i--) {
                    metrics[i] = {
                      id: metrics[i].path,
                      text: metrics[i].name
                    };
                  }

                  self.get('metricsCache').set(model.type, metrics);
                  self.set('metricsList', metrics);

                  // The element supports user-defined metrics. (Runnable)
                  if (model.get('context')) {
                    getUserMetrics(model, query.term, query.callback);

                  } else {
                    query.callback({results: filterMetrics(query.term, metrics)});

                  }

                });

              }

            }

        });
        $("#metricSelector").on('change', function (e) {

          if (e.added) {
            self.selectMetric({
              name: e.added.text,
              path: e.added.id
            });
          }

        });

      }, 500);

      function sortByKey (obj) {

        var keys = [];
        var sorted_obj = {};

        for(var key in obj){
            if(obj.hasOwnProperty(key)){
                keys.push(key);
            }
        }
        keys.sort();
        $.each(keys, function(i, key){
            sorted_obj[key] = obj[key];
        });

        return sorted_obj;

      }

      /*
       * Get all available Elements for selection.
       */
      var i = AVAILABLE_TYPES.length;
      var singular = {
        'apps': 'App',
        'streams': 'Stream',
        'flows': 'Flow',
        'mapreduce': 'Mapreduce',
        'datasets': 'Dataset',
        'procedures': 'Procedure'
      };

      // This format is used by the select2 box to render in groups.
      var byType = {};
      var remaining = i;

      while (i--) {
        (function (nextType) {

          self.HTTP.rest(nextType, function (models, status) {

            var i = models.length;
            while (i--) {
              if (C[singular[nextType]]) {
                models[i] = C[singular[nextType]].create(models[i]);
                self.elementModels.push(models[i]);
              }
            }

            $.each(models, function (i, element) {

              var id = element.type + '|' + element.id;

              if (byType[element.type]) {
                byType[element.type].push({
                  id: id,
                  text: element.name
                });
              } else {
                byType[element.type] = [{
                  id: id,
                  text: element.name
                }];
              }

            });

            if (!--remaining) {

              byType = sortByKey(byType);

              for (var type in byType) {
                self.elementsCache.push({
                  text: type + 's',
                  children: byType[type]
                });
              }

            }

          });

        })(AVAILABLE_TYPES[i]);
      }

      this.set('paused', false);

      this.set('interval', setInterval(function () {

        if (!self.get('paused')) {
          self.update();
        }

      }, 1000));

    },

    unload: function () {

      this.set('elementModels', []);
      this.set('elementsCache', []);
      this.set('metricsCache', Em.Object.create());

      clearInterval(this.get('interval'));

      // This is set in the Analyze embeddable.
      C.removeResizeHandler('metrics-explorer');

    },

    update: function () {

      var self = this;
      var urls = [];

      var selected = this.get('selected');
      var start, now = new Date().getTime();

      // Add a two second buffer to make sure we have a full response.
      start = now - ((C.__timeRange + 2) * 1000);
      start = Math.floor(start / 1000);

      this.get('selected').forEach(function (item) {
        urls.push(item.path + '?start=' + start + '&count=' + C.__timeRange);
      });

      function findMetric (path) {
        var i = selected.content.length;
        while (i --) {
          if (path.indexOf(selected.content[i].path) === 0) {
            return selected.content[i];
          }
        }
      }
      if (!Em.isEmpty(urls)) {
        this.HTTP.post('metrics', urls, function (response, status) {

          if (response.result) {

            var s = null, series = [], selected = self.get('selected.content'),
              result = response.result, metric, d;

            for (var i = 0; i < result.length; i ++) {

              if ((metric = findMetric(result[i].path))) {

                s = {
                  name: metric.metric + ' (' + metric.element + ', ' + metric.type + ')',
                  color: metric.color,
                  data: []
                }, d = response.result[i].result.data;

                for (var j = 0; j < d.length; j ++) {
                  s.data.push({
                    x: d[j].time,
                    y: d[j].value
                  });
                }

                series.push(s);

              }

            }
            self.set('series', series);

          }

        });
      }

    }.observes('selected.[]'),

    paused: false,
    pausedLabel: function () {

      return this.get('paused') ? 'Continue' : 'Pause';

    }.property('paused').cacheable(false),
    togglePause: function () {

      this.set('paused', !this.get('paused'));

    },

    showConfigure: function (metric) {

      this.configuring.set('element', { name: 'Elements' });
      this.configuring.set('metric', { name: 'Metric Names' });

      $("#elementSelector").select2('val', null);
      $("#metricSelector").select2('val', null);
      $('#analyze-configurator').fadeIn(100);

    },

    hideConfigure: function () {

      $('#analyze-configurator').fadeOut(100);

    },

    selectElement: function (model) {

      this.configuring.set('element', model);
      $("#metricSelector").select2("enable", true);

    },

    selectMetric: function (metric) {

      this.configuring.set('metric', metric);

    },

    addToChart: function () {

      var element = this.get('configuring.element');
      var metric = this.get('configuring.metric');

      var path = element.interpolate(metric.path);
      var selected = {
        element: element.name,
        type: element.type,
        metric: metric.name,
        path: path,
        color: this.get('palette').color(),
        href: element.get('href')
      };

      this.get('selected').pushObject(selected);

      this.saveLocal();
      this.hideConfigure();

    },

    removeFromChart: function (selected) {

      this.get('selected').removeObject(selected);
      this.saveLocal();
      this.hideConfigure();

    },

    /**
     * Saves selection state to localstorage.
     */
    saveLocal: function() {
      localStorage.setItem(STORED_APP_NAME, JSON.stringify(this.get('selected')));
    }

  });

  Controller.reopenClass({
    type: 'Analyze',
    kind: 'Controller'
  });

  return Controller;

});
<commit_msg>Changing color interpolation to default<commit_after>/*
 * Analyze Controller.
 * This manages all actions executed from metrics explorer.
 */

define(['../../helpers/chart-helper'], function (chartHelper) {

  // Used for local storage, which is used to store our metrics selection.
  var STORED_APP_NAME = 'continuuity-analyze';

  // Used to query for available element types from REST.
  var AVAILABLE_TYPES = ['apps', 'streams', 'flows', 'mapreduce', 'datasets', 'procedures'];

  var Controller = Em.Controller.extend(Em.Evented, {

    elementModels: [],

    // Holds available element models.
    elementsCache: [],

    // Holds a per-type cache of available metrics.
    metricsCache: Em.Object.create(),

    // Holds the currently selected metrics.
    selected: Em.ArrayProxy.create({ content: [] }),

    // Holds temporary information from the 'Add Metric' form.
    configuring: Em.Object.extend({
      noSelection: function () {
        return this.get('element.name') === 'Elements' ||
          this.get('metric.name') === 'Metric Names';
      }.property('element', 'metric'),
      element: {
        name: 'Elements'
      },
      metric: {
        name: 'Metric Names'
      }
    }),

    init: function () {

      /*
       * Only 'extend' allows computed properties, as above.
       * Therefore we create / construct here.
       */
      this.set('configuring', this.get('configuring').create());

    },

    load: function (id) {

      var self = this;

      this.set('palette', new Rickshaw.Color.Palette({ scheme: 'colorwheel'  }));

      this.set('selected', Em.ArrayProxy.create({ content: [] }));

      /*
       * Prepopulate metrics selection from Local Storage if available.
       */
      if (window.localStorage) {

        var saved = localStorage.getItem(STORED_APP_NAME);
        if (saved) {
          this.set('selected.content', JSON.parse(saved).content);
        }

      }

      var self = this;

      this.get('selected').forEach(function (item, index) {

        item.color = self.get('palette').color();

      });

      function findElement(type, id) {

        var models = self.elementModels, i = models.length;
        while (i--) {
          if (models[i].type === type && models[i].id === id) {
            return models[i];
          }
        }
        return null;

      }

      // Needs time to find elements. Move to run loop.
      setTimeout(function () {

        $("#elementSelector").select2({
            containerCssClass: "analyze-configurator-element-select",
            placeholder: "Select Element",
            query: function(query) {

              var data = [];

              $.each(self.elementsCache, function(){

                var children = [];
                $.each(this.children, function () {
                  if(query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
                      children.push({id: this.id, text: this.text });
                  }
                });
                this.children = children;
                if (children.length) {
                  data.push(this);
                }
              });
              query.callback({results: data});

            }
        });
        $("#elementSelector").on('change', function (e) {

          if (e.added) {
            var id = e.added.id.split('|');
            var element = findElement(id[0], id[1]);
            self.selectElement(element);
          }

        });

        function filterMetrics(term, metrics) {

          var results = [];
          $.each(metrics, function () {
            if(term.length === 0 || this.text.toUpperCase().indexOf(term.toUpperCase()) >= 0 ){
                results.push({id: this.id, text: this.text });
            }
          });
          return results;

        }

        function getUserMetrics(model, term, done) {

          var context = model.get('context');
          var metrics = self.get('metricsList');

          self.HTTP.rest('metrics/user' + model.get('context'), function (response, status) {

            if (response.error) {

              Em.debug(response.error);

            } else {

              if (response.result.length) {

                var userMetrics = [], result = response.result, i = result.length;
                while (i--) {

                  var path = '/user' + context + '/' + window.encodeURIComponent(result[i].metric);
                  var j = metrics.length, found = false;

                  while (j--) {
                    if (metrics[j].id === path) {
                      found = true;
                    }
                  }

                  if (!found) {
                    userMetrics.push({
                      id: path,
                      text: result[i].metric
                    });
                  }
                }

                metrics = metrics.concat(userMetrics);
                self.set('metricsList', metrics);
                done({results: filterMetrics(term, metrics)});

              } else {

                done({results: filterMetrics(term, metrics)});

              }
            }
          });
        }

        $("#metricSelector").select2({
            placeholder: "Select Metric",
            query: function(query) {

              var model = self.configuring.element;
              var metrics = self.metricsCache.get(model.type);

              if (metrics) {

                // The element supports user-defined metrics. (Runnable)
                if (model.get('context')) {
                  getUserMetrics(model, query.term, query.callback);

                } else {
                  query.callback({results: filterMetrics(query.term, metrics)});

                }

              } else {

                self.HTTP.rest('metrics', 'system', model.type, function (metrics, status) {

                  var i = metrics.length;
                  while (i--) {
                    metrics[i] = {
                      id: metrics[i].path,
                      text: metrics[i].name
                    };
                  }

                  self.get('metricsCache').set(model.type, metrics);
                  self.set('metricsList', metrics);

                  // The element supports user-defined metrics. (Runnable)
                  if (model.get('context')) {
                    getUserMetrics(model, query.term, query.callback);

                  } else {
                    query.callback({results: filterMetrics(query.term, metrics)});

                  }

                });

              }

            }

        });
        $("#metricSelector").on('change', function (e) {

          if (e.added) {
            self.selectMetric({
              name: e.added.text,
              path: e.added.id
            });
          }

        });

      }, 500);

      function sortByKey (obj) {

        var keys = [];
        var sorted_obj = {};

        for(var key in obj){
            if(obj.hasOwnProperty(key)){
                keys.push(key);
            }
        }
        keys.sort();
        $.each(keys, function(i, key){
            sorted_obj[key] = obj[key];
        });

        return sorted_obj;

      }

      /*
       * Get all available Elements for selection.
       */
      var i = AVAILABLE_TYPES.length;
      var singular = {
        'apps': 'App',
        'streams': 'Stream',
        'flows': 'Flow',
        'mapreduce': 'Mapreduce',
        'datasets': 'Dataset',
        'procedures': 'Procedure'
      };

      // This format is used by the select2 box to render in groups.
      var byType = {};
      var remaining = i;

      while (i--) {
        (function (nextType) {

          self.HTTP.rest(nextType, function (models, status) {

            var i = models.length;
            while (i--) {
              if (C[singular[nextType]]) {
                models[i] = C[singular[nextType]].create(models[i]);
                self.elementModels.push(models[i]);
              }
            }

            $.each(models, function (i, element) {

              var id = element.type + '|' + element.id;

              if (byType[element.type]) {
                byType[element.type].push({
                  id: id,
                  text: element.name
                });
              } else {
                byType[element.type] = [{
                  id: id,
                  text: element.name
                }];
              }

            });

            if (!--remaining) {

              byType = sortByKey(byType);

              for (var type in byType) {
                self.elementsCache.push({
                  text: type + 's',
                  children: byType[type]
                });
              }

            }

          });

        })(AVAILABLE_TYPES[i]);
      }

      this.set('paused', false);

      this.set('interval', setInterval(function () {

        if (!self.get('paused')) {
          self.update();
        }

      }, 1000));

    },

    unload: function () {

      this.set('elementModels', []);
      this.set('elementsCache', []);
      this.set('metricsCache', Em.Object.create());

      clearInterval(this.get('interval'));

      // This is set in the Analyze embeddable.
      C.removeResizeHandler('metrics-explorer');

    },

    update: function () {

      var self = this;
      var urls = [];

      var selected = this.get('selected');
      var start, now = new Date().getTime();

      // Add a two second buffer to make sure we have a full response.
      start = now - ((C.__timeRange + 2) * 1000);
      start = Math.floor(start / 1000);

      this.get('selected').forEach(function (item) {
        urls.push(item.path + '?start=' + start + '&count=' + C.__timeRange);
      });

      function findMetric (path) {
        var i = selected.content.length;
        while (i --) {
          if (path.indexOf(selected.content[i].path) === 0) {
            return selected.content[i];
          }
        }
      }
      if (!Em.isEmpty(urls)) {
        this.HTTP.post('metrics', urls, function (response, status) {

          if (response.result) {

            var s = null, series = [], selected = self.get('selected.content'),
              result = response.result, metric, d;

            for (var i = 0; i < result.length; i ++) {

              if ((metric = findMetric(result[i].path))) {

                s = {
                  name: metric.metric + ' (' + metric.element + ', ' + metric.type + ')',
                  color: metric.color,
                  data: []
                }, d = response.result[i].result.data;

                for (var j = 0; j < d.length; j ++) {
                  s.data.push({
                    x: d[j].time,
                    y: d[j].value
                  });
                }

                series.push(s);

              }

            }
            self.set('series', series);

          }

        });
      }

    }.observes('selected.[]'),

    paused: false,
    pausedLabel: function () {

      return this.get('paused') ? 'Continue' : 'Pause';

    }.property('paused').cacheable(false),
    togglePause: function () {

      this.set('paused', !this.get('paused'));

    },

    showConfigure: function (metric) {

      this.configuring.set('element', { name: 'Elements' });
      this.configuring.set('metric', { name: 'Metric Names' });

      $("#elementSelector").select2('val', null);
      $("#metricSelector").select2('val', null);
      $('#analyze-configurator').fadeIn(100);

    },

    hideConfigure: function () {

      $('#analyze-configurator').fadeOut(100);

    },

    selectElement: function (model) {

      this.configuring.set('element', model);
      $("#metricSelector").select2("enable", true);

    },

    selectMetric: function (metric) {

      this.configuring.set('metric', metric);

    },

    addToChart: function () {

      var element = this.get('configuring.element');
      var metric = this.get('configuring.metric');

      var path = element.interpolate(metric.path);
      var selected = {
        element: element.name,
        type: element.type,
        metric: metric.name,
        path: path,
        color: this.get('palette').color(),
        href: element.get('href')
      };

      this.get('selected').pushObject(selected);

      this.saveLocal();
      this.hideConfigure();

    },

    removeFromChart: function (selected) {

      this.get('selected').removeObject(selected);
      this.saveLocal();
      this.hideConfigure();

    },

    /**
     * Saves selection state to localstorage.
     */
    saveLocal: function() {
      localStorage.setItem(STORED_APP_NAME, JSON.stringify(this.get('selected')));
    }

  });

  Controller.reopenClass({
    type: 'Analyze',
    kind: 'Controller'
  });

  return Controller;

});
<|endoftext|>


<commit_before>var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
var SoundEvent = require('../SoundEvent');
var SoundValueEvent = require('../SoundValueEvent');
/*!
 * @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
 */
var WebAudioSound = new Class({
    Extends: BaseSound,
    /**
     * @class Phaser.Sound.WebAudioSound
     * @constructor
     * @param {Phaser.Sound.WebAudioSoundManager} manager - Reference to the current sound manager instance.
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig} [config={}] - An optional config object containing default sound settings.
     */
    initialize: function WebAudioSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        /**
         * Audio buffer containing decoded data of the audio asset to be played.
         *
         * @private
         * @property {AudioBuffer} audioBuffer
         */
        this.audioBuffer = manager.game.cache.audio.get(key);
        if (!this.audioBuffer) {
            console.error('No audio loaded in cache with key: \'' + key + '\'!');
            return;
        }
        /**
         * A reference to an audio source node used for playing back audio from
         * audio data stored in an Phaser.Sound.WebAudioSound#audioBuffer.
         *
         * @private
         * @property {AudioBufferSourceNode} source
         * @default null
         */
        this.source = null;
        /**
         * A reference to a second audio source used for gapless looped playback.
         *
         * @private
         * @property {AudioBufferSourceNode} loopSource
         * @default null
         */
        this.loopSource = null;
        /**
         * Gain node responsible for controlling this sound's muting.
         *
         * @private
         * @property {GainNode} muteNode
         */
        this.muteNode = manager.context.createGain();
        /**
         * Gain node responsible for controlling this sound's volume.
         *
         * @private
         * @property {GainNode} volumeNode
         */
        this.volumeNode = manager.context.createGain();
        /**
         * The time at which the sound should have started playback from the beginning.
         * Based on BaseAudioContext.currentTime value.
         *
         * @private
         * @property {number} playTime
         * @default 0
         */
        this.playTime = 0;
        /**
         * The time at which the sound source should have actually started playback.
         * Based on BaseAudioContext.currentTime value.
         *
         * @private
         * @property {number} startTime
         * @default 0
         */
        this.startTime = 0;
        /**
         * The time at which the sound loop source should actually start playback.
         * Based on BaseAudioContext.currentTime value.
         *
         * @private
         * @property {number} loopTime
         * @default 0
         */
        this.loopTime = 0;
        /**
         * An array where we keep track of all rate updates during playback.
         *
         * @private
         * @property {{ time: number, rate: number }[]} rateUpdates
         * @default []
         */
        this.rateUpdates = [];
        /**
         * Used for keeping track when sound source playback has ended
         * so its state can be updated accordingly.
         *
         * @private
         * @property {boolean} hasEnded
         * @default false
         */
        this.hasEnded = false;
        /**
         * Used for keeping track when sound source has looped
         * so its state can be updated accordingly.
         *
         * @private
         * @property {boolean} hasLooped
         * @default false
         */
        this.hasLooped = false;
        this.muteNode.connect(this.volumeNode);
        this.volumeNode.connect(manager.destination);
        this.duration = this.audioBuffer.duration;
        this.totalDuration = this.audioBuffer.duration;
        BaseSound.call(this, manager, key, config);
    },
    /**
     * Play this sound, or a marked section of it.
     * It always plays the sound from the start. If you want to start playback from a specific time
     * you can set 'seek' setting of the config object, provided to this call, to that value.
     *
     * @method Phaser.Sound.WebAudioSound#play
     * @param {string} [markerName=''] - If you want to play a marker then provide the marker name here, otherwise omit it to play the full sound.
     * @param {ISoundConfig} [config] - Optional sound config object to be applied to this marker or entire sound if no marker name is provided. It gets memorized for future plays of current section of the sound.
     * @returns {Phaser.Sound.WebAudioSound | null} This sound instance or 'null' if an error occurred.
     */
    play: function (markerName, config) {
        if (!BaseSound.prototype.play.call(this, markerName, config)) {
            return null;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        this.stopAndRemoveBufferSource();
        this.createAndStartBufferSource();
        this.events.dispatch(new SoundEvent(this, 'SOUND_PLAY'));
        return this;
    },
    /**
     * Pauses the sound.
     *
     * @method Phaser.Sound.WebAudioSound#pause
     * @returns {boolean} Whether the sound was paused successfully.
     */
    pause: function () {
        if (this.manager.context.currentTime < this.startTime) {
            return false;
        }
        if (!BaseSound.prototype.pause.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = true \/\/\/
        this.currentConfig.seek = this.getCurrentTime(); // Equivalent to setting paused time
        this.stopAndRemoveBufferSource();
        this.events.dispatch(new SoundEvent(this, 'SOUND_PAUSE'));
        return true;
    },
    /**
     * Resumes the sound.
     *
     * @method Phaser.Sound.WebAudioSound#resume
     * @returns {boolean} Whether the sound was resumed successfully.
     */
    resume: function () {
        if (this.manager.context.currentTime < this.startTime) {
            return false;
        }
        if (!BaseSound.prototype.resume.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        this.createAndStartBufferSource();
        this.events.dispatch(new SoundEvent(this, 'SOUND_RESUME'));
        return true;
    },
    /**
     * Stop playing this sound.
     *
     * @method Phaser.Sound.WebAudioSound#stop
     * @returns {boolean} Whether the sound was stopped successfully.
     */
    stop: function () {
        if (!BaseSound.prototype.stop.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = false \/\/\/
        this.stopAndRemoveBufferSource();
        this.events.dispatch(new SoundEvent(this, 'SOUND_STOP'));
        return true;
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#createAndStartBufferSource
     */
    createAndStartBufferSource: function () {
        var seek = this.currentConfig.seek;
        var delay = this.currentConfig.delay;
        var when = this.manager.context.currentTime + delay;
        var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
        var duration = this.duration - seek;
        this.playTime = when - seek;
        this.startTime = when;
        this.source = this.createBufferSource();
        this.applyConfig();
        this.source.start(Math.max(0, when), Math.max(0, offset), Math.max(0, duration));
        this.resetConfig();
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#createAndStartLoopBufferSource
     */
    createAndStartLoopBufferSource: function () {
        var when = this.getLoopTime();
        var offset = this.currentMarker ? this.currentMarker.start : 0;
        var duration = this.duration;
        this.loopTime = when;
        this.loopSource = this.createBufferSource();
        this.loopSource.playbackRate.setValueAtTime(this.totalRate, 0);
        this.loopSource.start(Math.max(0, when), Math.max(0, offset), Math.max(0, duration));
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#createBufferSource
     */
    createBufferSource: function () {
        var _this = this;
        var source = this.manager.context.createBufferSource();
        source.buffer = this.audioBuffer;
        source.connect(this.muteNode);
        source.onended = function (ev) {
            if (ev.target === _this.source) {
                // sound ended
                if (_this.currentConfig.loop) {
                    _this.hasLooped = true;
                }
                else {
                    _this.hasEnded = true;
                }
            }
            // else was stopped
        };
        return source;
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#stopAndRemoveBufferSource
     */
    stopAndRemoveBufferSource: function () {
        if (this.source) {
            this.source.stop();
            this.source.disconnect();
            this.source = null;
        }
        this.playTime = 0;
        this.startTime = 0;
        this.stopAndRemoveLoopBufferSource();
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     */
    stopAndRemoveLoopBufferSource: function () {
        if (this.loopSource) {
            this.loopSource.stop();
            this.loopSource.disconnect();
            this.loopSource = null;
        }
        this.loopTime = 0;
    },
    /**
     * @protected
     */
    applyConfig: function () {
        this.rateUpdates.length = 0;
        this.rateUpdates.push({
            time: 0,
            rate: 1
        });
        BaseSound.prototype.applyConfig.call(this);
    },
    /**
     * Update method called on every game step.
     *
     * @param {number} time - The current timestamp as generated by the Request Animation Frame or SetTimeout.
     * @param {number} delta - The delta time elapsed since the last frame.
     */
    update: function (time, delta) {
        if (this.hasEnded) {
            this.hasEnded = false;
            BaseSound.prototype.stop.call(this);
            this.stopAndRemoveBufferSource();
            this.events.dispatch(new SoundEvent(this, 'SOUND_ENDED'));
        }
        else if (this.hasLooped) {
            this.hasLooped = false;
            this.source = this.loopSource;
            this.loopSource = null;
            this.playTime = this.startTime = this.loopTime;
            this.rateUpdates.length = 0;
            this.rateUpdates.push({
                time: 0,
                rate: this.totalRate
            });
            this.createAndStartLoopBufferSource();
            this.events.dispatch(new SoundEvent(this, 'SOUND_LOOP'));
        }
    },
    destroy: function () {
        BaseSound.prototype.destroy.call(this);
        this.audioBuffer = null;
        this.stopAndRemoveBufferSource();
        this.muteNode.disconnect();
        this.muteNode = null;
        this.volumeNode.disconnect();
        this.volumeNode = null;
        this.rateUpdates = null;
    },
    /**
     * @private
     */
    setRate: function () {
        BaseSound.prototype.setRate.call(this);
        var now = this.manager.context.currentTime;
        if (this.source) {
            this.source.playbackRate.setValueAtTime(this.totalRate, now);
        }
        if (this.isPlaying) {
            this.rateUpdates.push({
                time: Math.max(this.startTime, now) - this.playTime,
                rate: this.totalRate
            });
            if (this.loopSource) {
                this.stopAndRemoveLoopBufferSource();
                this.createAndStartLoopBufferSource();
            }
        }
    },
    /**
     * @private
     */
    getCurrentTime: function () {
        var currentTime = 0;
        for (var i = 0; i < this.rateUpdates.length; i++) {
            var nextTime = void 0;
            if (i < this.rateUpdates.length - 1) {
                nextTime = this.rateUpdates[i + 1].time;
            }
            else {
                nextTime = this.manager.context.currentTime - this.playTime;
            }
            currentTime += (nextTime - this.rateUpdates[i].time) * this.rateUpdates[i].rate;
        }
        return currentTime;
    },
    /**
     * @private
     */
    getLoopTime: function () {
        var lastRateUpdateCurrentTime = 0;
        for (var i = 0; i < this.rateUpdates.length - 1; i++) {
            lastRateUpdateCurrentTime +=
                (this.rateUpdates[i + 1].time - this.rateUpdates[i].time) * this.rateUpdates[i].rate;
        }
        var lastRateUpdate = this.rateUpdates[this.rateUpdates.length - 1];
        return this.playTime + lastRateUpdate.time
            + (this.duration - lastRateUpdateCurrentTime) / lastRateUpdate.rate;
    }
});
/**
 * Mute setting.
 * @property {boolean} mute
 */
Object.defineProperty(WebAudioSound.prototype, 'mute', {
    get: function () {
        return this.muteNode.gain.value === 0;
    },
    set: function (value) {
        this.currentConfig.mute = value;
        this.muteNode.gain.setValueAtTime(value ? 0 : 1, 0);
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_MUTE', value));
    }
});
/**
 * Volume setting.
 * @property {number} volume
 */
Object.defineProperty(WebAudioSound.prototype, 'volume', {
    get: function () {
        return this.volumeNode.gain.value;
    },
    set: function (value) {
        this.currentConfig.volume = value;
        this.volumeNode.gain.setValueAtTime(value, 0);
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_VOLUME', value));
    }
});
/**
 * Playback rate.
 * @property {number} rate
 */
Object.defineProperty(WebAudioSound.prototype, 'rate', {
    get: function () {
        return this.currentConfig.rate;
    },
    set: function (value) {
        this.currentConfig.rate = value;
        this.setRate();
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_RATE', value));
    }
});
/**
 * Detuning of sound.
 * @property {number} detune
 */
Object.defineProperty(WebAudioSound.prototype, 'detune', {
    get: function () {
        return this.currentConfig.detune;
    },
    set: function (value) {
        this.currentConfig.detune = value;
        this.setRate();
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_DETUNE', value));
    }
});
/**
 * Current position of playing sound.
 * @property {number} seek
 */
Object.defineProperty(WebAudioSound.prototype, 'seek', {
    get: function () {
        if (this.isPlaying) {
            if (this.manager.context.currentTime < this.startTime) {
                return this.startTime - this.playTime;
            }
            return this.getCurrentTime();
        }
        else if (this.isPaused) {
            return this.currentConfig.seek;
        }
        else {
            return 0;
        }
    },
    set: function (value) {
        if (this.manager.context.currentTime < this.startTime) {
            return;
        }
        if (this.isPlaying || this.isPaused) {
            value = Math.min(Math.max(0, value), this.duration);
            this.currentConfig.seek = value;
            this.events.dispatch(new SoundValueEvent(this, 'SOUND_SEEK', value));
        }
        if (this.isPlaying) {
            this.stopAndRemoveBufferSource();
            this.createAndStartBufferSource();
        }
    }
});
/**
 * Property indicating whether or not
 * the sound or current sound marker will loop.
 *
 * @property {boolean} loop
 */
Object.defineProperty(WebAudioSound.prototype, 'loop', {
    get: function () {
        return this.currentConfig.loop;
    },
    set: function (value) {
        this.currentConfig.loop = value;
        if (this.isPlaying) {
            this.stopAndRemoveLoopBufferSource();
            if (value) {
                this.createAndStartLoopBufferSource();
            }
        }
    }
});
module.exports = WebAudioSound;
<commit_msg>Updated stopAndRemoveLoopBufferSource method docs<commit_after>var Class = require('../../utils/Class');
var BaseSound = require('../BaseSound');
var SoundEvent = require('../SoundEvent');
var SoundValueEvent = require('../SoundValueEvent');
/*!
 * @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
 */
var WebAudioSound = new Class({
    Extends: BaseSound,
    /**
     * @class Phaser.Sound.WebAudioSound
     * @constructor
     * @param {Phaser.Sound.WebAudioSoundManager} manager - Reference to the current sound manager instance.
     * @param {string} key - Asset key for the sound.
     * @param {ISoundConfig} [config={}] - An optional config object containing default sound settings.
     */
    initialize: function WebAudioSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        /**
         * Audio buffer containing decoded data of the audio asset to be played.
         *
         * @private
         * @property {AudioBuffer} audioBuffer
         */
        this.audioBuffer = manager.game.cache.audio.get(key);
        if (!this.audioBuffer) {
            console.error('No audio loaded in cache with key: \'' + key + '\'!');
            return;
        }
        /**
         * A reference to an audio source node used for playing back audio from
         * audio data stored in an Phaser.Sound.WebAudioSound#audioBuffer.
         *
         * @private
         * @property {AudioBufferSourceNode} source
         * @default null
         */
        this.source = null;
        /**
         * A reference to a second audio source used for gapless looped playback.
         *
         * @private
         * @property {AudioBufferSourceNode} loopSource
         * @default null
         */
        this.loopSource = null;
        /**
         * Gain node responsible for controlling this sound's muting.
         *
         * @private
         * @property {GainNode} muteNode
         */
        this.muteNode = manager.context.createGain();
        /**
         * Gain node responsible for controlling this sound's volume.
         *
         * @private
         * @property {GainNode} volumeNode
         */
        this.volumeNode = manager.context.createGain();
        /**
         * The time at which the sound should have started playback from the beginning.
         * Based on BaseAudioContext.currentTime value.
         *
         * @private
         * @property {number} playTime
         * @default 0
         */
        this.playTime = 0;
        /**
         * The time at which the sound source should have actually started playback.
         * Based on BaseAudioContext.currentTime value.
         *
         * @private
         * @property {number} startTime
         * @default 0
         */
        this.startTime = 0;
        /**
         * The time at which the sound loop source should actually start playback.
         * Based on BaseAudioContext.currentTime value.
         *
         * @private
         * @property {number} loopTime
         * @default 0
         */
        this.loopTime = 0;
        /**
         * An array where we keep track of all rate updates during playback.
         *
         * @private
         * @property {{ time: number, rate: number }[]} rateUpdates
         * @default []
         */
        this.rateUpdates = [];
        /**
         * Used for keeping track when sound source playback has ended
         * so its state can be updated accordingly.
         *
         * @private
         * @property {boolean} hasEnded
         * @default false
         */
        this.hasEnded = false;
        /**
         * Used for keeping track when sound source has looped
         * so its state can be updated accordingly.
         *
         * @private
         * @property {boolean} hasLooped
         * @default false
         */
        this.hasLooped = false;
        this.muteNode.connect(this.volumeNode);
        this.volumeNode.connect(manager.destination);
        this.duration = this.audioBuffer.duration;
        this.totalDuration = this.audioBuffer.duration;
        BaseSound.call(this, manager, key, config);
    },
    /**
     * Play this sound, or a marked section of it.
     * It always plays the sound from the start. If you want to start playback from a specific time
     * you can set 'seek' setting of the config object, provided to this call, to that value.
     *
     * @method Phaser.Sound.WebAudioSound#play
     * @param {string} [markerName=''] - If you want to play a marker then provide the marker name here, otherwise omit it to play the full sound.
     * @param {ISoundConfig} [config] - Optional sound config object to be applied to this marker or entire sound if no marker name is provided. It gets memorized for future plays of current section of the sound.
     * @returns {Phaser.Sound.WebAudioSound | null} This sound instance or 'null' if an error occurred.
     */
    play: function (markerName, config) {
        if (!BaseSound.prototype.play.call(this, markerName, config)) {
            return null;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        this.stopAndRemoveBufferSource();
        this.createAndStartBufferSource();
        this.events.dispatch(new SoundEvent(this, 'SOUND_PLAY'));
        return this;
    },
    /**
     * Pauses the sound.
     *
     * @method Phaser.Sound.WebAudioSound#pause
     * @returns {boolean} Whether the sound was paused successfully.
     */
    pause: function () {
        if (this.manager.context.currentTime < this.startTime) {
            return false;
        }
        if (!BaseSound.prototype.pause.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = true \/\/\/
        this.currentConfig.seek = this.getCurrentTime(); // Equivalent to setting paused time
        this.stopAndRemoveBufferSource();
        this.events.dispatch(new SoundEvent(this, 'SOUND_PAUSE'));
        return true;
    },
    /**
     * Resumes the sound.
     *
     * @method Phaser.Sound.WebAudioSound#resume
     * @returns {boolean} Whether the sound was resumed successfully.
     */
    resume: function () {
        if (this.manager.context.currentTime < this.startTime) {
            return false;
        }
        if (!BaseSound.prototype.resume.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = true, isPaused = false \/\/\/
        this.createAndStartBufferSource();
        this.events.dispatch(new SoundEvent(this, 'SOUND_RESUME'));
        return true;
    },
    /**
     * Stop playing this sound.
     *
     * @method Phaser.Sound.WebAudioSound#stop
     * @returns {boolean} Whether the sound was stopped successfully.
     */
    stop: function () {
        if (!BaseSound.prototype.stop.call(this)) {
            return false;
        }
        //  \/\/\/ isPlaying = false, isPaused = false \/\/\/
        this.stopAndRemoveBufferSource();
        this.events.dispatch(new SoundEvent(this, 'SOUND_STOP'));
        return true;
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#createAndStartBufferSource
     */
    createAndStartBufferSource: function () {
        var seek = this.currentConfig.seek;
        var delay = this.currentConfig.delay;
        var when = this.manager.context.currentTime + delay;
        var offset = (this.currentMarker ? this.currentMarker.start : 0) + seek;
        var duration = this.duration - seek;
        this.playTime = when - seek;
        this.startTime = when;
        this.source = this.createBufferSource();
        this.applyConfig();
        this.source.start(Math.max(0, when), Math.max(0, offset), Math.max(0, duration));
        this.resetConfig();
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#createAndStartLoopBufferSource
     */
    createAndStartLoopBufferSource: function () {
        var when = this.getLoopTime();
        var offset = this.currentMarker ? this.currentMarker.start : 0;
        var duration = this.duration;
        this.loopTime = when;
        this.loopSource = this.createBufferSource();
        this.loopSource.playbackRate.setValueAtTime(this.totalRate, 0);
        this.loopSource.start(Math.max(0, when), Math.max(0, offset), Math.max(0, duration));
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#createBufferSource
     */
    createBufferSource: function () {
        var _this = this;
        var source = this.manager.context.createBufferSource();
        source.buffer = this.audioBuffer;
        source.connect(this.muteNode);
        source.onended = function (ev) {
            if (ev.target === _this.source) {
                // sound ended
                if (_this.currentConfig.loop) {
                    _this.hasLooped = true;
                }
                else {
                    _this.hasEnded = true;
                }
            }
            // else was stopped
        };
        return source;
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#stopAndRemoveBufferSource
     */
    stopAndRemoveBufferSource: function () {
        if (this.source) {
            this.source.stop();
            this.source.disconnect();
            this.source = null;
        }
        this.playTime = 0;
        this.startTime = 0;
        this.stopAndRemoveLoopBufferSource();
    },
    /**
     * Used internally to do what the name says.
     *
     * @private
     * @method Phaser.Sound.WebAudioSound#stopAndRemoveLoopBufferSource
     */
    stopAndRemoveLoopBufferSource: function () {
        if (this.loopSource) {
            this.loopSource.stop();
            this.loopSource.disconnect();
            this.loopSource = null;
        }
        this.loopTime = 0;
    },
    /**
     * @protected
     */
    applyConfig: function () {
        this.rateUpdates.length = 0;
        this.rateUpdates.push({
            time: 0,
            rate: 1
        });
        BaseSound.prototype.applyConfig.call(this);
    },
    /**
     * Update method called on every game step.
     *
     * @param {number} time - The current timestamp as generated by the Request Animation Frame or SetTimeout.
     * @param {number} delta - The delta time elapsed since the last frame.
     */
    update: function (time, delta) {
        if (this.hasEnded) {
            this.hasEnded = false;
            BaseSound.prototype.stop.call(this);
            this.stopAndRemoveBufferSource();
            this.events.dispatch(new SoundEvent(this, 'SOUND_ENDED'));
        }
        else if (this.hasLooped) {
            this.hasLooped = false;
            this.source = this.loopSource;
            this.loopSource = null;
            this.playTime = this.startTime = this.loopTime;
            this.rateUpdates.length = 0;
            this.rateUpdates.push({
                time: 0,
                rate: this.totalRate
            });
            this.createAndStartLoopBufferSource();
            this.events.dispatch(new SoundEvent(this, 'SOUND_LOOP'));
        }
    },
    destroy: function () {
        BaseSound.prototype.destroy.call(this);
        this.audioBuffer = null;
        this.stopAndRemoveBufferSource();
        this.muteNode.disconnect();
        this.muteNode = null;
        this.volumeNode.disconnect();
        this.volumeNode = null;
        this.rateUpdates = null;
    },
    /**
     * @private
     */
    setRate: function () {
        BaseSound.prototype.setRate.call(this);
        var now = this.manager.context.currentTime;
        if (this.source) {
            this.source.playbackRate.setValueAtTime(this.totalRate, now);
        }
        if (this.isPlaying) {
            this.rateUpdates.push({
                time: Math.max(this.startTime, now) - this.playTime,
                rate: this.totalRate
            });
            if (this.loopSource) {
                this.stopAndRemoveLoopBufferSource();
                this.createAndStartLoopBufferSource();
            }
        }
    },
    /**
     * @private
     */
    getCurrentTime: function () {
        var currentTime = 0;
        for (var i = 0; i < this.rateUpdates.length; i++) {
            var nextTime = void 0;
            if (i < this.rateUpdates.length - 1) {
                nextTime = this.rateUpdates[i + 1].time;
            }
            else {
                nextTime = this.manager.context.currentTime - this.playTime;
            }
            currentTime += (nextTime - this.rateUpdates[i].time) * this.rateUpdates[i].rate;
        }
        return currentTime;
    },
    /**
     * @private
     */
    getLoopTime: function () {
        var lastRateUpdateCurrentTime = 0;
        for (var i = 0; i < this.rateUpdates.length - 1; i++) {
            lastRateUpdateCurrentTime +=
                (this.rateUpdates[i + 1].time - this.rateUpdates[i].time) * this.rateUpdates[i].rate;
        }
        var lastRateUpdate = this.rateUpdates[this.rateUpdates.length - 1];
        return this.playTime + lastRateUpdate.time
            + (this.duration - lastRateUpdateCurrentTime) / lastRateUpdate.rate;
    }
});
/**
 * Mute setting.
 * @property {boolean} mute
 */
Object.defineProperty(WebAudioSound.prototype, 'mute', {
    get: function () {
        return this.muteNode.gain.value === 0;
    },
    set: function (value) {
        this.currentConfig.mute = value;
        this.muteNode.gain.setValueAtTime(value ? 0 : 1, 0);
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_MUTE', value));
    }
});
/**
 * Volume setting.
 * @property {number} volume
 */
Object.defineProperty(WebAudioSound.prototype, 'volume', {
    get: function () {
        return this.volumeNode.gain.value;
    },
    set: function (value) {
        this.currentConfig.volume = value;
        this.volumeNode.gain.setValueAtTime(value, 0);
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_VOLUME', value));
    }
});
/**
 * Playback rate.
 * @property {number} rate
 */
Object.defineProperty(WebAudioSound.prototype, 'rate', {
    get: function () {
        return this.currentConfig.rate;
    },
    set: function (value) {
        this.currentConfig.rate = value;
        this.setRate();
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_RATE', value));
    }
});
/**
 * Detuning of sound.
 * @property {number} detune
 */
Object.defineProperty(WebAudioSound.prototype, 'detune', {
    get: function () {
        return this.currentConfig.detune;
    },
    set: function (value) {
        this.currentConfig.detune = value;
        this.setRate();
        this.events.dispatch(new SoundValueEvent(this, 'SOUND_DETUNE', value));
    }
});
/**
 * Current position of playing sound.
 * @property {number} seek
 */
Object.defineProperty(WebAudioSound.prototype, 'seek', {
    get: function () {
        if (this.isPlaying) {
            if (this.manager.context.currentTime < this.startTime) {
                return this.startTime - this.playTime;
            }
            return this.getCurrentTime();
        }
        else if (this.isPaused) {
            return this.currentConfig.seek;
        }
        else {
            return 0;
        }
    },
    set: function (value) {
        if (this.manager.context.currentTime < this.startTime) {
            return;
        }
        if (this.isPlaying || this.isPaused) {
            value = Math.min(Math.max(0, value), this.duration);
            this.currentConfig.seek = value;
            this.events.dispatch(new SoundValueEvent(this, 'SOUND_SEEK', value));
        }
        if (this.isPlaying) {
            this.stopAndRemoveBufferSource();
            this.createAndStartBufferSource();
        }
    }
});
/**
 * Property indicating whether or not
 * the sound or current sound marker will loop.
 *
 * @property {boolean} loop
 */
Object.defineProperty(WebAudioSound.prototype, 'loop', {
    get: function () {
        return this.currentConfig.loop;
    },
    set: function (value) {
        this.currentConfig.loop = value;
        if (this.isPlaying) {
            this.stopAndRemoveLoopBufferSource();
            if (value) {
                this.createAndStartLoopBufferSource();
            }
        }
    }
});
module.exports = WebAudioSound;
<|endoftext|>


<commit_before>//
// Strider Webapp extension for Sauce Labs tests
//

module.exports = function(ctx, cb) {
  /*
   * GET /api/sauce/
   *
   * Get the current Strider config for specified project. This will be a JSON-encoded
   * object with the keys: sauce_username, sauce_access_key and sauce_browsers
   *
   * @param url Github html_url of the project.
   */
  function getIndex(req, res) {
    var url = req.param("url")

    function error(err_msg) {
      console.error("Strider-Sauce: getIndex() - %s", err_msg)
      var r = {
        errors: [err_msg],
        status: "error"
      }
      res.statusCode = 400
      return res.end(JSON.stringify(r, null, '\t'))
    }

    Step(
      function() {
          req.user.get_repo_config(url, this)
      },
      function(err, repo, access_level, owner_user_obj) {
        if (err) {
          return error("Error fetching Repo Config for url " + url + ": " + err)
        }
        repo = repo.toJSON()
        var r = {
          status: "ok",
          errors: [],
          results: {
            sauce_username: repo.sauce_username,
            sauce_access_key: repo.sauce_access_key,
            sauce_browsers: repo.sauce_browsers,
          }
        }
        return res.end(JSON.stringify(r, null, '\t'))
      }
    )
  }

  /*
   * POST /api/sauce/
   *
   * Set the current Strider config for specified project.
   *
   * @param url Github html_url of the project.
   * @param sauce_username Sauce Labs username.
   * @param sauce_access_key Sauce Labs access key.
   * @param sauce_browsers JSON-encoded list of object tuples.
   *
   */
  function postIndex(req, res) {
    console.log("post index")
    return res.end("ok")

  }

  // Extend RepoConfig model with 'Sauce' properties
  function saucePlugin(schema, opts) {
    schema.add({
      sauce_access_key: String,
      sauce_username: String,
      sauce_browsers: [],
    })
  }
  ctx.models.RepoConfig.plugin(saucePlugin)

  // Add webserver routes
  ctx.route.get("/api/sauce",
    ctx.middleware.require_auth,
    ctx.middleware.require_params(["url"]),
    getIndex)
  ctx.route.post("/api/sauce",
    ctx.middleware.require_auth,
    ctx.middleware.require_params(["url"]),
    postIndex)

  console.log("strider-sauce webapp extension loaded")

  cb(null, null)
}
<commit_msg>don't need Step<commit_after>//
// Strider Webapp extension for Sauce Labs tests
//

module.exports = function(ctx, cb) {
  /*
   * GET /api/sauce/
   *
   * Get the current Strider config for specified project. This will be a JSON-encoded
   * object with the keys: sauce_username, sauce_access_key and sauce_browsers
   *
   * @param url Github html_url of the project.
   */
  function getIndex(req, res) {
    var url = req.param("url")

    function error(err_msg) {
      console.error("Strider-Sauce: getIndex() - %s", err_msg)
      var r = {
        errors: [err_msg],
        status: "error"
      }
      res.statusCode = 400
      return res.end(JSON.stringify(r, null, '\t'))
    }

    req.user.get_repo_config(url, function(err, repo, access_level, owner_user_obj) {
      if (err) {
        return error("Error fetching Repo Config for url " + url + ": " + err)
      }
      repo = repo.toJSON()
      var r = {
        status: "ok",
        errors: [],
        results: {
          sauce_username: repo.sauce_username,
          sauce_access_key: repo.sauce_access_key,
          sauce_browsers: repo.sauce_browsers,
        }
      }
      return res.end(JSON.stringify(r, null, '\t'))
    })
  }

  /*
   * POST /api/sauce/
   *
   * Set the current Strider config for specified project.
   *
   * @param url Github html_url of the project.
   * @param sauce_username Sauce Labs username.
   * @param sauce_access_key Sauce Labs access key.
   * @param sauce_browsers JSON-encoded list of object tuples.
   *
   */
  function postIndex(req, res) {
    console.log("post index")
    return res.end("ok")

  }

  // Extend RepoConfig model with 'Sauce' properties
  function saucePlugin(schema, opts) {
    schema.add({
      sauce_access_key: String,
      sauce_username: String,
      sauce_browsers: [],
    })
  }
  ctx.models.RepoConfig.plugin(saucePlugin)

  // Add webserver routes
  ctx.route.get("/api/sauce",
    ctx.middleware.require_auth,
    ctx.middleware.require_params(["url"]),
    getIndex)
  ctx.route.post("/api/sauce",
    ctx.middleware.require_auth,
    ctx.middleware.require_params(["url"]),
    postIndex)

  console.log("strider-sauce webapp extension loaded")

  cb(null, null)
}
<|endoftext|>


<commit_before>/*
URL=$(wt create \
    -s pg_username=<USER> \
    -s pg_password=<PASS> \
    -s tunnel_rsa_private_key="<KEY>" \
    -s pg_db=<DB> \
    dwh.js)

curl "$URL?pg_db=<PG_DATABASE>&pg_host=<PG_HOST>&pg_port=5439&tunnel_user=<TUNNEL_USER>&tunnel_host=<TUNNEL_HOST>&q=select%20*%20from%20tenants%20limit%201"
*/

var Bluebird = require('bluebird');
var Net = require('net');
var Postgres = require('pg');
var SSH = require('ssh2');

var FORWARDER_PORT = Math.floor(4000 + Math.random() * 1000);
var tunnel$;

return function(context, req, res) {

    var err;
    ['pg_username', 'pg_password', 'tunnel_rsa_private_key'].forEach(function(i) {
        if (typeof context.secrets[i] !== 'string') {
            err = i;
        }
    });
    ['pg_host', 'pg_port', 'pg_db', 'tunnel_user', 'tunnel_host', 'q'].forEach(function(i) {
        if (typeof context.data[i] !== 'string') {
            err = i;
        }
    });

    if (err) {
        try {
            console.log('ERROR: request without ' + err + '.');
            res.writeHead(400);
            return res.end('Missing ' + err);
        }
        catch (e) {
            // ignore
        }
    }

    var connOptions = "postgres://" + context.secrets.pg_username + ":" + context.secrets.pg_password + "@localhost:" + FORWARDER_PORT + "/" + context.secrets.pg_db;

    tunnel$ = tunnel$
        ?   tunnel$
        :   createTunnel({
                host: context.data.tunnel_host,
                username: context.data.tunnel_user,
                privateKey: context.secrets.tunnel_rsa_private_key.replace(/\\[n]/g, '\n'),
                pgServer: context.data.pg_host,
                pgPort: context.data.pg_port,
            });

    return tunnel$
        .then(onTunnelReady, onTunnelError);

    function onTunnelReady(end) {
        console.log('Got a tunnel');

        Postgres.connect(connOptions, function (err, client, done) {
            console.log('connected to pg');
            if (err) {
                end();
                console.log('error connecting', err);
                res.writeHead(502);
                return res.end('Error connecting to database');
            }
            client.query(context.data.q, function(err, result) {
                done();

                if (err) {
                    console.log('error running query', err);
                    res.writeHead(502);
                    return res.end('Error executing query');
                }

                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({
                    rows: result.rows,
                }, null, 2));
            });
        });
    }

    function onTunnelError(err) {
        console.log('Unable to get tunnel', err.message);

        res.writeHead(500);
        res.end('Tunnel creation failed. See webtask logs.');
    }
};

function createTunnel(options) {
    return new Bluebird(function (resolve, reject) {
        var ssh = new SSH.Client();
        var connectOptions = {
            host: options.host,
            username: options.username,
            privateKey: options.privateKey,
            // debug: function (msg) {
            //     console.log('DEBUG', msg);
            // },
        };

        console.log('Initiating connection');

        ssh.on('ready', onClientReady);
        ssh.on('error', onClientError);
        ssh.connect(connectOptions);

        return;
        function end() {
            console.log('Ending ssh tunnel');
            ssh.end();

            tunnel$ = null;
        }

        function onClientError(err) {
            console.log('Client error', err.message);
            tunnel$ = null;

            return reject(err);
        }

        function onClientReady() {
            console.log('ssh client ready');

            var listener = Net.createServer(function (sock) {
                console.log('Created raw network server', sock.remoteAddress, sock.remotePort);

                ssh.forwardOut(sock.remoteAddress, sock.remotePort, options.pgServer, options.pgPort, function (err, stream) {
                    if (err) {
                        console.log('Forwarder failed', err.message);
                        sock.end();
                        return reject(err);
                    }

                    sock.pipe(stream).pipe(sock);

                    console.log('Forwarder all wired up');
                });
            });

            listener.on('close', function () {
                console.log('Forwarder closed');

                end();
            });

            listener.on('error', function (err) {
                console.log('Forwarder error', err.message);

                end();
            });

            listener.listen(FORWARDER_PORT, function () {
                console.log('Forwarding server now listening', arguments);

                return resolve(end);
            });
        }
    });
}
<commit_msg>update to use token<commit_after>/*
URL=$(wt create \
    -s pg_username=<USER> \
    -s pg_password=<PASS> \
    -s tunnel_rsa_private_key="<KEY>" \
    -s pg_db=<DB> \
    dwh.js)

curl "$URL?pg_db=<PG_DATABASE>&pg_host=<PG_HOST>&pg_port=5439&tunnel_user=<TUNNEL_USER>&tunnel_host=<TUNNEL_HOST>&q=select%20*%20from%20tenants%20limit%201"
*/

var Bluebird = require('bluebird');
var Net = require('net');
var Postgres = require('pg');
var SSH = require('ssh2');

var FORWARDER_PORT = Math.floor(4000 + Math.random() * 1000);
var tunnel$;

return function(context, req, res) {

    var err;
    ['token', 'pg_username', 'pg_password', 'tunnel_rsa_private_key'].forEach(function(i) {
        if (typeof context.secrets[i] !== 'string') {
            err = i;
        }
    });
    ['token', 'pg_host', 'pg_port', 'pg_db', 'tunnel_user', 'tunnel_host', 'q'].forEach(function(i) {
        if (typeof context.data[i] !== 'string') {
            err = i;
        }
    });

    if (err) {
        try {
            console.log('ERROR: request without ' + err + '.');
            res.writeHead(400);
            return res.end('Missing ' + err);
        }
        catch (e) {
            // ignore
        }
    }

    if (context.secrets.token !== context.data.token) {
        console.log('Unauthorized');
        res.writeHead(401);
        return res.end('Missing token');
    }

    var connOptions = "postgres://" + context.secrets.pg_username + ":" + context.secrets.pg_password + "@localhost:" + FORWARDER_PORT + "/" + context.secrets.pg_db;

    tunnel$ = tunnel$
        ?   tunnel$
        :   createTunnel({
                host: context.data.tunnel_host,
                username: context.data.tunnel_user,
                privateKey: context.secrets.tunnel_rsa_private_key.replace(/\\[n]/g, '\n'),
                pgServer: context.data.pg_host,
                pgPort: context.data.pg_port,
            });

    return tunnel$
        .then(onTunnelReady, onTunnelError);

    function onTunnelReady(end) {
        console.log('Got a tunnel');

        Postgres.connect(connOptions, function (err, client, done) {
            console.log('connected to pg');
            if (err) {
                end();
                console.log('error connecting', err);
                res.writeHead(502);
                return res.end('Error connecting to database');
            }
            client.query(context.data.q, function(err, result) {
                done();

                if (err) {
                    console.log('error running query', err);
                    res.writeHead(502);
                    return res.end('Error executing query');
                }

                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({
                    rows: result.rows,
                }, null, 2));
            });
        });
    }

    function onTunnelError(err) {
        console.log('Unable to get tunnel', err.message);

        res.writeHead(500);
        res.end('Tunnel creation failed. See webtask logs.');
    }
};

function createTunnel(options) {
    return new Bluebird(function (resolve, reject) {
        var ssh = new SSH.Client();
        var connectOptions = {
            host: options.host,
            username: options.username,
            privateKey: options.privateKey,
            // debug: function (msg) {
            //     console.log('DEBUG', msg);
            // },
        };

        console.log('Initiating connection');

        ssh.on('ready', onClientReady);
        ssh.on('error', onClientError);
        ssh.connect(connectOptions);

        return;
        function end() {
            console.log('Ending ssh tunnel');
            ssh.end();

            tunnel$ = null;
        }

        function onClientError(err) {
            console.log('Client error', err.message);
            tunnel$ = null;

            return reject(err);
        }

        function onClientReady() {
            console.log('ssh client ready');

            var listener = Net.createServer(function (sock) {
                console.log('Created raw network server', sock.remoteAddress, sock.remotePort);

                ssh.forwardOut(sock.remoteAddress, sock.remotePort, options.pgServer, options.pgPort, function (err, stream) {
                    if (err) {
                        console.log('Forwarder failed', err.message);
                        sock.end();
                        return reject(err);
                    }

                    sock.pipe(stream).pipe(sock);

                    console.log('Forwarder all wired up');
                });
            });

            listener.on('close', function () {
                console.log('Forwarder closed');

                end();
            });

            listener.on('error', function (err) {
                console.log('Forwarder error', err.message);

                end();
            });

            listener.listen(FORWARDER_PORT, function () {
                console.log('Forwarding server now listening', arguments);

                return resolve(end);
            });
        }
    });
}
<|endoftext|>


<commit_before>// @copyright: https://github.com/hanzichi/hanzichi.github.io/blob/master/2016/bigrender/js/bigrender.js

(function (win, doc) {
	/* bind 兼容 */
	Function.prototype.bind = Function.prototype.bind || function (context) {
		var that = this;
		return function () {
			return that.apply(context, arguments);
		};
	};

	var LazyRender = {
		getElementsByClassName: function (cls) {
			if (doc.getElementsByName) {
				return doc.getElementsByClassName(cls);
			}

			var allTags = doc.getElementsByTagName('*'),
			    aCls = [],
			    reg = new RegExp('\\b' + cls + '\\b', 'i');
			for (var i = 0, tmp, len = allTags.length; i < len; i++) {
				(tmp = allTags[i]) && reg.test(tmp.className) && aCls.push(tmp);
			}

			return aCls;
		},
		addEvent: function (ele, type, fn) {
			ele.addEventListener ? ele.addEventListener(type, fn, false) : ele.attachEvent('on' + type, fn);
		},
		removeEvent: function (ele, type, fn) {
			ele.removeEventListener ? ele.removeEventListener(type, fn, false) : ele.detachEvent('on' + type, fn);
		},
		getPos: function (ele) {
			var pos = {
				x: 0,
				y: 0
			};
			while (ele.offsetParent) {
				pos.x += ele.offsetLeft;
				pos.y += ele.offsetTop;
				ele = ele.offsetParent;
			}

			return pos;
		},
		getViewport: function () {
			var html = doc.documentElement;

			return {
				width: !win.innerWidth ? html.clientWidth : win.innerWidth,
				height: !win.innerHeight ? html.clientHeight : win.innerHeight
			};
		},
		getScrollHeight: function () {
			var html = doc.documentElement,
				bd = doc.body;
			return Math.max(win.pageYOffset || 0, html.scrollTop, bd.scrollTop);
		},
		getEleSize = function (ele) {
			return {
				width: ele.offsetWidth,
				height: ele.offsetHeight
			};
		},

		render: {
			threshold: 0,	// {Number} 阀值，预加载高度，单位px
			eles: null,		// {Array} 需延迟加载的元素集合
			fn: null,		// {Function} scroll、resize、touchmove 所绑定的方法，等价于 pollTextareas()

			evalScripts: function (code) {
				var head = doc.getElementsByTagName('head')[0],
					script = doc.createElement('script');

				script.type = 'text/javascript';
				script.text = code;
				head.appendChild(script);
			},
			evalStyles: function (code) {
				var head = doc.getElementsByTagName('head')[0],
					style = doc.createElement('style');

				style.type = 'text/css';
				try {
					style.appendChild(doc.createTextNode(code));
				} catch (e) {
					style.styleSheets.cssText = code;
				}
				head.appendChild(style);
			},
			extractCode: function (str, isStyle) {
				var cata = isStyle ? 'style' : 'script',
					scriptFragment = '<' + cata + '[^>]*>([\\S\\s]*?)</' + cata + '\\s',
					matchAll = new RegExp(scriptFragment, 'img'),
					matchOne = new RegExp(scriptFragment, 'im'),
					matchResults = str.match(matchAll) || [],
					ret = [];

				for (var i = 0, len = matchResults.length; i < len; i++) {
					var temp = (matchResults[i].match(matchOne)) || ['', ''][1];
					if (temp) {
						ret.push(temp);
					}
				}

				return ret;
			}
		}
	};
})(window, document)<commit_msg>update lazyRender.js<commit_after>// @copyright: https://github.com/hanzichi/hanzichi.github.io/blob/master/2016/bigrender/js/bigrender.js

(function (win, doc) {
	/* bind 兼容 */
	Function.prototype.bind = Function.prototype.bind || function (context) {
		var that = this;
		return function () {
			return that.apply(context, arguments);
		};
	};

	var LazyRender = {
		getElementsByClassName: function (cls) {
			if (doc.getElementsByName) {
				return doc.getElementsByClassName(cls);
			}

			var allTags = doc.getElementsByTagName('*'),
			    aCls = [],
			    reg = new RegExp('\\b' + cls + '\\b', 'i');
			for (var i = 0, tmp, len = allTags.length; i < len; i++) {
				(tmp = allTags[i]) && reg.test(tmp.className) && aCls.push(tmp);
			}

			return aCls;
		},
		addEvent: function (ele, type, fn) {
			ele.addEventListener ? ele.addEventListener(type, fn, false) : ele.attachEvent('on' + type, fn);
		},
		removeEvent: function (ele, type, fn) {
			ele.removeEventListener ? ele.removeEventListener(type, fn, false) : ele.detachEvent('on' + type, fn);
		},
		getPos: function (ele) {
			var pos = {
				x: 0,
				y: 0
			};
			while (ele.offsetParent) {
				pos.x += ele.offsetLeft;
				pos.y += ele.offsetTop;
				ele = ele.offsetParent;
			}

			return pos;
		},
		getViewport: function () {
			var html = doc.documentElement;

			return {
				width: !win.innerWidth ? html.clientWidth : win.innerWidth,
				height: !win.innerHeight ? html.clientHeight : win.innerHeight
			};
		},
		getScrollHeight: function () {
			var html = doc.documentElement,
				bd = doc.body;
			return Math.max(win.pageYOffset || 0, html.scrollTop, bd.scrollTop);
		},
		getEleSize = function (ele) {
			return {
				width: ele.offsetWidth,
				height: ele.offsetHeight
			};
		},

		render: {
			threshold: 0,	// {Number} 阀值，预加载高度，单位px
			eles: null,		// {Array} 需延迟加载的元素集合
			fn: null,		// {Function} scroll、resize、touchmove 所绑定的方法，等价于 pollTextareas()

			evalScripts: function (code) {
				var head = doc.getElementsByTagName('head')[0],
					script = doc.createElement('script');

				script.type = 'text/javascript';
				script.text = code;
				head.appendChild(script);
			},
			evalStyles: function (code) {
				var head = doc.getElementsByTagName('head')[0],
					style = doc.createElement('style');

				style.type = 'text/css';
				try {
					style.appendChild(doc.createTextNode(code));
				} catch (e) {
					style.styleSheets.cssText = code;
				}
				head.appendChild(style);
			},
			extractCode: function (str, isStyle) {
				var cata = isStyle ? 'style' : 'script',
					scriptFragment = '<' + cata + '[^>]*>([\\S\\s]*?)</' + cata + '\\s*>',		// 匹配style或script中的代码块
					matchAll = new RegExp(scriptFragment, 'img'),
					matchOne = new RegExp(scriptFragment, 'im'),
					matchResults = str.match(matchAll) || [],
					ret = [];

				for (var i = 0, len = matchResults.length; i < len; i++) {
					var temp = (matchResults[i].match(matchOne)) || ['', ''][1];
					if (temp) {
						ret.push(temp);
					}
				}

				return ret;
			},
			decodeHTML: function(str) {
				return str.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');	// 替换html代码中转义的'<>&'符号
			}

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


<commit_before>var CONFIG = require("./config");
var http   = require("https");
var sys    = require('sys');
var exec   = require('child_process').exec;

module.exports.getOrgsRepos = function (repos, organization_name) {
  var orgsRepos = []
  for (var index in repos) {
    if ({}.hasOwnProperty.call(repos, index)) {
      var current_repo_owner = repos[index].owner.login;
      var current_repo_name = repos[index].owner.name;

      if (organization_name === current_repo_owner) {
        var repo_name = repos[index].name

        orgsRepos.push (repo_name)
      }
    }
  }

  return orgsRepos;
}

module.exports.getMyRepos = function (repos, current_user) {
  var myRepos = []

  for (var index in repos) {
    if ({}.hasOwnProperty.call(repos, index)) {
      var current_repo_owner = repos[index].owner.login;
      var current_repo_name = repos[index].owner.name;

      if (current_user === current_repo_owner) {
        var ssh_repo_address = repos[index].ssh_url

        myRepos.push (ssh_repo_address)
      }
    }
  }

  return myRepos;
}

module.exports.forkRepos = function (owner, repos, index, callback) {
  var repo_name = repos[index]

  var options = {
    host: "api.github.com",
    port: 443,
    path: "/repos/" + owner + "/" + repo_name + "/forks",
    method: 'POST',
    headers: {
      "Authorization": "token " + CONFIG.GITHUB_TOKEN,
      "User-Agent": "git-tools-cloner"
    }
  };

  var req = http.request(options, function(res) {
    var username = "";

    res.setEncoding('utf8');
    res.on('data', function (chunk) {
      username += chunk;
    });

    res.on('end', function () {
      console.log (options.path)

      if (repos.length - 1 === index) {
        return callback ()
      } else {
        module.exports.forkRepos (owner, repos, ++index, callback)
      }
    });
  });

  req.on('error', function(e) {
    console.log('problem with request: ' + e.message);
  });

  // write data to request body
  req.write('');
  req.end();
}

module.exports.checkoutRepos = function (repos, index, callback) {
  var address = repos[index]

  exec ("cd " + CONFIG.REPOSITORIES + " && git clone " + address, function (error, stdout, stderr) {
    console.log (address);

    if (error) {
      console.log (error)
    }

    if (repos.length - 1 === index) {
      return callback ()
    } else {
      module.exports.checkoutRepos (repos, ++index, callback)
    }

    console.log ("\n")
  })
}

module.exports.getCurrentUser = function (callback) {
  var options = {
    host: "api.github.com",
    port: 443,
    path: "/user",
    method: 'GET',
    headers: {
      "Authorization": "token " + CONFIG.GITHUB_TOKEN,
      "User-Agent": "git-tools-cloner"
    }
  };

  var req = http.request(options, function(res) {
    var username = "";

    res.setEncoding('utf8');
    res.on('data', function (chunk) {
      username += chunk;
    });

    res.on('end', function () {
      callback(JSON.parse (username).login);
    });
  });

  req.on('error', function(e) {
    console.log('problem with request: ' + e.message);
  });

  // write data to request body
  req.write('data\n');
  req.write('data\n');
  req.end();
}

module.exports.getAllRepos = function (page, repos, callback) {
  var options = {
    host: "api.github.com",
    port: 443,
    path: "/user/repos?page=" + page + "&per_page=" + CONFIG.PER_PAGE,
    method: 'GET',
    headers: {
      "Authorization": "token " + CONFIG.GITHUB_TOKEN,
      "User-Agent": "git-tools-cloner"
    }
  };

  var req = http.request(options, function(res) {
    var buffered_output = "";

    res.setEncoding('utf8');
    res.on('data', function (chunk) {
      buffered_output += chunk;
    });

    res.on('end', function () {
      var current_json_object = JSON.parse (buffered_output);
      var current_page_length = current_json_object.length;

      if (current_page_length > 0) {
        repos = module.exports.add_repos (repos, current_json_object);
      }

      if (current_page_length === CONFIG.PER_PAGE) {
        module.exports.getAllRepos (++page, repos, callback);
      } else {
        if (current_page_length > 0) {
          if (typeof callback === "function") {
            return callback(repos);
          }
        }
      }
    });
  });

  req.on('error', function(e) {
    console.log('problem with request: ' + e.message);
  });

  // write data to request body
  req.write('data\n');
  req.write('data\n');
  req.end();
}

module.exports.add_repos = function (repos, append_repos) {
  for (var index in append_repos) {
    if ({}.hasOwnProperty.call(repos, index)) {
      repos.push (append_repos[index]);
    }
  }

  return repos;
}
<commit_msg>Revert "return the rest of the callbacks"<commit_after>var CONFIG = require("./config");
var http   = require("https");
var sys    = require('sys');
var exec   = require('child_process').exec;

module.exports.getOrgsRepos = function (repos, organization_name) {
  var orgsRepos = []
  for (var index in repos) {
    if ({}.hasOwnProperty.call(repos, index)) {
      var current_repo_owner = repos[index].owner.login;
      var current_repo_name = repos[index].owner.name;

      if (organization_name === current_repo_owner) {
        var repo_name = repos[index].name

        orgsRepos.push (repo_name)
      }
    }
  }

  return orgsRepos;
}

module.exports.getMyRepos = function (repos, current_user) {
  var myRepos = []

  for (var index in repos) {
    if ({}.hasOwnProperty.call(repos, index)) {
      var current_repo_owner = repos[index].owner.login;
      var current_repo_name = repos[index].owner.name;

      if (current_user === current_repo_owner) {
        var ssh_repo_address = repos[index].ssh_url

        myRepos.push (ssh_repo_address)
      }
    }
  }

  return myRepos;
}

module.exports.forkRepos = function (owner, repos, index, callback) {
  var repo_name = repos[index]

  var options = {
    host: "api.github.com",
    port: 443,
    path: "/repos/" + owner + "/" + repo_name + "/forks",
    method: 'POST',
    headers: {
      "Authorization": "token " + CONFIG.GITHUB_TOKEN,
      "User-Agent": "git-tools-cloner"
    }
  };

  var req = http.request(options, function(res) {
    var username = "";

    res.setEncoding('utf8');
    res.on('data', function (chunk) {
      username += chunk;
    });

    res.on('end', function () {
      console.log (options.path)

      if (repos.length - 1 === index) {
        callback ()
      } else {
        module.exports.forkRepos (owner, repos, ++index, callback)
      }
    });
  });

  req.on('error', function(e) {
    console.log('problem with request: ' + e.message);
  });

  // write data to request body
  req.write('');
  req.end();
}

module.exports.checkoutRepos = function (repos, index, callback) {
  var address = repos[index]

  exec ("cd " + CONFIG.REPOSITORIES + " && git clone " + address, function (error, stdout, stderr) {
    console.log (address);

    if (error) {
      console.log (error)
    }

    if (repos.length - 1 === index) {
      return callback ()
    } else {
      module.exports.checkoutRepos (repos, ++index, callback)
    }

    console.log ("\n")
  })
}

module.exports.getCurrentUser = function (callback) {
  var options = {
    host: "api.github.com",
    port: 443,
    path: "/user",
    method: 'GET',
    headers: {
      "Authorization": "token " + CONFIG.GITHUB_TOKEN,
      "User-Agent": "git-tools-cloner"
    }
  };

  var req = http.request(options, function(res) {
    var username = "";

    res.setEncoding('utf8');
    res.on('data', function (chunk) {
      username += chunk;
    });

    res.on('end', function () {
      callback(JSON.parse (username).login);
    });
  });

  req.on('error', function(e) {
    console.log('problem with request: ' + e.message);
  });

  // write data to request body
  req.write('data\n');
  req.write('data\n');
  req.end();
}

module.exports.getAllRepos = function (page, repos, callback) {
  var options = {
    host: "api.github.com",
    port: 443,
    path: "/user/repos?page=" + page + "&per_page=" + CONFIG.PER_PAGE,
    method: 'GET',
    headers: {
      "Authorization": "token " + CONFIG.GITHUB_TOKEN,
      "User-Agent": "git-tools-cloner"
    }
  };

  var req = http.request(options, function(res) {
    var buffered_output = "";

    res.setEncoding('utf8');
    res.on('data', function (chunk) {
      buffered_output += chunk;
    });

    res.on('end', function () {
      var current_json_object = JSON.parse (buffered_output);
      var current_page_length = current_json_object.length;

      if (current_page_length > 0) {
        repos = module.exports.add_repos (repos, current_json_object);
      }

      if (current_page_length === CONFIG.PER_PAGE) {
        module.exports.getAllRepos (++page, repos, callback);
      } else {
        if (current_page_length > 0) {
          if (typeof callback === "function") {
            callback(repos);
          }
        }
      }
    });
  });

  req.on('error', function(e) {
    console.log('problem with request: ' + e.message);
  });

  // write data to request body
  req.write('data\n');
  req.write('data\n');
  req.end();
}

module.exports.add_repos = function (repos, append_repos) {
  for (var index in append_repos) {
    if ({}.hasOwnProperty.call(repos, index)) {
      repos.push (append_repos[index]);
    }
  }

  return repos;
}
<|endoftext|>