<commit_before>module('Component', {
    setup: function(){
        this.component = $('
'+
                                '<input size="16" type="text" value="12-02-2012" readonly>'+
                                ''+
                            '
')
                        .appendTo('#qunit-fixture')
                        .datepicker({format: "dd-mm-yyyy"});
        this.input = this.component.find('input');
        this.addon = this.component.find('.add-on');
        this.dp = this.component.data('datepicker')
        this.picker = this.dp.picker;
    },
    teardown: function(){
        this.picker.remove();
    }
});

test('Component gets date/viewDate from input value', function(){
    datesEqual(this.dp.date, UTCDate(2012, 1, 12));
    datesEqual(this.dp.viewDate, UTCDate(2012, 1, 12));
});

test('Activation by component', function(){
    ok(!this.picker.is(':visible'));
    this.addon.click();
    ok(this.picker.is(':visible'));
});

test('simple keyboard nav test', function(){
    var target;

    // Keyboard nav only works with non-readonly inputs
    this.input.removeAttr('readonly');

    equal(this.dp.viewMode, 0);
    target = this.picker.find('.datepicker-days thead th.switch');
    equal(target.text(), 'February 2012', 'Title is "February 2012"');
    datesEqual(this.dp.date, UTCDate(2012, 1, 12));
    datesEqual(this.dp.viewDate, UTCDate(2012, 1, 12));

    // Focus/open
    this.addon.click();

    // Navigation: -1 day, left arrow key
    this.input.trigger({
        type: 'keydown',
        keyCode: 37
    });
    datesEqual(this.dp.viewDate, UTCDate(2012, 1, 11));
    datesEqual(this.dp.date, UTCDate(2012, 1, 11));
    // Month not changed
    target = this.picker.find('.datepicker-days thead th.switch');
    equal(target.text(), 'February 2012', 'Title is "February 2012"');

    // Navigation: +1 month, shift + right arrow key
    this.input.trigger({
        type: 'keydown',
        keyCode: 39,
        shiftKey: true
    });
    datesEqual(this.dp.viewDate, UTCDate(2012, 2, 11));
    datesEqual(this.dp.date, UTCDate(2012, 2, 11));
    target = this.picker.find('.datepicker-days thead th.switch');
    equal(target.text(), 'March 2012', 'Title is "March 2012"');

    // Navigation: -1 year, ctrl + left arrow key
    this.input.trigger({
        type: 'keydown',
        keyCode: 37,
        ctrlKey: true
    });
    datesEqual(this.dp.viewDate, UTCDate(2011, 2, 11));
    datesEqual(this.dp.date, UTCDate(2011, 2, 11));
    target = this.picker.find('.datepicker-days thead th.switch');
    equal(target.text(), 'March 2011', 'Title is "March 2011"');
});

test('setValue', function(){
    this.dp.date = UTCDate(2012, 2, 13)
    this.dp.setValue()
    datesEqual(this.dp.date, UTCDate(2012, 2, 13));
    equal(this.input.val(), '13-03-2012');
});

test('update', function(){
    this.input.val('13-03-2012');
    this.dp.update()
    datesEqual(this.dp.date, UTCDate(2012, 2, 13));
});

test('Navigating to/from decade view', function(){
    var target;

    this.addon.click();
    this.input.val('31-03-2012');
    this.dp.update();

    equal(this.dp.viewMode, 0);
    target = this.picker.find('.datepicker-days thead th.switch');
    ok(target.is(':visible'), 'View switcher is visible');

    target.click();
    ok(this.picker.find('.datepicker-months').is(':visible'), 'Month picker is visible');
    equal(this.dp.viewMode, 1);
    // Not modified when switching modes
    datesEqual(this.dp.viewDate, UTCDate(2012, 2, 31));
    datesEqual(this.dp.date, UTCDate(2012, 2, 31));

    target = this.picker.find('.datepicker-months thead th.switch');
    ok(target.is(':visible'), 'View switcher is visible');

    target.click();
    ok(this.picker.find('.datepicker-years').is(':visible'), 'Year picker is visible');
    equal(this.dp.viewMode, 2);
    // Not modified when switching modes
    datesEqual(this.dp.viewDate, UTCDate(2012, 2, 31));
    datesEqual(this.dp.date, UTCDate(2012, 2, 31));

    // Change years to test internal state changes
    target = this.picker.find('.datepicker-years tbody span:contains(2011)');
    target.click();
    equal(this.dp.viewMode, 1);
    // Only viewDate modified
    datesEqual(this.dp.viewDate, UTCDate(2011, 2, 1));
    datesEqual(this.dp.date, UTCDate(2012, 2, 31));

    target = this.picker.find('.datepicker-months tbody span:contains(Apr)');
    target.click();
    equal(this.dp.viewMode, 0);
    // Only viewDate modified
    datesEqual(this.dp.viewDate, UTCDate(2011, 3, 1));
    datesEqual(this.dp.date, UTCDate(2012, 2, 31));
});

test('Selecting date resets viewDate and date', function(){
    var target;

    this.addon.click();
    this.input.val('31-03-2012');
    this.dp.update();

    // Rendered correctly
    equal(this.dp.viewMode, 0);
    target = this.picker.find('.datepicker-days tbody td:first');
    equal(target.text(), '26'); // Should be Feb 26

    // Updated internally on click
    target.click();
    datesEqual(this.dp.viewDate, UTCDate(2012, 1, 26))
    datesEqual(this.dp.date, UTCDate(2012, 1, 26))

    // Re-rendered on click
    target = this.picker.find('.datepicker-days tbody td:first');
    equal(target.text(), '29'); // Should be Jan 29
});

test('"remove" removes associated HTML', function(){
    var datepickerDivSelector = '.datepicker';

    //there should be one datepicker initiated so that means one hidden .datepicker div
    equal($(datepickerDivSelector).length, 1);
    this.component.datepicker('remove');
    equal($(datepickerDivSelector).length, 0);//hidden HTML should be gone
});

test('Does not block events', function(){
    var clicks = 0;
    function handler(){
        clicks++;
    }
    $('#qunit-fixture').on('click', '.add-on', handler);
    this.addon.click();
    equal(clicks, 1);
    $('#qunit-fixture').off('click', '.add-on', handler);
});
<commit_msg>Fix test for remove function, now that pickers are detached<commit_after>module('Component', {
    setup: function(){
        this.component = $('
'+
                                '<input size="16" type="text" value="12-02-2012" readonly>'+
                                ''+
                            '
')
                        .appendTo('#qunit-fixture')
                        .datepicker({format: "dd-mm-yyyy"});
        this.input = this.component.find('input');
        this.addon = this.component.find('.add-on');
        this.dp = this.component.data('datepicker')
        this.picker = this.dp.picker;
    },
    teardown: function(){
        this.picker.remove();
    }
});

test('Component gets date/viewDate from input value', function(){
    datesEqual(this.dp.date, UTCDate(2012, 1, 12));
    datesEqual(this.dp.viewDate, UTCDate(2012, 1, 12));
});

test('Activation by component', function(){
    ok(!this.picker.is(':visible'));
    this.addon.click();
    ok(this.picker.is(':visible'));
});

test('simple keyboard nav test', function(){
    var target;

    // Keyboard nav only works with non-readonly inputs
    this.input.removeAttr('readonly');

    equal(this.dp.viewMode, 0);
    target = this.picker.find('.datepicker-days thead th.switch');
    equal(target.text(), 'February 2012', 'Title is "February 2012"');
    datesEqual(this.dp.date, UTCDate(2012, 1, 12));
    datesEqual(this.dp.viewDate, UTCDate(2012, 1, 12));

    // Focus/open
    this.addon.click();

    // Navigation: -1 day, left arrow key
    this.input.trigger({
        type: 'keydown',
        keyCode: 37
    });
    datesEqual(this.dp.viewDate, UTCDate(2012, 1, 11));
    datesEqual(this.dp.date, UTCDate(2012, 1, 11));
    // Month not changed
    target = this.picker.find('.datepicker-days thead th.switch');
    equal(target.text(), 'February 2012', 'Title is "February 2012"');

    // Navigation: +1 month, shift + right arrow key
    this.input.trigger({
        type: 'keydown',
        keyCode: 39,
        shiftKey: true
    });
    datesEqual(this.dp.viewDate, UTCDate(2012, 2, 11));
    datesEqual(this.dp.date, UTCDate(2012, 2, 11));
    target = this.picker.find('.datepicker-days thead th.switch');
    equal(target.text(), 'March 2012', 'Title is "March 2012"');

    // Navigation: -1 year, ctrl + left arrow key
    this.input.trigger({
        type: 'keydown',
        keyCode: 37,
        ctrlKey: true
    });
    datesEqual(this.dp.viewDate, UTCDate(2011, 2, 11));
    datesEqual(this.dp.date, UTCDate(2011, 2, 11));
    target = this.picker.find('.datepicker-days thead th.switch');
    equal(target.text(), 'March 2011', 'Title is "March 2011"');
});

test('setValue', function(){
    this.dp.date = UTCDate(2012, 2, 13)
    this.dp.setValue()
    datesEqual(this.dp.date, UTCDate(2012, 2, 13));
    equal(this.input.val(), '13-03-2012');
});

test('update', function(){
    this.input.val('13-03-2012');
    this.dp.update()
    datesEqual(this.dp.date, UTCDate(2012, 2, 13));
});

test('Navigating to/from decade view', function(){
    var target;

    this.addon.click();
    this.input.val('31-03-2012');
    this.dp.update();

    equal(this.dp.viewMode, 0);
    target = this.picker.find('.datepicker-days thead th.switch');
    ok(target.is(':visible'), 'View switcher is visible');

    target.click();
    ok(this.picker.find('.datepicker-months').is(':visible'), 'Month picker is visible');
    equal(this.dp.viewMode, 1);
    // Not modified when switching modes
    datesEqual(this.dp.viewDate, UTCDate(2012, 2, 31));
    datesEqual(this.dp.date, UTCDate(2012, 2, 31));

    target = this.picker.find('.datepicker-months thead th.switch');
    ok(target.is(':visible'), 'View switcher is visible');

    target.click();
    ok(this.picker.find('.datepicker-years').is(':visible'), 'Year picker is visible');
    equal(this.dp.viewMode, 2);
    // Not modified when switching modes
    datesEqual(this.dp.viewDate, UTCDate(2012, 2, 31));
    datesEqual(this.dp.date, UTCDate(2012, 2, 31));

    // Change years to test internal state changes
    target = this.picker.find('.datepicker-years tbody span:contains(2011)');
    target.click();
    equal(this.dp.viewMode, 1);
    // Only viewDate modified
    datesEqual(this.dp.viewDate, UTCDate(2011, 2, 1));
    datesEqual(this.dp.date, UTCDate(2012, 2, 31));

    target = this.picker.find('.datepicker-months tbody span:contains(Apr)');
    target.click();
    equal(this.dp.viewMode, 0);
    // Only viewDate modified
    datesEqual(this.dp.viewDate, UTCDate(2011, 3, 1));
    datesEqual(this.dp.date, UTCDate(2012, 2, 31));
});

test('Selecting date resets viewDate and date', function(){
    var target;

    this.addon.click();
    this.input.val('31-03-2012');
    this.dp.update();

    // Rendered correctly
    equal(this.dp.viewMode, 0);
    target = this.picker.find('.datepicker-days tbody td:first');
    equal(target.text(), '26'); // Should be Feb 26

    // Updated internally on click
    target.click();
    datesEqual(this.dp.viewDate, UTCDate(2012, 1, 26))
    datesEqual(this.dp.date, UTCDate(2012, 1, 26))

    // Re-rendered on click
    target = this.picker.find('.datepicker-days tbody td:first');
    equal(target.text(), '29'); // Should be Jan 29
});

test('"remove" removes associated HTML', function(){
    var datepickerDivSelector = '.datepicker';

    $('#datepicker').datepicker('show');

    //there should be one datepicker initiated so that means one hidden .datepicker div
    equal($(datepickerDivSelector).length, 1);
    this.component.datepicker('remove');
    equal($(datepickerDivSelector).length, 0);//hidden HTML should be gone
});

test('Does not block events', function(){
    var clicks = 0;
    function handler(){
        clicks++;
    }
    $('#qunit-fixture').on('click', '.add-on', handler);
    this.addon.click();
    equal(clicks, 1);
    $('#qunit-fixture').off('click', '.add-on', handler);
});
<|endoftext|>


<commit_before>import { merge } from "htmlbars/utils";

export function domHelpers(helpers, extensions) {
  var base = {
    // These methods are runtime for now. If they are too expensive,
    // I may inline them at compile-time.
    appendText: function(element, value) {
      if (value === undefined) { return; }
      element.appendChild(document.createTextNode(value));
    },

    appendHTML: function(element, value) {
      if (value === undefined) { return; }
      element.appendChild(this.frag(element, value));
    },

    appendFragment: function(element, fragment) {
      if (fragment === undefined) { return; }
      element.appendChild(fragment);
    },

    ambiguousContents: function(element, context, string, escaped) {
      var helper, value, args;

      if (helper = helpers[string]) {
        return this.helperContents(string, element, context, [], { element: element, escaped: escaped });
      } else {
        return this.resolveContents(context, [string], element, escaped);
      }
    },

    helperContents: function(name, element, context, args, options) {
      var helper = helpers[name];
      options.element = element;
      args.push(options);
      return helper.apply(context, args);
    },

    resolveContents: function(context, parts, element, escaped) {
      var helper = helpers.RESOLVE;
      if (helper) {
        var options = {
          element: element,
          escaped: escaped,
          append: this.appendCallback(element),
          dom: this
        };

        return helper.apply(context, [parts, options]);
      }

      return parts.reduce(function(current, part) {
        return current[part];
      }, context);
    },

    ambiguousAttr: function(context, string, stream, buffer, options) {
      var helper;

      if (helper = helpers[string]) {
        throw new Error("helperAttr is not implemented yet");
      } else {
        return this.resolveInAttr(context, [string], stream, buffer, options);
      }
    },

    helperAttr: function(context, name, args, buffer, options) {
      options.dom = this;
      var helper = helpers[name], position = buffer.length;
      args.push(options);

      var stream = helper.apply(context, args);

      buffer.push('');

      // skip(stream, 1)
      var skippedFirst = false;

      var subscription = stream.subscribe(function(next) {
        buffer[position] = next;

        if (skippedFirst) {
          options.setAttribute(buffer.join(''));
        } else {
          skippedFirst = true;
        }
      });

      subscription.connect();
    },

    resolveInAttr: function(context, parts, buffer, options) {
      var helper = helpers.RESOLVE_IN_ATTR;

      options.dom = this;

      if (helper) {
        var position = buffer.length;
        buffer.push('');

        var stream = helper.call(context, parts, options);

        // skip(stream, 1)
        var skippedFirst = false;

        var subscription = stream.subscribe(function(next) {
          buffer[position] = next;

          if (skippedFirst) {
            options.setAttribute(buffer.join(''));
          } else {
            skippedFirst = true;
          }
        });

        subscription.connect();

        return;
      }

      var out = parts.reduce(function(current, part) {
        return current[part];
      }, context);

      buffer.push(out);
    },

    setAttribute: function(element, name, value, options) {
      var callback;

      this.setAttr(element, name, subscribe);
      callback(value);

      function subscribe(listener) {
        callback = listener;
      }
    },

    setAttr: function(element, name, subscribe) {
      subscribe(function(value) {
        element.setAttribute(name, value);
      });
    },

    frag: function(element, string) {
      /*global DocumentFragment*/
      if (element instanceof DocumentFragment) {
        element = this.createElement('div');
      }

      return this.createContextualFragment(element, string);
    },

    // overridable
    appendCallback: function(element) {
      return function(node) { element.appendChild(node); };
    },

    createElement: function() {
      return document.createElement.apply(document, arguments);
    },

    createDocumentFragment: function() {
      return document.createDocumentFragment.apply(document, arguments);
    },

    createContextualFragment: function(element, string) {
      var range = this.createRange();
      range.setStart(element, 0);
      range.collapse(false);
      return range.createContextualFragment(string);
    },

    createRange: function() {
      return document.createRange();
    }
  };

  return extensions ? merge(extensions, base) : base;
}

export function hydrate(spec, options) {
  return spec(domHelpers(options.helpers || {}, options.extensions || {}));
}
<commit_msg>Expose stream throttling<commit_after>import { merge } from "htmlbars/utils";

export function domHelpers(helpers, extensions) {
  var base = {
    // These methods are runtime for now. If they are too expensive,
    // I may inline them at compile-time.
    appendText: function(element, value) {
      if (value === undefined) { return; }
      element.appendChild(document.createTextNode(value));
    },

    appendHTML: function(element, value) {
      if (value === undefined) { return; }
      element.appendChild(this.frag(element, value));
    },

    appendFragment: function(element, fragment) {
      if (fragment === undefined) { return; }
      element.appendChild(fragment);
    },

    ambiguousContents: function(element, context, string, escaped) {
      var helper, value, args;

      if (helper = helpers[string]) {
        return this.helperContents(string, element, context, [], { element: element, escaped: escaped });
      } else {
        return this.resolveContents(context, [string], element, escaped);
      }
    },

    helperContents: function(name, element, context, args, options) {
      var helper = helpers[name];
      options.element = element;
      args.push(options);
      return helper.apply(context, args);
    },

    resolveContents: function(context, parts, element, escaped) {
      var helper = helpers.RESOLVE;
      if (helper) {
        var options = {
          element: element,
          escaped: escaped,
          append: this.appendCallback(element),
          dom: this
        };

        return helper.apply(context, [parts, options]);
      }

      return parts.reduce(function(current, part) {
        return current[part];
      }, context);
    },

    ambiguousAttr: function(context, string, stream, buffer, options) {
      var helper;

      if (helper = helpers[string]) {
        throw new Error("helperAttr is not implemented yet");
      } else {
        return this.resolveInAttr(context, [string], stream, buffer, options);
      }
    },

    helperAttr: function(context, name, args, buffer, options) {
      options.dom = this;
      var helper = helpers[name], position = buffer.length;
      args.push(options);

      var stream = this.throttle(helper.apply(context, args));

      buffer.push('');

      // skip(stream, 1)
      var skippedFirst = false;

      var subscription = stream.subscribe(function(next) {
        buffer[position] = next;

        if (skippedFirst) {
          options.setAttribute(buffer.join(''));
        } else {
          skippedFirst = true;
        }
      });

      subscription.connect();
    },

    resolveInAttr: function(context, parts, buffer, options) {
      var helper = helpers.RESOLVE_IN_ATTR;

      options.dom = this;

      if (helper) {
        var position = buffer.length;
        buffer.push('');

        var stream = helper.call(context, parts, options);

        // skip(stream, 1)
        var skippedFirst = false;

        var subscription = stream.subscribe(function(next) {
          buffer[position] = next;

          if (skippedFirst) {
            options.setAttribute(buffer.join(''));
          } else {
            skippedFirst = true;
          }
        });

        subscription.connect();

        return;
      }

      var out = parts.reduce(function(current, part) {
        return current[part];
      }, context);

      buffer.push(out);
    },

    setAttribute: function(element, name, value, options) {
      var callback;

      this.setAttr(element, name, subscribe);
      callback(value);

      function subscribe(listener) {
        callback = listener;
      }
    },

    setAttr: function(element, name, subscribe) {
      subscribe(function(value) {
        element.setAttribute(name, value);
      });
    },

    frag: function(element, string) {
      /*global DocumentFragment*/
      if (element instanceof DocumentFragment) {
        element = this.createElement('div');
      }

      return this.createContextualFragment(element, string);
    },

    // overridable
    appendCallback: function(element) {
      return function(node) { element.appendChild(node); };
    },

    createElement: function() {
      return document.createElement.apply(document, arguments);
    },

    createDocumentFragment: function() {
      return document.createDocumentFragment.apply(document, arguments);
    },

    createContextualFragment: function(element, string) {
      var range = this.createRange();
      range.setStart(element, 0);
      range.collapse(false);
      return range.createContextualFragment(string);
    },

    createRange: function() {
      return document.createRange();
    },

    throttle: function(stream) {
      return stream;
    }
  };

  return extensions ? merge(extensions, base) : base;
}

export function hydrate(spec, options) {
  return spec(domHelpers(options.helpers || {}, options.extensions || {}));
}
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();

router.get('/:workflow/:task/:platform:/:deployment', function(req, res, next) {
    var client = req.app.get('elastic'),
      workflow = req.params.workflow.toLowerCase(),
      task = req.params.task.toLowerCase(),
      platform = req.params.platform.toLowerCase(),
      deployment = req.params.deployment, /* we keep the original case */
      mf_server = req.app.get('mf_server'),
      expand = req.query.expand,
      json = {};

    /* retrieve all experiment summaries that have this deployment */

    /* (1) get deployment plan for the given hashvalue */
    /* (2) parse key experiments */
    /* (3) for each experiment, get
     *   (a)
     * */
    res.json(json);
});

module.exports = router;
<commit_msg>first draft for /mf/summary with energy and runtime reports<commit_after>var express = require('express');
var router = express.Router();
var async = require('async');
var dateFormat = require('dateformat');

router.get('/:workflow/:task/:platform/:deployment', function(req, res, next) {
    var client = req.app.get('elastic'),
      workflow = req.params.workflow.toLowerCase(),
      task = req.params.task.toLowerCase(),
      platform = req.params.platform.toLowerCase(),
      deployment = req.params.deployment, // we keep the original case
      mf_server = req.app.get('mf_server'),
      dreamcloud_pwm_idx = req.app.get('pwm_idx'),
      expand = req.query.expand,
      experiments = [],
      json = [];

    /* (1) get deployment plan for the given hashvalue */
    client.get({
        index: 'deployment_on_' + platform,
        type: workflow + '_' + task,
        id: deployment
    }, function(error, response) {
        if (error) {
            res.status(500);
            return next(error);
        }
        /* parse all experiments that use this deployment plan */
        if (response.found) {
            var source = response._source;
            experiments = source.experiments;
        } else {
            var message = {};
            message.error = "Could not find deployment plan in the database";
            res.json(message);
            return;
        }

        var index = workflow + '_' + task;
        async.forEachOf(experiments, function(value, experiment, callback) {
            /* get start of experiment */
            client.search({
                index: index,
                type: experiment,
                size: 1,
                sort: ['@timestamp:asc']
            }, function(error, response) {
                if (error) {
                    callback(null);
                    return;
                }
                var start, end;
                if (response.hits !== undefined) {
                    var only_results = response.hits.hits;
                    var keys = Object.keys(only_results);
                    keys.forEach(function(key) {
                        var metric_data = only_results[key]._source;
                        start = metric_data['@timestamp'];
                        start = start.replace(/\s/g, '0');
                    });
                }

                /* get end of experiment */
                client.search({
                    index: index,
                    type: experiment,
                    size: 1,
                    sort: ['@timestamp:desc']
                }, function(error, response) {
                    if (error) {
                        callback(null);
                        return;
                    }
                    if (response.hits !== undefined) {
                        var only_results = response.hits.hits;
                        var keys = Object.keys(only_results);
                        keys.forEach(function(key) {
                            var metric_data = only_results[key]._source;
                            end = metric_data['@timestamp'];
                            end = start.replace(/\s/g, '0');
                        });
                    }

                    if (!is_defined(start) || !is_defined(end)) {
                        callback(null);
                        return;
                    }

                    /* add runtime statistics to response object */
                    var data = {};
                    data.experiment = experiment;
                    data.workflow = workflow;
                    data.task = task;
                    data.deployment = deployment;
                    data.runtime = {};
                    data.runtime.start = start;
                    data.runtime.end = end;
                    data.runtime.seconds = (new Date(end) - new Date(start)) / 1000;
                    if (!data.runtime.seconds) {
                        data.runtime.seconds = 0;
                    }

                    /* get energy measurments */
                    var body = compute_average_on("NODE01", "NODE02", "NODE03", start, end);
                    client.search({
                        index: dreamcloud_pwm_idx,
                        searchType: 'count',
                        body: body
                    }, function(error, response) {
                        if (error) {
                            json.push(data);
                            callback(null);
                            return;
                        }
                        var answer = {},
                            aggs = response.aggregations;

                        data.energy = {};
                        var power_data = {};
                        var average = aggs.power_metrics.NODE01.value;
                        data.energy.NODE01 = {};
                        data.energy.NODE01.avg_watt_consumption = average;
                        var duration = (new Date(end) - new Date(start)) / 1000;
                        var joule = average * duration;
                        data.energy.NODE01.total_energy_consumption = joule;

                        average = aggs.power_metrics.NODE02.value;
                        data.energy.NODE02 = {};
                        data.energy.NODE02.avg_watt_consumption = average;
                        joule = average * duration;
                        data.energy.NODE02.total_energy_consumption = joule;

                        average = aggs.power_metrics.NODE03.value;
                        data.energy.NODE03 = {};
                        data.energy.NODE03.avg_watt_consumption = average;
                        joule = average * duration;
                        data.energy.NODE03.total_energy_consumption = joule;

                        json.push(data);
                        callback(null);
                    });
                });
            });
        }, function(error) {
            if (error) {
                res.status(500);
                return next(error);
            }

            res.json(json);
        });
    });
});

function is_defined(variable) {
    return (typeof variable !== 'undefined');
}

function compute_average_on(metric_name_a, metric_name_b, metric_name_c, from, to) {
    var query = {
        "aggs": {
            "power_metrics": {
                "filter": {
                    "and": [{
                        "or": [{
                            "exists": {
                                "field": metric_name_a
                            }
                        }, {
                            "exists": {
                                "field": metric_name_b
                            }
                        }, {
                            "exists": {
                                "field": metric_name_c
                            }
                        }]
                    }, {
                        "range": {
                            "@timestamp": {
                                "gte": from.toString(),
                                "lte": to.toString()
                            }
                        }
                    }]
                },
                "aggs": {
                    "NODE01": {
                        "avg": {
                            "field": metric_name_a
                        }
                    },
                    "NODE02": {
                        "avg": {
                            "field": metric_name_b
                        }
                    },
                    "NODE03": {
                        "avg": {
                            "field": metric_name_c
                        }
                    }
                }
            }
        }
    }
    return query;
}

module.exports = router;
<|endoftext|>


<commit_before>import {fetchPage} from "./pagination-fetch-page"
import {paginationSetFetching} from "./pagination-set-fetching"
import {paginationSetAssignmentURL} from "./pagination-set-assignment-url"
import {nextPage} from "../selectors"
import {all} from "../../assignment/selectors"
/**
 * PUBLIC: Fetch all pages of repositories associated with an assignment
 *
 * @return An asynchronous thunk action which resolves once all pages have been fetched
 */
export const fetchAllPages = (assignmentURL) => {
  return (dispatch, getState) => {
    const urlObj = new URL(assignmentURL)
    let repoURL = `${urlObj.origin}/api/internal/${urlObj.pathname}/`
    if (all(getState()).type === "individual") {
      repoURL += "assignment_repositories"
    } else {
      repoURL += "group_assignment_repositories"
    }
    dispatch(paginationSetAssignmentURL(assignmentURL))
    dispatch(paginationSetFetching(true))
    return chainFetchPage(dispatch, getState, repoURL).then(() => {
      dispatch(paginationSetFetching(false))
    })
  }
}

/**
 * PRIVATE: Dispatches fetch page while nextPage attribute of pagination is true
 *
 * @return An asynchronous thunk action which resolves once all pages have been fetched
 */
const chainFetchPage = (dispatch, getState, repoURL) => {
  return dispatch(fetchPage(repoURL, nextPage(getState()))).then(() => {
    if (nextPage(getState())) {
      return chainFetchPage(dispatch, getState, repoURL)
    }
  })
}
<commit_msg>update assingment repo api path<commit_after>import {fetchPage} from "./pagination-fetch-page"
import {paginationSetFetching} from "./pagination-set-fetching"
import {paginationSetAssignmentURL} from "./pagination-set-assignment-url"
import {nextPage} from "../selectors"
import {all} from "../../assignment/selectors"
/**
 * PUBLIC: Fetch all pages of repositories associated with an assignment
 *
 * @return An asynchronous thunk action which resolves once all pages have been fetched
 */
export const fetchAllPages = (assignmentURL) => {
  return (dispatch, getState) => {
    const urlObj = new URL(assignmentURL)
    let repoURL = `${urlObj.origin}/api/internal/${urlObj.pathname}/`
    if (all(getState()).type === "individual") {
      repoURL += "assignment_repos"
    } else {
      repoURL += "group_assignment_repos"
    }
    dispatch(paginationSetAssignmentURL(assignmentURL))
    dispatch(paginationSetFetching(true))
    return chainFetchPage(dispatch, getState, repoURL).then(() => {
      dispatch(paginationSetFetching(false))
    })
  }
}

/**
 * PRIVATE: Dispatches fetch page while nextPage attribute of pagination is true
 *
 * @return An asynchronous thunk action which resolves once all pages have been fetched
 */
const chainFetchPage = (dispatch, getState, repoURL) => {
  return dispatch(fetchPage(repoURL, nextPage(getState()))).then(() => {
    if (nextPage(getState())) {
      return chainFetchPage(dispatch, getState, repoURL)
    }
  })
}
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import CodeListSelector from './code-list-selector'
import VisHintPicker from './vis-hint-picker'

import {
  updateMultiple, switchBooleanMultiple, newCodeListMultiple
} from '../actions/response-format'

import { AXIS } from '../constants/pogues-constants'
const { INFO, MEASURE } = AXIS
import { connect } from 'react-redux'

function MultipleResponseFormatEditor(
  { id, qrId, format,
    updateMultiple, newCodeListMultiple, switchBooleanMultiple,
    locale }) {

  const {
    infoCodeList, measureCodeList, measureBoolean, measureVisHint
  } = format

  return (

      <CodeListSelector
        id={infoCodeList}
        title={"Axe d'information"}
        select={infoCodeList => updateMultiple(id, { infoCodeList })}
        create={() => newCodeListMultiple(id, qrId, INFO)}
        locale={locale} />

      <CodeListSelector
        id={measureCodeList}
        disabled={measureBoolean}
        title={"Information mesurée"}
        select={measureCodeList => updateMultiple(id, { measureCodeList })}
        create={() => newCodeListMultiple(id, qrId, MEASURE)}
        locale={locale} />
      <VisHintPicker visHint={measureVisHint}
        disabled={measureBoolean}
        locale={locale}
        select={measureVisHint => updateMultiple(id, { measureVisHint })}/>

          Boolean

          <input type="checkbox" className="form-control"
            checked={measureBoolean}
            onChange={e => switchBooleanMultiple(id) }/>

  )
}

const mapStateToProps = state => ({
  qrId: state.appState.questionnaire
})

const mapDispatchToProps = {
  updateMultiple,
  newCodeListMultiple,
  switchBooleanMultiple
}

MultipleResponseFormatEditor.propTypes = {
  id: PropTypes.string.isRequired,
  /**
   * Id of the current questionnaire
   */
  qrId: PropTypes.string.isRequired,
  format: PropTypes.object.isRequired,
  locale: PropTypes.object.isRequired,
  updateMultiple: PropTypes.func.isRequired,
  newCodeListMultiple: PropTypes.func.isRequired,
  switchBooleanMultiple: PropTypes.func.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(MultipleResponseFormatEditor)

<commit_msg>Fix style of checkbox<commit_after>import React, { PropTypes } from 'react'
import CodeListSelector from './code-list-selector'
import VisHintPicker from './vis-hint-picker'

import {
  updateMultiple, switchBooleanMultiple, newCodeListMultiple
} from '../actions/response-format'

import { AXIS } from '../constants/pogues-constants'
const { INFO, MEASURE } = AXIS
import { connect } from 'react-redux'

function MultipleResponseFormatEditor(
  { id, qrId, format,
    updateMultiple, newCodeListMultiple, switchBooleanMultiple,
    locale }) {

  const {
    infoCodeList, measureCodeList, measureBoolean, measureVisHint
  } = format

  return (

      <CodeListSelector
        id={infoCodeList}
        title={"Axe d'information"}
        select={infoCodeList => updateMultiple(id, { infoCodeList })}
        create={() => newCodeListMultiple(id, qrId, INFO)}
        locale={locale} />

      <CodeListSelector
        id={measureCodeList}
        disabled={measureBoolean}
        title={"Information mesurée"}
        select={measureCodeList => updateMultiple(id, { measureCodeList })}
        create={() => newCodeListMultiple(id, qrId, MEASURE)}
        locale={locale} />
      <VisHintPicker visHint={measureVisHint}
        disabled={measureBoolean}
        locale={locale}
        select={measureVisHint => updateMultiple(id, { measureVisHint })}/>

          Boolean

            {/* we use class "checkbox" to have the proper vertical
                alignment (`padding: 7px;`) but we need to remove
                `margin-left` since the class `chekbox` is intended
                to make the label appear on the right side of the box
            */}
            <input type="checkbox" style={{ marginLeft: 0 }}
            checked={measureBoolean}
            onChange={e => switchBooleanMultiple(id) }/>

  )
}

const mapStateToProps = state => ({
  qrId: state.appState.questionnaire
})

const mapDispatchToProps = {
  updateMultiple,
  newCodeListMultiple,
  switchBooleanMultiple
}

MultipleResponseFormatEditor.propTypes = {
  id: PropTypes.string.isRequired,
  /**
   * Id of the current questionnaire
   */
  qrId: PropTypes.string.isRequired,
  format: PropTypes.object.isRequired,
  locale: PropTypes.object.isRequired,
  updateMultiple: PropTypes.func.isRequired,
  newCodeListMultiple: PropTypes.func.isRequired,
  switchBooleanMultiple: PropTypes.func.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(MultipleResponseFormatEditor)

<|endoftext|>


<commit_before>(function (controllers, undefined) {

    /**
     * @ngdoc controller
     * @name Merchello.Plugins.Reports.ExportOrders
     * @function
     *
     * @description
     * The controller for the reports Export Orders page
     */
    controllers.ExportOrdersController = function ($scope, merchelloPluginReportOrderExportService, queryDisplayBuilder) {

        $scope.loaded = true;
        $scope.preValuesLoaded = true;

        $scope.itemsPerPage = 0;
        $scope.totalItems = 0;
        $scope.filterStartDate = '';
        $scope.filterEndDate = '';
        $scope.currentFilters = [];

        // exposed methods
        $scope.exportOrders = exportOrders;

        /**
         * @ngdoc method
         * @name init
         * @function
         *
         * @description
         * Initializes the controller
         */
        function init() {
            setDefaultDates(new Date());
        }

        /**
         * @ngdoc method
         * @name exportOrders
         * @function
         *
         * @description
         * Requests order data download
         */
        function exportOrders(filterStartDate, filterEndDate) {
            // prevent exporting more orders until current order is complete
            if ($scope.loaded == false) {
                return;
            }

            $scope.filterStartDate = filterStartDate;
            $scope.filterEndDate = filterEndDate;
            $scope.loaded = false;

            var query = buildQueryDates($scope.filterStartDate, $scope.filterEndDate);
            console.info(query);
            var promise = merchelloPluginReportOrderExportService.getOrdersByDateRange(query);
            promise.then(function (data) {
                var element = angular.element('<a/>');
                element.attr({
                    href: 'data:attachment/csv;charset=utf-8,' + encodeURI(data),
                    target: '_blank',
                    download: 'orders.csv'
                })[0].click();

                $scope.loaded = true;
            });
        }

        /**
         * @ngdoc method
         * @name buildQueryDates
         * @function
         *
         * @description
         * Perpares a new query object for passing to the ApiController
         */
        function buildQueryDates(startDate, endDate) {

            var query = queryDisplayBuilder.createDefault();

            if (startDate === undefined && endDate === undefined) {
                $scope.currentFilters = [];
            } else {
                if (Date.parse(startDate) > Date.parse(endDate)) {
                    var temp = startDate;
                    startDate = endDate;
                    endDate = temp;
                }
                $scope.filterStartDate = startDate;
                $scope.filterEndDate = endDate;
                query.addInvoiceDateParam($scope.filterStartDate, 'start');
                query.addInvoiceDateParam($scope.filterEndDate, 'end');
            }

            query.currentPage = 0;
            query.itemsPerPage = 25;
            query.sortBy = 'invoiceDate';
            query.sortDirection = 'desc';

            return query;
        }

        /**
         * @ngdoc method
         * @name setDefaultDates
         * @function
         *
         * @description
         * Sets the default dates
         */
        function setDefaultDates(actual) {
            var month = actual.getMonth() == 0 ? 11 : actual.getMonth() - 1;
            var start = new Date(actual.getFullYear(), month, actual.getDate());
            var end = new Date(actual.getFullYear(), actual.getMonth(), actual.getDate());
            $scope.filterStartDate = start.toLocaleDateString();
            $scope.filterEndDate = end.toLocaleDateString();
        }

        init();
    };

    angular.module("umbraco").controller("Merchello.Plugins.Reports.ExportOrders", ['$scope', 'merchelloPluginReportOrderExportService', 'queryDisplayBuilder', merchello.Controllers.ExportOrdersController]);

}(window.merchello.Controllers = window.merchello.Controllers || {}));
<commit_msg>fixed export orders download in IE and Firefox<commit_after>(function (controllers, undefined) {

    /**
     * @ngdoc controller
     * @name Merchello.Plugins.Reports.ExportOrders
     * @function
     *
     * @description
     * The controller for the reports Export Orders page
     */
    controllers.ExportOrdersController = function ($scope, merchelloPluginReportOrderExportService, queryDisplayBuilder) {

        $scope.loaded = true;
        $scope.preValuesLoaded = true;

        $scope.itemsPerPage = 0;
        $scope.totalItems = 0;
        $scope.filterStartDate = '';
        $scope.filterEndDate = '';
        $scope.currentFilters = [];

        // exposed methods
        $scope.exportOrders = exportOrders;

        /**
         * @ngdoc method
         * @name init
         * @function
         *
         * @description
         * Initializes the controller
         */
        function init() {
            setDefaultDates(new Date());
        }

        /**
         * @ngdoc method
         * @name exportOrders
         * @function
         *
         * @description
         * Requests order data download
         */
        function exportOrders(filterStartDate, filterEndDate) {
            // prevent exporting more orders until current order is complete
            if ($scope.loaded == false) {
                return;
            }

            $scope.filterStartDate = filterStartDate;
            $scope.filterEndDate = filterEndDate;
            $scope.loaded = false;

            var query = buildQueryDates($scope.filterStartDate, $scope.filterEndDate);
            console.info(query);
            var promise = merchelloPluginReportOrderExportService.getOrdersByDateRange(query);
            promise.then(function (data) {
                // IE fix. Must download csv via msSaveBlob
                if (window.navigator.msSaveOrOpenBlob) {
                    var blob = new Blob([decodeURIComponent(encodeURI(data))], {
                        type: 'text/csv;charset=utf-8'
                    });
                    navigator.msSaveBlob(blob, 'orders.csv');
                }
                else {
                    var hiddenElement = document.createElement('a');
                    hiddenElement.href = 'data:attachment/csv,' + encodeURI(data);
                    hiddenElement.target = '_blank';
                    hiddenElement.download = 'orders.csv';
                    // Firefox fix. Element must be on DOM for download click to work
                    document.body.appendChild(hiddenElement);
                    hiddenElement.click();
                }

                $scope.loaded = true;
            });
        }

        /**
         * @ngdoc method
         * @name buildQueryDates
         * @function
         *
         * @description
         * Perpares a new query object for passing to the ApiController
         */
        function buildQueryDates(startDate, endDate) {

            var query = queryDisplayBuilder.createDefault();

            if (startDate === undefined && endDate === undefined) {
                $scope.currentFilters = [];
            } else {
                if (Date.parse(startDate) > Date.parse(endDate)) {
                    var temp = startDate;
                    startDate = endDate;
                    endDate = temp;
                }
                $scope.filterStartDate = startDate;
                $scope.filterEndDate = endDate;
                query.addInvoiceDateParam($scope.filterStartDate, 'start');
                query.addInvoiceDateParam($scope.filterEndDate, 'end');
            }

            query.currentPage = 0;
            query.itemsPerPage = 25;
            query.sortBy = 'invoiceDate';
            query.sortDirection = 'desc';

            return query;
        }

        /**
         * @ngdoc method
         * @name setDefaultDates
         * @function
         *
         * @description
         * Sets the default dates
         */
        function setDefaultDates(actual) {
            var month = actual.getMonth() == 0 ? 11 : actual.getMonth() - 1;
            var start = new Date(actual.getFullYear(), month, actual.getDate());
            var end = new Date(actual.getFullYear(), actual.getMonth(), actual.getDate());
            $scope.filterStartDate = start.toLocaleDateString();
            $scope.filterEndDate = end.toLocaleDateString();
        }

        init();
    };

    angular.module("umbraco").controller("Merchello.Plugins.Reports.ExportOrders", ['$scope', 'merchelloPluginReportOrderExportService', 'queryDisplayBuilder', merchello.Controllers.ExportOrdersController]);

}(window.merchello.Controllers = window.merchello.Controllers || {}));
<|endoftext|>


<commit_before>[['idb-1', 'http-1'],
 ['http-1', 'http-2'],
 ['http-1', 'idb-1'],
 ['idb-1', 'idb-2']].map(function(adapters) {

  module('replication: ' + adapters[0] + ':' + adapters[1], {
    setup : function () {
      this.name = generateAdapterUrl(adapters[0]);
      this.remote = generateAdapterUrl(adapters[1]);
    }
  });

  var docs = [
    {_id: "0", integer: 0, string: '0'},
    {_id: "1", integer: 1, string: '1'},
    {_id: "2", integer: 2, string: '2'}
  ];

  asyncTest("Test basic pull replication", function() {
    console.info('Starting Test: Test basic pull replication');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        db.replicate.from(self.remote, function(err, result) {
          ok(result.ok, 'replication was ok');
          ok(result.docs_written = docs.length, 'correct # docs written');
          start();
        });
      });
    });
  });

  asyncTest("Local DB contains documents", function() {
    console.info('Starting Test: Local DB contains documents');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, _) {
        db.bulkDocs({docs: docs}, {}, function(err, _) {
          db.replicate.from(self.remote, function(err, _) {
            db.allDocs(function(err, result) {
              ok(result.rows.length === docs.length, 'correct # docs exist');
              start();
            });
          });
        });
      });
    });
  });

  asyncTest("Test basic push replication", function() {
    console.info('Starting Test: Test basic push replication');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      db.bulkDocs({docs: docs}, {}, function(err, results) {
        db.replicate.to(self.remote, function(err, result) {
          ok(result.ok, 'replication was ok');
          ok(result.docs_written === docs.length, 'correct # docs written');
          start();
        });
      });
    });
  });

  asyncTest("Test basic push replication take 2", function() {
    console.info('Starting Test: Test basic push replication take 2');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      db.bulkDocs({docs: docs}, {}, function(err, _) {
        db.replicate.to(self.remote, function(err, _) {
          remote.allDocs(function(err, result) {
            ok(result.rows.length === docs.length, 'correct # docs written');
            start();
          });
        });
      });
    });
  });

  asyncTest("Test checkpoint", function() {
    console.info('Starting Test: Test checkpoint');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        db.replicate.from(self.remote, function(err, result) {
          ok(result.ok, 'replication was ok');
          ok(result.docs_written === docs.length, 'correct # docs written');
          db.replicate.from(self.remote, function(err, result) {
            ok(result.ok, 'replication was ok');
            ok(result.docs_written === 0, 'correct # docs written');
            ok(result.docs_read === 0, 'no docs read');
            start();
          });
        });
      });
    });
  });

  asyncTest("Test checkpoint 2", function() {
    console.info('Starting Test: Test checkpoint 2');
    var self = this;
    var doc = {_id: "3", count: 0};
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.put(doc, {}, function(err, results) {
        db.replicate.from(self.remote, function(err, result) {
          ok(result.ok, 'replication was ok');
          doc._rev = results.rev;
          doc.count++;
          remote.put(doc, {}, function(err, results) {
            doc._rev = results.rev;
            doc.count++;
            remote.put(doc, {}, function(err, results) {
              db.replicate.from(self.remote, function(err, result) {
                ok(result.ok, 'replication was ok');
                ok(result.docs_written === 1, 'correct # docs written');
                start();
              });
            });
          });
        });
      });
    });
  });

  asyncTest("Test checkpoint 3 :)", function() {
    console.info('Starting Test: Test checkpoint 3 :)');
    var self = this;
    var doc = {_id: "3", count: 0};
    initDBPair(this.name, this.remote, function(db, remote) {
      db.put(doc, {}, function(err, results) {
        Pouch.replicate(db, remote, {}, function(err, result) {
          ok(result.ok, 'replication was ok');
          doc._rev = results.rev;
          doc.count++;
          db.put(doc, {}, function(err, results) {
            doc._rev = results.rev;
            doc.count++;
            db.put(doc, {}, function(err, results) {
              Pouch.replicate(db, remote, {}, function(err, result) {
                ok(result.ok, 'replication was ok');
                ok(result.docs_written === 1, 'correct # docs written');
                start();
              });
            });
          });
        });
      });
    });
  });

  // CouchDB will not generate a conflict here, it uses a deteministic
  // method to generate the revision number, however we cannot copy its
  // method as it depends on erlangs internal data representation
  asyncTest("Test basic conflict", function() {
    console.info('Starting Test: Test basic conflict');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};
    var doc2 = {_id: 'adoc', bar:'baz'};
    initDBPair(this.name, this.remote, function(db, remote) {
      db.put(doc1, function(err, localres) {
        remote.put(doc2, function(err, remoteres) {
          db.replicate.to(self.remote, function(err, _) {
            remote.get('adoc', {conflicts: true}, function(err, result) {
              ok(result._conflicts, 'result has a conflict');
              start();
            });
          });
        });
      });
    });
  });

  // independent changes to a local document and a remote document
  // with subsequent replication
  asyncTest("Test advanced conflict", function() {
    ok(true, 'skipping failing test');
    return start();
    console.info('Starting Test: Test advanced conflict');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};  // initial doc, replicated
    var doc2 = {_id: 'adoc', bar:'baz'};  // remote change
    var doc3 = {_id: 'adoc', fb3:'ba3'};  // local change
    initDBPair(this.name, this.remote, function(db, remote) {
      db.put(doc1, function(err, localres) {
        doc2._rev = localres.rev, doc3._rev = localres.rev;
        db.replicate.to(self.remote, function(err, _) {
          // update remote and local then replicate both ways...
          remote.put(doc2, {}, function(err, remoteres) {
            db.put(doc3, function(err, localres) {
              db.replicate.to(self.remote, function(err, _) {
                db.replicate.from(self.remote, function(err,remoteres) {
                  // expect consistent state of conflict between instances
                  remote.get('adoc', {conflicts: true}, function(err, remoteWin) {
                    db.get('adoc', {conflicts: true}, function(err, localWin) {
                      // are winning and conflicting revisions identical?
                      equal(remoteWin._rev, localWin._rev, "remote and local winning revisions do not match");
                      deepEqual(remoteWin._conflicts, localWin._conflicts, "remote and local winning revision conflicts do not match");
                      start();
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  });

  asyncTest("Test basic continous pull replication", function() {
    console.info('Starting Test: Test basic continous pull replication');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        var count = 0;
        var rep = db.replicate.from(self.remote, {continuous: true});
        var changes = db.changes({
          onChange: function(change) {
            ++count;
            if (count === 3) {
              return remote.put(doc1);
            }
            if (count === 4) {
              ok(true, 'Got all the changes');
              rep.cancel();
              changes.cancel();
              start();
            }
          },
          continuous: true,
        });
      });
    });
  });

  asyncTest("Test basic continous push replication", function() {
    console.info('Starting Test: Test basic continous push replication');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};
    initDBPair(this.name, this.remote, function(db, remote) {
      db.bulkDocs({docs: docs}, {}, function(err, results) {
        var count = 0;
        var rep = remote.replicate.from(db, {continuous: true});
        var changes = remote.changes({
          onChange: function(change) {
            ++count;
            if (count === 4) {
              ok(true, 'Got all the changes');
              rep.cancel();
              changes.cancel();
              start();
            }
          },
          continuous: true,
        });
        setTimeout(function() {
          db.put(doc1, {});
        }, 50);
      });
    });
  });

  asyncTest("Test cancel pull replication", function() {
    console.info('Starting Test: Test cancel pull replication');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};
    var doc2 = {_id: 'anotherdoc', foo:'baz'};
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        var count = 0;
        var replicate = db.replicate.from(self.remote, {continuous: true});
        var changes = db.changes({
          continuous: true,
          onChange: function(change) {
            ++count;
            if (count === 3) {
              remote.put(doc1);
            }
            if (count === 4) {
              replicate.cancel();
              remote.put(doc2);
              setTimeout(function() {
                ok(count === 4, 'got no more docs');
                changes.cancel();
                start();
              }, 500);
            }
          },
        });
      });
    });
  });

  asyncTest("Replication filter", function() {
    console.info('Starting Test: Replication filter');
    var docs1 = [
      {_id: "0", integer: 0},
      {_id: "1", integer: 1},
      {_id: "2", integer: 2},
      {_id: "3", integer: 3}
    ];

    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs1}, function(err, info) {
        var replicate = db.replicate.from(remote, {
          continuous: true,
          filter: function(doc) { return doc.integer % 2 === 0; }
        });
        setTimeout(function() {
          db.allDocs(function(err, docs) {
            equal(docs.rows.length, 2);
            replicate.cancel();
            start();
          });
        }, 500);
      });
    });
  });

  asyncTest("Replication with deleted doc", function() {
    console.info('Starting Test: Replication with deleted doc');

    var docs1 = [
      {_id: "0", integer: 0},
      {_id: "1", integer: 1},
      {_id: "2", integer: 2},
      {_id: "3", integer: 3},
      {_id: "4", integer: 4, _deleted: true}
    ];

    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs1}, function(err, info) {
        var replicate = db.replicate.from(remote, function() {
          db.allDocs(function(err, res) {
            equal(res.total_rows, 4, 'Replication with deleted docs');
            start();
          });
        });
      });
    });
  });

  asyncTest("Replication notifications", function() {
    console.info('Starting Test: replication notifications');
    var self = this;
    var changes = 0;
    var onChange = function(c) {
      changes++;
      ok(true, 'Got change notification');
      if (changes === 3) {
        ok(true, 'Got all change notification');
        start();
      }
    }
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        db.replicate.from(self.remote, {onChange: onChange});
      });
    });
  });

});
<commit_msg>added test for replication sequence tracking<commit_after>[['idb-1', 'http-1'],
 ['http-1', 'http-2'],
 ['http-1', 'idb-1'],
 ['idb-1', 'idb-2']].map(function(adapters) {

  module('replication: ' + adapters[0] + ':' + adapters[1], {
    setup : function () {
      this.name = generateAdapterUrl(adapters[0]);
      this.remote = generateAdapterUrl(adapters[1]);
    }
  });

  var docs = [
    {_id: "0", integer: 0, string: '0'},
    {_id: "1", integer: 1, string: '1'},
    {_id: "2", integer: 2, string: '2'}
  ];

  asyncTest("Test basic pull replication", function() {
    console.info('Starting Test: Test basic pull replication');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        db.replicate.from(self.remote, function(err, result) {
          ok(result.ok, 'replication was ok');
          ok(result.docs_written = docs.length, 'correct # docs written');
          start();
        });
      });
    });
  });

  asyncTest("Local DB contains documents", function() {
    console.info('Starting Test: Local DB contains documents');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, _) {
        db.bulkDocs({docs: docs}, {}, function(err, _) {
          db.replicate.from(self.remote, function(err, _) {
            db.allDocs(function(err, result) {
              ok(result.rows.length === docs.length, 'correct # docs exist');
              start();
            });
          });
        });
      });
    });
  });

  asyncTest("Test basic push replication", function() {
    console.info('Starting Test: Test basic push replication');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      db.bulkDocs({docs: docs}, {}, function(err, results) {
        db.replicate.to(self.remote, function(err, result) {
          ok(result.ok, 'replication was ok');
          ok(result.docs_written === docs.length, 'correct # docs written');
          start();
        });
      });
    });
  });

  asyncTest("Test basic push replication take 2", function() {
    console.info('Starting Test: Test basic push replication take 2');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      db.bulkDocs({docs: docs}, {}, function(err, _) {
        db.replicate.to(self.remote, function(err, _) {
          remote.allDocs(function(err, result) {
            ok(result.rows.length === docs.length, 'correct # docs written');
            start();
          });
        });
      });
    });
  });

  asyncTest("Test basic push replication sequence tracking", function() {
    console.info('Starting Test: Test basic push replication sequence tracking');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      var doc1 = {_id: 'adoc', foo:'bar'};
      db.put(doc1, function(err, result) {
        db.replicate.to(self.remote, function(err, result) {
          ok(result.docs_read === 1, 'correct # changed docs read (1) on first replication');
          db.replicate.to(self.remote, function(err, result) {
            ok(result.docs_read === 0, 'correct # changed docs read (0) on second replication');
            db.replicate.to(self.remote, function(err, result) {
              ok(result.docs_read === 0, 'correct # changed docs read (0) on third replication');
              start();
            });
          });
        });
      });
    });
  });

  asyncTest("Test checkpoint", function() {
    console.info('Starting Test: Test checkpoint');
    var self = this;
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        db.replicate.from(self.remote, function(err, result) {
          ok(result.ok, 'replication was ok');
          ok(result.docs_written === docs.length, 'correct # docs written');
          db.replicate.from(self.remote, function(err, result) {
            ok(result.ok, 'replication was ok');
            ok(result.docs_written === 0, 'correct # docs written');
            ok(result.docs_read === 0, 'no docs read');
            start();
          });
        });
      });
    });
  });

  asyncTest("Test checkpoint 2", function() {
    console.info('Starting Test: Test checkpoint 2');
    var self = this;
    var doc = {_id: "3", count: 0};
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.put(doc, {}, function(err, results) {
        db.replicate.from(self.remote, function(err, result) {
          ok(result.ok, 'replication was ok');
          doc._rev = results.rev;
          doc.count++;
          remote.put(doc, {}, function(err, results) {
            doc._rev = results.rev;
            doc.count++;
            remote.put(doc, {}, function(err, results) {
              db.replicate.from(self.remote, function(err, result) {
                ok(result.ok, 'replication was ok');
                ok(result.docs_written === 1, 'correct # docs written');
                start();
              });
            });
          });
        });
      });
    });
  });

  asyncTest("Test checkpoint 3 :)", function() {
    console.info('Starting Test: Test checkpoint 3 :)');
    var self = this;
    var doc = {_id: "3", count: 0};
    initDBPair(this.name, this.remote, function(db, remote) {
      db.put(doc, {}, function(err, results) {
        Pouch.replicate(db, remote, {}, function(err, result) {
          ok(result.ok, 'replication was ok');
          doc._rev = results.rev;
          doc.count++;
          db.put(doc, {}, function(err, results) {
            doc._rev = results.rev;
            doc.count++;
            db.put(doc, {}, function(err, results) {
              Pouch.replicate(db, remote, {}, function(err, result) {
                ok(result.ok, 'replication was ok');
                ok(result.docs_written === 1, 'correct # docs written');
                start();
              });
            });
          });
        });
      });
    });
  });

  // CouchDB will not generate a conflict here, it uses a deteministic
  // method to generate the revision number, however we cannot copy its
  // method as it depends on erlangs internal data representation
  asyncTest("Test basic conflict", function() {
    console.info('Starting Test: Test basic conflict');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};
    var doc2 = {_id: 'adoc', bar:'baz'};
    initDBPair(this.name, this.remote, function(db, remote) {
      db.put(doc1, function(err, localres) {
        remote.put(doc2, function(err, remoteres) {
          db.replicate.to(self.remote, function(err, _) {
            remote.get('adoc', {conflicts: true}, function(err, result) {
              ok(result._conflicts, 'result has a conflict');
              start();
            });
          });
        });
      });
    });
  });

  // independent changes to a local document and a remote document
  // with subsequent replication
  asyncTest("Test advanced conflict", function() {
    ok(true, 'skipping failing test');
    return start();
    console.info('Starting Test: Test advanced conflict');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};  // initial doc, replicated
    var doc2 = {_id: 'adoc', bar:'baz'};  // remote change
    var doc3 = {_id: 'adoc', fb3:'ba3'};  // local change
    initDBPair(this.name, this.remote, function(db, remote) {
      db.put(doc1, function(err, localres) {
        doc2._rev = localres.rev, doc3._rev = localres.rev;
        db.replicate.to(self.remote, function(err, _) {
          // update remote and local then replicate both ways...
          remote.put(doc2, {}, function(err, remoteres) {
            db.put(doc3, function(err, localres) {
              db.replicate.to(self.remote, function(err, _) {
                db.replicate.from(self.remote, function(err,remoteres) {
                  // expect consistent state of conflict between instances
                  remote.get('adoc', {conflicts: true}, function(err, remoteWin) {
                    db.get('adoc', {conflicts: true}, function(err, localWin) {
                      // are winning and conflicting revisions identical?
                      equal(remoteWin._rev, localWin._rev, "remote and local winning revisions do not match");
                      deepEqual(remoteWin._conflicts, localWin._conflicts, "remote and local winning revision conflicts do not match");
                      start();
                    });
                  });
                });
              });
            });
          });
        });
      });
    });
  });

  asyncTest("Test basic continous pull replication", function() {
    console.info('Starting Test: Test basic continous pull replication');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        var count = 0;
        var rep = db.replicate.from(self.remote, {continuous: true});
        var changes = db.changes({
          onChange: function(change) {
            ++count;
            if (count === 3) {
              return remote.put(doc1);
            }
            if (count === 4) {
              ok(true, 'Got all the changes');
              rep.cancel();
              changes.cancel();
              start();
            }
          },
          continuous: true,
        });
      });
    });
  });

  asyncTest("Test basic continous push replication", function() {
    console.info('Starting Test: Test basic continous push replication');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};
    initDBPair(this.name, this.remote, function(db, remote) {
      db.bulkDocs({docs: docs}, {}, function(err, results) {
        var count = 0;
        var rep = remote.replicate.from(db, {continuous: true});
        var changes = remote.changes({
          onChange: function(change) {
            ++count;
            if (count === 4) {
              ok(true, 'Got all the changes');
              rep.cancel();
              changes.cancel();
              start();
            }
          },
          continuous: true,
        });
        setTimeout(function() {
          db.put(doc1, {});
        }, 50);
      });
    });
  });

  asyncTest("Test cancel pull replication", function() {
    console.info('Starting Test: Test cancel pull replication');
    var self = this;
    var doc1 = {_id: 'adoc', foo:'bar'};
    var doc2 = {_id: 'anotherdoc', foo:'baz'};
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        var count = 0;
        var replicate = db.replicate.from(self.remote, {continuous: true});
        var changes = db.changes({
          continuous: true,
          onChange: function(change) {
            ++count;
            if (count === 3) {
              remote.put(doc1);
            }
            if (count === 4) {
              replicate.cancel();
              remote.put(doc2);
              setTimeout(function() {
                ok(count === 4, 'got no more docs');
                changes.cancel();
                start();
              }, 500);
            }
          },
        });
      });
    });
  });

  asyncTest("Replication filter", function() {
    console.info('Starting Test: Replication filter');
    var docs1 = [
      {_id: "0", integer: 0},
      {_id: "1", integer: 1},
      {_id: "2", integer: 2},
      {_id: "3", integer: 3}
    ];

    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs1}, function(err, info) {
        var replicate = db.replicate.from(remote, {
          continuous: true,
          filter: function(doc) { return doc.integer % 2 === 0; }
        });
        setTimeout(function() {
          db.allDocs(function(err, docs) {
            equal(docs.rows.length, 2);
            replicate.cancel();
            start();
          });
        }, 500);
      });
    });
  });

  asyncTest("Replication with deleted doc", function() {
    console.info('Starting Test: Replication with deleted doc');

    var docs1 = [
      {_id: "0", integer: 0},
      {_id: "1", integer: 1},
      {_id: "2", integer: 2},
      {_id: "3", integer: 3},
      {_id: "4", integer: 4, _deleted: true}
    ];

    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs1}, function(err, info) {
        var replicate = db.replicate.from(remote, function() {
          db.allDocs(function(err, res) {
            equal(res.total_rows, 4, 'Replication with deleted docs');
            start();
          });
        });
      });
    });
  });

  asyncTest("Replication notifications", function() {
    console.info('Starting Test: replication notifications');
    var self = this;
    var changes = 0;
    var onChange = function(c) {
      changes++;
      ok(true, 'Got change notification');
      if (changes === 3) {
        ok(true, 'Got all change notification');
        start();
      }
    }
    initDBPair(this.name, this.remote, function(db, remote) {
      remote.bulkDocs({docs: docs}, {}, function(err, results) {
        db.replicate.from(self.remote, {onChange: onChange});
      });
    });
  });

});
<|endoftext|>


<commit_before>const { getAllCompanyLists, getListsCompanyIsIn, addCompanyToList, removeCompanyFromList } = require('../repos')
const { transformCompaniesInLists } = require('../transformers')

async function handleAddRemoveCompanyToList (req, res, next) {
  const { list } = req.body
  const { id } = res.locals.company
  const listsToUpdate = []
  try {
    for (let [listId, value] of Object.entries(list)) {
      const addOrRemoveCompany = (value === 'yes' ? addCompanyToList : removeCompanyFromList)
      listsToUpdate.push(addOrRemoveCompany(req.session.token, listId, id))
    }
    await Promise.all(listsToUpdate)
    req.flash('success', 'Lists changes for this company have been saved.')
    res.send()
  } catch (error) {
    req.flash('error', 'Could not add or remove to list')
    next(error)
  }
}

async function fetchListsCompanyIsOn (req, res, next) {
  try {
    const [allLists, allListsCompaniesIn] = await Promise.all([
      getAllCompanyLists(req.session.token),
      getListsCompanyIsIn(req.session.token, res.locals.company.id),
    ])
    res.locals.listsCompanyIsIn = await transformCompaniesInLists(allLists, allListsCompaniesIn)
    next()
  } catch (error) {
    next(error)
  }
}

async function renderAddRemoveForm (req, res, next) {
  const { company, listsCompanyIsIn, csrfToken } = res.locals
  try {
    res
      .breadcrumb(company.name, `/companies/${company.id}`)
      .breadcrumb('Add and remove from lists')
      .render('company-lists/views/add-remove-list-container', {
        heading: `Add and remove ${company.name} from lists`,
        props: {
          list: listsCompanyIsIn,
          companyId: company.id,
          token: csrfToken,
          createNewListUrl: `/companies/${company.id}/lists/create`,
          cancelLinkUrl: `/companies/${company.id}`,
        },
      })
  } catch (error) {
    next(error)
  }
}

module.exports = {
  handleAddRemoveCompanyToList,
  renderAddRemoveForm,
  fetchListsCompanyIsOn,
}
<commit_msg>Guard against no return url being set in browser<commit_after>const { getAllCompanyLists, getListsCompanyIsIn, addCompanyToList, removeCompanyFromList } = require('../repos')
const { transformCompaniesInLists } = require('../transformers')
const urls = require('../../../lib/urls')

async function handleAddRemoveCompanyToList (req, res, next) {
  const { list } = req.body
  const { id } = res.locals.company
  const listsToUpdate = []
  try {
    for (let [listId, value] of Object.entries(list)) {
      const addOrRemoveCompany = (value === 'yes' ? addCompanyToList : removeCompanyFromList)
      listsToUpdate.push(addOrRemoveCompany(req.session.token, listId, id))
    }
    await Promise.all(listsToUpdate)
    req.flash('success', 'Lists changes for this company have been saved.')
    res.send()
  } catch (error) {
    req.flash('error', 'Could not add or remove to list')
    next(error)
  }
}

async function fetchListsCompanyIsOn (req, res, next) {
  try {
    const [allLists, allListsCompaniesIn] = await Promise.all([
      getAllCompanyLists(req.session.token),
      getListsCompanyIsIn(req.session.token, res.locals.company.id),
    ])
    res.locals.listsCompanyIsIn = await transformCompaniesInLists(allLists, allListsCompaniesIn)
    next()
  } catch (error) {
    next(error)
  }
}

async function renderAddRemoveForm (req, res, next) {
  const { company, listsCompanyIsIn, csrfToken } = res.locals
  const cancelLinkUrl = req.query.returnUrl || urls.dashboard()

  try {
    res
      .breadcrumb(company.name, `/companies/${company.id}`)
      .breadcrumb('Add and remove from lists')
      .render('company-lists/views/add-remove-list-container', {
        heading: `Add and remove ${company.name} from lists`,
        props: {
          list: listsCompanyIsIn,
          companyId: company.id,
          token: csrfToken,
          createNewListUrl: `/companies/${company.id}/lists/create`,
          cancelLinkUrl,
        },
      })
  } catch (error) {
    next(error)
  }
}

module.exports = {
  handleAddRemoveCompanyToList,
  renderAddRemoveForm,
  fetchListsCompanyIsOn,
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import {Layer} from '../../../lib';
import {assembleShaders} from '../../../shader-utils';
import {GL, Model, Geometry} from 'luma.gl';

const glslify = require('glslify');

import earcut from 'earcut';
import flattenDeep from 'lodash.flattendeep';
import normalize from 'geojson-normalize';

const DEFAULT_COLOR = [0, 0, 255, 255];

const defaultGetColor = feature => feature.properties.color;

export default class ReflectionLayer extends Layer {

  static layerName = 'ReflectionLayer';

  /**
   * @class
   * @param {object} props
   */
  constructor(props) {
    super({
      getColor: defaultGetColor,
      drawCountour: false,
      strokeWidth: 1,
      ...props
    });
  }

  initializeState() {
    const {gl} = this.context;

    const {attributeManager} = this.state;
    attributeManager.addDynamic({
      // Primtive attributes
      indices: {size: 1, update: this.calculateIndices, isIndexed: true},
      positions: {size: 3, update: this.calculatePositions},
      colors: {
        type: GL.UNSIGNED_BYTE,
        size: 4,
        update: this.calculateColors
      },
      // Instanced attributes
      pickingColors: {
        type: GL.UNSIGNED_BYTE,
        size: 3,
        update: this.calculatePickingColors,
        noAlloc: true
      }
    });

    const IndexType = gl.getExtension('OES_element_index_uint') ?
      Uint32Array : Uint16Array;

    this.setState({
      model: this.getModel(gl),
      numInstances: 0,
      IndexType
    });
  }

  updateState({oldProps, props, changeFlags}) {
    const {attributeManager} = this.state;
    if (changeFlags.dataChanged) {
      this.state.choropleths = extractChoropleths(props.data);
      attributeManager.invalidateAll();
    }

    if (oldProps.opacity !== props.opacity) {
      this.setUniforms({opacity: props.opacity});
    }
  }

  draw({uniforms}) {
    const {gl} = this.context;
    const lineWidth = this.screenToDevicePixels(this.props.strokeWidth);
    const oldLineWidth = gl.getParameter(GL.LINE_WIDTH);
    gl.lineWidth(lineWidth);
    this.state.model.render(uniforms);
    gl.lineWidth(oldLineWidth);
  }

  pick(opts) {
    super.pick(opts);
    const {info} = opts;
    const index = this.decodePickingColor(info.color);
    const feature = index >= 0 ? this.props.data.features[index] : null;
    info.feature = feature;
    info.object = feature;
  }

  getModel(gl) {
    return new Model({
      gl,
      id: this.props.id,
      ...assembleShaders(gl, {
        vs: glslify('./reflection-layer-vertex.glsl'),
        fs: glslify('./reflection-layer-fragment.glsl')
      }),
      geometry: new Geometry({
        drawMode: this.props.drawContour ? GL.LINES : GL.TRIANGLES
      }),
      vertexCount: 0,
      isIndexed: true
    });
  }

  calculateIndices(attribute) {
    // adjust index offset for multiple choropleths
    const offsets = this.state.choropleths.reduce(
      (acc, choropleth) => [...acc, acc[acc.length - 1] +
        choropleth.reduce((count, polygon) => count + polygon.length, 0)],
      [0]
    );
    const {IndexType} = this.state;
    if (IndexType === Uint16Array && offsets[offsets.length - 1] > 65535) {
      throw new Error('Vertex count exceeds browser\'s limit');
    }

    const indices = this.state.choropleths.map(
      (choropleth, choroplethIndex) => this.props.drawContour ?
        // 1. get sequentially ordered indices of each choropleth contour
        // 2. offset them by the number of indices in previous choropleths
        calculateContourIndices(choropleth).map(
          index => index + offsets[choroplethIndex]
        ) :
        // 1. get triangulated indices for the internal areas
        // 2. offset them by the number of indices in previous choropleths
        calculateSurfaceIndices(choropleth).map(
          index => index + offsets[choroplethIndex]
        )
    );

    attribute.value = new IndexType(flattenDeep(indices));
    attribute.target = GL.ELEMENT_ARRAY_BUFFER;
    this.state.model.setVertexCount(attribute.value.length / attribute.size);
  }

  calculatePositions(attribute) {
    const vertices = flattenDeep(this.state.choropleths);
    attribute.value = new Float32Array(vertices);
  }

  calculateColors(attribute) {
    const {data: {features}, getColor} = this.props;

    const colors = this.state.choropleths.map(
      (choropleth, choroplethIndex) => {
        const feature = features[choropleth.featureIndex];
        const color = getColor(feature) || DEFAULT_COLOR;

        if (isNaN(color[3])) {
          color[3] = DEFAULT_COLOR[3];
        }

        return choropleth.map(polygon =>
          polygon.map(vertex => color)
        );
      }
    );

    attribute.value = new Uint8Array(flattenDeep(colors));
  }

  // Override the default picking colors calculation
  calculatePickingColors(attribute) {

    const colors = this.state.choropleths.map(
      (choropleth, choroplethIndex) => {
        const {featureIndex} = choropleth;
        const color = this.props.drawContour ? [0, 0, 0] : [
          (featureIndex + 1) % 256,
          Math.floor((featureIndex + 1) / 256) % 256,
          Math.floor((featureIndex + 1) / 256 / 256) % 256];
        return choropleth.map(polygon =>
          polygon.map(vertex => color)
        );
      }
    );

    attribute.value = new Uint8Array(flattenDeep(colors));
  }
}

/*
 * converts list of features from a GeoJSON object to a list of GeoJSON
 * polygon-style coordinates
 * @param {Object} data - geojson object
 * @returns {[Number,Number,Number][][][]} array of choropleths
 */
function extractChoropleths(data) {
  const normalizedGeojson = normalize(data);
  const result = [];

  normalizedGeojson.features.map((feature, featureIndex) => {
    const choropleths = featureToChoropleths(feature);
    choropleths.forEach(choropleth => {
      choropleth.featureIndex = featureIndex;
    });
    result.push(...choropleths);
  });
  return result;
}

/*
 * converts one GeoJSON features from object to a list of GeoJSON polygon-style
 * coordinates
 * @param {Object} data - geojson object
 * @returns {[Number,Number,Number][][][]} array of choropleths
 */
function featureToChoropleths(feature) {
  const {coordinates, type} = feature.geometry;
  let choropleths;

  switch (type) {
  case 'MultiPolygon':
    choropleths = coordinates;
    break;
  case 'Polygon':
    choropleths = [coordinates];
    break;
  case 'LineString':
    // create a LineStringLayer for LineString and MultiLineString?
    choropleths = [[coordinates]];
    break;
  case 'MultiLineString':
    choropleths = coordinates.map(coords => [coords]);
    break;
  default:
    choropleths = [];
  }
  return choropleths.map(
    choropleth => choropleth.map(
      polygon => polygon.map(
        coordinate => [coordinate[0], coordinate[1], coordinate[2] || 0]
      )
    )
  );
}

/*
 * get vertex indices for drawing choropleth contour
 * @param {[Number,Number,Number][][]} choropleth
 * @returns {[Number]} indices
 */
function calculateContourIndices(choropleth) {
  let offset = 0;

  return choropleth.reduce((acc, polygon) => {
    const numVertices = polygon.length;

    // use vertex pairs for gl.LINES => [0, 1, 1, 2, 2, ..., n-2, n-2, n-1]
    const indices = [...acc, offset];
    for (let i = 1; i < numVertices - 1; i++) {
      indices.push(i + offset, i + offset);
    }
    indices.push(offset + numVertices - 1);

    offset += numVertices;
    return indices;
  }, []);
}

/*
 * get vertex indices for drawing choropleth mesh
 * @param {[Number,Number,Number][][]} choropleth
 * @returns {[Number]} indices
 */
function calculateSurfaceIndices(choropleth) {
  let holes = null;

  if (choropleth.length > 1) {
    holes = choropleth.reduce(
      (acc, polygon) => [...acc, acc[acc.length - 1] + polygon.length],
      [0]
    ).slice(1, choropleth.length);
  }

  return earcut(flattenDeep(choropleth), holes, 3);
}
<commit_msg>added a framebuffer to the reflection layer<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

import {Layer} from '../../../lib';
import {assembleShaders} from '../../../shader-utils';
import {GL, Model, Geometry, Framebuffer, Texture2D} from 'luma.gl';

const glslify = require('glslify');

import earcut from 'earcut';
import flattenDeep from 'lodash.flattendeep';
import normalize from 'geojson-normalize';

const DEFAULT_COLOR = [0, 0, 255, 255];

const defaultGetColor = feature => feature.properties.color;

export default class ReflectionLayer extends Layer {

  static layerName = 'ReflectionLayer';

  /**
   * @class
   * @param {object} props
   */
  constructor(props) {
    super({
      getColor: defaultGetColor,
      drawCountour: false,
      strokeWidth: 1,
      ...props
    });
  }

  initializeState() {
    const {gl} = this.context;

    const {attributeManager} = this.state;
    attributeManager.addDynamic({
      // Primtive attributes
      indices: {size: 1, update: this.calculateIndices, isIndexed: true},
      positions: {size: 3, update: this.calculatePositions},
      colors: {
        type: GL.UNSIGNED_BYTE,
        size: 4,
        update: this.calculateColors
      },
      // Instanced attributes
      pickingColors: {
        type: GL.UNSIGNED_BYTE,
        size: 3,
        update: this.calculatePickingColors,
        noAlloc: true
      }
    });

    const IndexType = gl.getExtension('OES_element_index_uint') ?
      Uint32Array : Uint16Array;

    const framebuffer = new Framebuffer(gl, {
      width: this.context.viewport.width,
      height: this.context.viewport.height,
      minFilter: gl.LINEAR,
      magFilter: gl.LINEAR
    });

    this.setState({
      model: this.getModel(gl),
      numInstances: 0,
      framebuffer: framebuffer,
      IndexType
    });
  }

  updateState({oldProps, props, changeFlags}) {
    const {attributeManager} = this.state;
    if (changeFlags.dataChanged) {
      this.state.choropleths = extractChoropleths(props.data);
      attributeManager.invalidateAll();
    }

    if (oldProps.opacity !== props.opacity) {
      this.setUniforms({opacity: props.opacity});
    }

    if (this.context.viewport.width != this.state.framebuffer.width || this.context.viewport.height != this.state.framebuffer.height) {
      const {gl} = this.context;
      this.state.framebuffer.resize({
        width: this.context.viewport.width,
        height: this.context.viewport.height,
      });
    }
  }

  draw({uniforms}) {
    const {gl} = this.context;
    const lineWidth = this.screenToDevicePixels(this.props.strokeWidth);
    const oldLineWidth = gl.getParameter(GL.LINE_WIDTH);
    gl.lineWidth(lineWidth);
    this.state.model.render(uniforms);
    gl.lineWidth(oldLineWidth);
  }

  pick(opts) {
    super.pick(opts);
    const {info} = opts;
    const index = this.decodePickingColor(info.color);
    const feature = index >= 0 ? this.props.data.features[index] : null;
    info.feature = feature;
    info.object = feature;
  }

  getModel(gl) {
    return new Model({
      gl,
      id: this.props.id,
      ...assembleShaders(gl, {
        vs: glslify('./reflection-layer-vertex.glsl'),
        fs: glslify('./reflection-layer-fragment.glsl')
      }),
      geometry: new Geometry({
        drawMode: this.props.drawContour ? GL.LINES : GL.TRIANGLES
      }),
      vertexCount: 0,
      isIndexed: true
    });
  }

  calculateIndices(attribute) {
    // adjust index offset for multiple choropleths
    const offsets = this.state.choropleths.reduce(
      (acc, choropleth) => [...acc, acc[acc.length - 1] +
        choropleth.reduce((count, polygon) => count + polygon.length, 0)],
      [0]
    );
    const {IndexType} = this.state;
    if (IndexType === Uint16Array && offsets[offsets.length - 1] > 65535) {
      throw new Error('Vertex count exceeds browser\'s limit');
    }

    const indices = this.state.choropleths.map(
      (choropleth, choroplethIndex) => this.props.drawContour ?
        // 1. get sequentially ordered indices of each choropleth contour
        // 2. offset them by the number of indices in previous choropleths
        calculateContourIndices(choropleth).map(
          index => index + offsets[choroplethIndex]
        ) :
        // 1. get triangulated indices for the internal areas
        // 2. offset them by the number of indices in previous choropleths
        calculateSurfaceIndices(choropleth).map(
          index => index + offsets[choroplethIndex]
        )
    );

    attribute.value = new IndexType(flattenDeep(indices));
    attribute.target = GL.ELEMENT_ARRAY_BUFFER;
    this.state.model.setVertexCount(attribute.value.length / attribute.size);
  }

  calculatePositions(attribute) {
    const vertices = flattenDeep(this.state.choropleths);
    attribute.value = new Float32Array(vertices);
  }

  calculateColors(attribute) {
    const {data: {features}, getColor} = this.props;

    const colors = this.state.choropleths.map(
      (choropleth, choroplethIndex) => {
        const feature = features[choropleth.featureIndex];
        const color = getColor(feature) || DEFAULT_COLOR;

        if (isNaN(color[3])) {
          color[3] = DEFAULT_COLOR[3];
        }

        return choropleth.map(polygon =>
          polygon.map(vertex => color)
        );
      }
    );

    attribute.value = new Uint8Array(flattenDeep(colors));
  }

  // Override the default picking colors calculation
  calculatePickingColors(attribute) {

    const colors = this.state.choropleths.map(
      (choropleth, choroplethIndex) => {
        const {featureIndex} = choropleth;
        const color = this.props.drawContour ? [0, 0, 0] : [
          (featureIndex + 1) % 256,
          Math.floor((featureIndex + 1) / 256) % 256,
          Math.floor((featureIndex + 1) / 256 / 256) % 256];
        return choropleth.map(polygon =>
          polygon.map(vertex => color)
        );
      }
    );

    attribute.value = new Uint8Array(flattenDeep(colors));
  }
}

/*
 * converts list of features from a GeoJSON object to a list of GeoJSON
 * polygon-style coordinates
 * @param {Object} data - geojson object
 * @returns {[Number,Number,Number][][][]} array of choropleths
 */
function extractChoropleths(data) {
  const normalizedGeojson = normalize(data);
  const result = [];

  normalizedGeojson.features.map((feature, featureIndex) => {
    const choropleths = featureToChoropleths(feature);
    choropleths.forEach(choropleth => {
      choropleth.featureIndex = featureIndex;
    });
    result.push(...choropleths);
  });
  return result;
}

/*
 * converts one GeoJSON features from object to a list of GeoJSON polygon-style
 * coordinates
 * @param {Object} data - geojson object
 * @returns {[Number,Number,Number][][][]} array of choropleths
 */
function featureToChoropleths(feature) {
  const {coordinates, type} = feature.geometry;
  let choropleths;

  switch (type) {
  case 'MultiPolygon':
    choropleths = coordinates;
    break;
  case 'Polygon':
    choropleths = [coordinates];
    break;
  case 'LineString':
    // create a LineStringLayer for LineString and MultiLineString?
    choropleths = [[coordinates]];
    break;
  case 'MultiLineString':
    choropleths = coordinates.map(coords => [coords]);
    break;
  default:
    choropleths = [];
  }
  return choropleths.map(
    choropleth => choropleth.map(
      polygon => polygon.map(
        coordinate => [coordinate[0], coordinate[1], coordinate[2] || 0]
      )
    )
  );
}

/*
 * get vertex indices for drawing choropleth contour
 * @param {[Number,Number,Number][][]} choropleth
 * @returns {[Number]} indices
 */
function calculateContourIndices(choropleth) {
  let offset = 0;

  return choropleth.reduce((acc, polygon) => {
    const numVertices = polygon.length;

    // use vertex pairs for gl.LINES => [0, 1, 1, 2, 2, ..., n-2, n-2, n-1]
    const indices = [...acc, offset];
    for (let i = 1; i < numVertices - 1; i++) {
      indices.push(i + offset, i + offset);
    }
    indices.push(offset + numVertices - 1);

    offset += numVertices;
    return indices;
  }, []);
}

/*
 * get vertex indices for drawing choropleth mesh
 * @param {[Number,Number,Number][][]} choropleth
 * @returns {[Number]} indices
 */
function calculateSurfaceIndices(choropleth) {
  let holes = null;

  if (choropleth.length > 1) {
    holes = choropleth.reduce(
      (acc, polygon) => [...acc, acc[acc.length - 1] + polygon.length],
      [0]
    ).slice(1, choropleth.length);
  }

  return earcut(flattenDeep(choropleth), holes, 3);
}
<|endoftext|>