<commit_before>/*
 * Licensed under the Apache License, Version 2.0
 * See accompanying LICENSE file.
 */
'use strict';

angular.module('dashboard.streamingdag', ['dashboard.metrics'])

  .service('StreamingDag', ['Metrics', function (Metrics) {

    /** The constructor */
    function StreamingDag(appId, processors, levels, edges) {
      this.appId = appId;
      this.processors = _flatMap(processors); // TODO: Try and convert to Scala (#458)
      this.processorHierarchyLevels = _flatMap(levels);
      this.edges = _flatMap(edges, function (item) {
        return [item[0] + '_' + item[2], {source: item[0], target: item[2], type: item[1]}];
      });
      this.meter = {};
      this.histogram = {};
    }

    StreamingDag.prototype = {

      /** Update (or add) specified metrics in an array */
      updateMetricsArray: function (array) {
        for (var i = 0; i < array.length; i++) {
          var value = array[i].value;
          this.updateMetrics(value[0], value[1]);
        }
      },

      /** Update (or add) specified metrics */
      updateMetrics: function (name, data) {
        switch (name) {
          case 'org.apache.gearpump.metrics.Metrics.Meter':
            _update(Metrics.decodeMeter, this.meter, this);
            break;
          case 'org.apache.gearpump.metrics.Metrics.Histogram':
            _update(Metrics.decodeHistogram, this.histogram, this);
            break;
        }

        function _update(decodeFn, coll, self) {
          var metric = decodeFn(data);
          if (metric.name.appId === self.appId) {
            var item = _getOrCreate(coll, metric.name.metric, {});
            var key = metric.name.processorId + '_' + metric.name.taskId;
            item[key] = metric.values;
            item[key].processorId = metric.name.processorId;
            item[key].taskClass = self.processors[metric.name.processorId].taskClass;
            item[key].taskId = metric.name.taskId;
          }
        }
      },

      hasMetrics: function () {
        return Object.keys(this.meter).length + Object.keys(this.histogram).length > 0;
      },

      getProcessorsData: function () {
        var weights = {};
        angular.forEach(this.processors, function (_, key) {
          var processorId = parseInt(key);
          weights[processorId] = this._calculateProcessorWeight(processorId);
        }, this);
        return {
          processors: angular.copy(this.processors),
          hierarchyLevels: angular.copy(this.processorHierarchyLevels),
          weights: weights
        };
      },

      /** Weight of a processor equals the sum of its send throughput and receive throughput. */
      _calculateProcessorWeight: function (processorId) {
        var weight = 0;
        //var connections = this._calculateProcessorConnections(processorId);
        return Math.max(d3.sum(this._getProcessorMetrics(processorId, this.meter.sendThroughput, 'meanRate')),
          d3.sum(this._getProcessorMetrics(processorId, this.meter.receiveThroughput, 'meanRate')));
        //return weight;
      },

      getEdgesData: function () {
        var bandwidths = {};
        angular.forEach(this.edges, function (_, edgeId) {
          bandwidths[edgeId] = this._calculateEdgeBandwidth(edgeId);
        }, /* scope */ this);
        return {
          edges: angular.copy(this.edges),
          bandwidths: bandwidths
        };
      },

      /** Bandwidth of an edge equals the minimum of average send throughput and average receive throughput. */
      _calculateEdgeBandwidth: function (edgeId) {
        var digits = edgeId.split('_');
        var sourceId = parseInt(digits[0]);
        var targetId = parseInt(digits[1]);
        var sourceOutputs = this._calculateProcessorConnections(sourceId).outputs;
        var targetInputs = this._calculateProcessorConnections(targetId).inputs;
        var sourceSendThroughput = d3.sum(this._getProcessorMetrics(sourceId, this.meter.sendThroughput, 'meanRate'));
        var targetReceiveThroughput = d3.sum(this._getProcessorMetrics(targetId, this.meter.receiveThroughput, 'meanRate'));
        return Math.min(
          sourceOutputs === 0 ? 0 : (sourceSendThroughput / sourceOutputs),
          targetInputs === 0 ? 0 : (targetReceiveThroughput / targetInputs));
      },

      _calculateProcessorConnections: function (processorId) {
        var result = {inputs: 0, outputs: 0};
        angular.forEach(this.edges, function (edge) {
          if (edge.source === processorId) {
            result.outputs++;
          } else if (edge.target === processorId) {
            result.inputs++;
          }
        }, /* scope */ this);
        return result;
      },

      /** Return particular metrics value of a processor as an array. */
      _getProcessorMetrics: function (processorId, metricsGroup, metricType) {
        var values = [];
        if (metricsGroup) {
          var tasks = this.processors[processorId].parallelism;
          for (var taskId = 0; taskId < tasks; taskId++) {
            var name = processorId + '_' + taskId;
            if (metricsGroup.hasOwnProperty(name)) {
              values.push(metricsGroup[name][metricType]);
            }
          }
        }
        return values;
      },

      /** Return particular metrics value of all processors as an array. */
      _getAggregatedMetrics: function(metricsGroup, metricsType, op) {
        var values = [];
        if (metricsGroup) {
          angular.forEach(this.processors, function(_, key) {
            var processorId = parseInt(key);
            var processorValues = this._getProcessorMetrics(processorId, metricsGroup, metricsType);
            if (op === 'sum') {
              processorValues = d3.sum(processorValues);
            }
            values.push(processorValues);
          }, /* scope */ this);
        }
        return values;
      },

      getTotalProcessedEvents: function() {
        var sent = this._getAggregatedMetrics(this.meter.sendThroughput, 'count');
        var received = this._getAggregatedMetrics(this.meter.receiveThroughput, 'count');
        return {sent: d3.sum(sent), received: d3.sum(received)};
      },

      getThroughput: function() {
        var sent = this._getAggregatedMetrics(this.meter.sendThroughput, 'meanRate');
        var received = this._getAggregatedMetrics(this.meter.receiveThroughput, 'meanRate');
        return {sent: d3.sum(sent), received: d3.sum(received)};
      },

      getProcessTime: function() {
        return d3.mean(this._getAggregatedMetrics(this.histogram.processTime, 'mean'));
      },

      getReceiveLatency: function() {
        return d3.mean(this._getAggregatedMetrics(this.histogram.receiveLatency, 'mean'));
      },

      /** Return the depth of the hierarchy layout */
      hierarchyDepth: function () {
        return d3.max(d3.values(this.processorHierarchyLevels));
      }
    };

    function _getOrCreate(obj, prop, init) {
      if (!obj.hasOwnProperty(prop)) {
        obj[prop] = init;
      }
      return obj[prop];
    }

    function _flatMap(array, fn) {
      var result = {};
      array.map(function (item) {
        if (fn) {
          item = fn(item);
        }
        result[item[0]] = item[1];
      });
      return result;
    }

    return StreamingDag;
  }])
;<commit_msg>fix #691: metrics would be stored in nested arrays<commit_after>/*
 * Licensed under the Apache License, Version 2.0
 * See accompanying LICENSE file.
 */
'use strict';

angular.module('dashboard.streamingdag', ['dashboard.metrics'])

  .service('StreamingDag', ['Metrics', function (Metrics) {

    /** The constructor */
    function StreamingDag(appId, processors, levels, edges) {
      this.appId = appId;
      this.processors = _flatMap(processors); // TODO: Try and convert to Scala (#458)
      this.processorHierarchyLevels = _flatMap(levels);
      this.edges = _flatMap(edges, function (item) {
        return [item[0] + '_' + item[2], {source: item[0], target: item[2], type: item[1]}];
      });
      this.meter = {};
      this.histogram = {};
    }

    StreamingDag.prototype = {

      /** Update (or add) specified metrics in an array */
      updateMetricsArray: function (array) {
        for (var i = 0; i < array.length; i++) {
          var value = array[i].value;
          this.updateMetrics(value[0], value[1]);
        }
      },

      /** Update (or add) specified metrics */
      updateMetrics: function (name, data) {
        switch (name) {
          case 'org.apache.gearpump.metrics.Metrics.Meter':
            _update(Metrics.decodeMeter, this.meter, this);
            break;
          case 'org.apache.gearpump.metrics.Metrics.Histogram':
            _update(Metrics.decodeHistogram, this.histogram, this);
            break;
        }

        function _update(decodeFn, coll, self) {
          var metric = decodeFn(data);
          if (metric.name.appId === self.appId) {
            var item = _getOrCreate(coll, metric.name.metric, {});
            var key = metric.name.processorId + '_' + metric.name.taskId;
            item[key] = metric.values;
            item[key].processorId = metric.name.processorId;
            item[key].taskClass = self.processors[metric.name.processorId].taskClass;
            item[key].taskId = metric.name.taskId;
          }
        }
      },

      hasMetrics: function () {
        return Object.keys(this.meter).length + Object.keys(this.histogram).length > 0;
      },

      getProcessorsData: function () {
        var weights = {};
        angular.forEach(this.processors, function (_, key) {
          var processorId = parseInt(key);
          weights[processorId] = this._calculateProcessorWeight(processorId);
        }, this);
        return {
          processors: angular.copy(this.processors),
          hierarchyLevels: angular.copy(this.processorHierarchyLevels),
          weights: weights
        };
      },

      /** Weight of a processor equals the sum of its send throughput and receive throughput. */
      _calculateProcessorWeight: function (processorId) {
        var weight = 0;
        //var connections = this._calculateProcessorConnections(processorId);
        return Math.max(d3.sum(this._getProcessorMetrics(processorId, this.meter.sendThroughput, 'meanRate')),
          d3.sum(this._getProcessorMetrics(processorId, this.meter.receiveThroughput, 'meanRate')));
        //return weight;
      },

      getEdgesData: function () {
        var bandwidths = {};
        angular.forEach(this.edges, function (_, edgeId) {
          bandwidths[edgeId] = this._calculateEdgeBandwidth(edgeId);
        }, /* scope */ this);
        return {
          edges: angular.copy(this.edges),
          bandwidths: bandwidths
        };
      },

      /** Bandwidth of an edge equals the minimum of average send throughput and average receive throughput. */
      _calculateEdgeBandwidth: function (edgeId) {
        var digits = edgeId.split('_');
        var sourceId = parseInt(digits[0]);
        var targetId = parseInt(digits[1]);
        var sourceOutputs = this._calculateProcessorConnections(sourceId).outputs;
        var targetInputs = this._calculateProcessorConnections(targetId).inputs;
        var sourceSendThroughput = d3.sum(this._getProcessorMetrics(sourceId, this.meter.sendThroughput, 'meanRate'));
        var targetReceiveThroughput = d3.sum(this._getProcessorMetrics(targetId, this.meter.receiveThroughput, 'meanRate'));
        return Math.min(
          sourceOutputs === 0 ? 0 : (sourceSendThroughput / sourceOutputs),
          targetInputs === 0 ? 0 : (targetReceiveThroughput / targetInputs));
      },

      _calculateProcessorConnections: function (processorId) {
        var result = {inputs: 0, outputs: 0};
        angular.forEach(this.edges, function (edge) {
          if (edge.source === processorId) {
            result.outputs++;
          } else if (edge.target === processorId) {
            result.inputs++;
          }
        }, /* scope */ this);
        return result;
      },

      /** Return particular metrics value of a processor as an array. */
      _getProcessorMetrics: function (processorId, metricsGroup, metricType) {
        var values = [];
        if (metricsGroup) {
          var tasks = this.processors[processorId].parallelism;
          for (var taskId = 0; taskId < tasks; taskId++) {
            var name = processorId + '_' + taskId;
            if (metricsGroup.hasOwnProperty(name)) {
              values.push(metricsGroup[name][metricType]);
            }
          }
        }
        return values;
      },

      /** Return particular metrics value of all processors as an array. */
      _getAggregatedMetrics: function(metricsGroup, metricsType) {
        var values = [];
        if (metricsGroup) {
          angular.forEach(this.processors, function(_, key) {
            var processorId = parseInt(key);
            var processorValues = this._getProcessorMetrics(processorId, metricsGroup, metricsType);
            values = values.concat(processorValues);
          }, /* scope */ this);
        }
        return values;
      },

      getTotalProcessedEvents: function() {
        var sent = this._getAggregatedMetrics(this.meter.sendThroughput, 'count');
        var received = this._getAggregatedMetrics(this.meter.receiveThroughput, 'count');
        return {sent: d3.sum(sent), received: d3.sum(received)};
      },

      getThroughput: function() {
        var sent = this._getAggregatedMetrics(this.meter.sendThroughput, 'meanRate');
        var received = this._getAggregatedMetrics(this.meter.receiveThroughput, 'meanRate');
        return {sent: d3.sum(sent), received: d3.sum(received)};
      },

      getProcessTime: function() {
        return d3.mean(this._getAggregatedMetrics(this.histogram.processTime, 'mean'));
      },

      getReceiveLatency: function() {
        return d3.mean(this._getAggregatedMetrics(this.histogram.receiveLatency, 'mean'));
      },

      /** Return the depth of the hierarchy layout */
      hierarchyDepth: function () {
        return d3.max(d3.values(this.processorHierarchyLevels));
      }
    };

    function _getOrCreate(obj, prop, init) {
      if (!obj.hasOwnProperty(prop)) {
        obj[prop] = init;
      }
      return obj[prop];
    }

    function _flatMap(array, fn) {
      var result = {};
      array.map(function (item) {
        if (fn) {
          item = fn(item);
        }
        result[item[0]] = item[1];
      });
      return result;
    }

    return StreamingDag;
  }])
;<|endoftext|>


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

module.exports = function (fs, path, url, convict) {
  const AVAILABLE_BACKENDS = ["memory", "mysql", "memcached", "cassandra"]
  const STATS_BACKENDS = ['none', 'heka', 'statsd']

  var conf = convict({
    env: {
      doc: "The current node.js environment",
      default: "production",
      format: [ "production", "local", "test" ],
      env: 'NODE_ENV'
    },
    log: {
      level: {
        default: 'info'
      }
    },
    public_url: {
      format: "url",
      // the real url is set by awsbox
      default: "http://127.0.0.1:9000",
      env: "PUBLIC_URL"
    },
    domain: {
      format: "url",
      default: "127.0.0.1:9000"
    },
    secretKeyFile: {
      default: path.resolve(__dirname, '../config/secret-key.json')
    },
    publicKeyFile: {
      default: path.resolve(__dirname, '../config/public-key.json')
    },
    kvstore: {
      cache: {
        format: AVAILABLE_BACKENDS,
        default: 'memory',
        env: 'KVSTORE_CACHE'
      },
      backend: {
        format: AVAILABLE_BACKENDS,
        default: "memory",
        env: 'KVSTORE_BACKEND'
      },
      available_backends: {
        doc: "List of available key-value stores",
        default: AVAILABLE_BACKENDS
      }
    },
    memcached: {
      hosts: {
        default: '127.0.0.1:11211'
      },
      lifetime: {
        default: 1000 * 60 * 2
      }
    },
    mysql: {
      user: {
        default: 'root',
        env: 'MYSQL_USERNAME'
      },
      password: {
        default: '',
        env: 'MYSQL_PASSWORD'
      },
      database: {
        default: 'picl',
        env: 'MYSQL_DATABASE'
      },
      host: {
        default: '127.0.0.1',
        env: 'MYSQL_HOST'
      },
      port: {
        default: '3306',
        env: 'MYSQL_PORT'
      },
      create_schema: {
        default: true,
        env: 'CREATE_MYSQL_SCHEMA'
      },
      max_query_time_ms: {
        doc: "The maximum amount of time we'll allow a query to run before considering the database to be sick",
        default: 5000,
        format: 'duration',
        env: 'MAX_QUERY_TIME_MS'
      },
      max_reconnect_attempts: {
        doc: "The maximum number of times we'll attempt to reconnect to the database before failing all outstanding queries",
        default: 3,
        format: 'nat'
      }
    },
    bind_to: {
      host: {
        doc: "The ip address the server should bind",
        default: '127.0.0.1',
        format: 'ipaddress',
        env: 'IP_ADDRESS'
      },
      port: {
        doc: "The port the server should bind",
        default: 9000,
        format: 'port',
        env: 'PORT'
      }
    },
    bridge: {
      url: {
        doc: "Thes url of the bridge server",
        default: 'http://127.0.0.1:3030',
        env: 'FAB_URL'
      }
    },
    stats: {
      backend: {
        format: STATS_BACKENDS,
        default: 'none',
        env: 'STATS_BACKEND'
      }
    },
    heka: {
      host: {
        default: '127.0.0.1'
      },
      port: {
        default: 4880
      }
    },
    statsd: {
      host: {
        default: '127.0.0.1',
      },
      port: {
        default: 8125
      }
    },
    srp: {
      alg_name: {
        doc: "Name of secure hash algorithm to use",
        default: 'sha256',
        env: 'SRP_HASH_ALGORITHM'
      },
      N_bits: {
        doc: "Size of N",
        default: 2048,
        format: 'nat',
        env: 'SRP_N_BITS'
      },
      s_bytes: {
        doc: "Bytes in salt",
        default: 32,
        format: 'nat',
        env: 'SRP_S_BYTES'
      }
    },
    smtp: {
      listen: {
        host: {
          doc: 'host for bin/mailer.js',
          default: '127.0.0.1',
          env: 'MAILER_HOST'
        },
        port: {
          doc: 'port for bin/mailer.js',
          default: 9999,
          env: 'MAILER_PORT'
        }
      },
      host: {
        doc: 'SMTP host for sending email',
        default: 'smtp.gmail.com',
        env: 'SMTP_HOST'
      },
      port: {
        doc: 'SMTP port',
        default: 465,
        env: 'SMTP_PORT'
      },
      secure: {
        doc: 'Connect to SMTP host securely',
        default: true,
        env: 'SMTP_SECURE'
      },
      user: {
        doc: 'SMTP username',
        format: String,
        default: undefined,
        env: 'SMTP_USER'
      },
      password: {
        doc: 'SMTP password',
        format: String,
        default: undefined,
        env: 'SMTP_PASS'
      },
      sender: {
        doc: 'email address of the sender',
        default: 'Firefox Accounts <no-reply@lcip.org>',
        env: 'SMTP_SENDER'
      },
      verification_url: {
        doc: 'The landing page for verify emails',
        format: String,
        default: undefined,
        env: 'VERIFY_URL',
        arg: 'verify-url'
      },
      report_url: {
        doc: 'A page where users can report suspicious activity',
        format: String,
        default: '#'
      },
      template_path: {
        doc: 'path to the email template directory',
        default: path.resolve(__dirname, '../templates/email')
      }
    },
    toobusy: {
      max_lag: {
        doc: "Max event-loop lag before toobusy reports failure",
        default: 70,
        format: 'nat',
        env: 'TOOBUSY_MAX_LAG'
      }
    },
    dev: {
      verified: {
        doc: 'new Accounts should start already verified',
        default: false,
        env: 'DEV_VERIFIED'
      }
    }
  })

  // handle configuration files.  you can specify a CSV list of configuration
  // files to process, which will be overlayed in order, in the CONFIG_FILES
  // environment variable. By default, the ./config/<env>.json file is loaded.

  var envConfig = path.join(__dirname, conf.get('env') + '.json')
  var files = (envConfig + ',' + process.env.CONFIG_FILES)
                .split(',').filter(fs.existsSync)
  conf.loadFile(files)

  // set the public url as the issuer domain for assertions
  conf.set('domain', url.parse(conf.get('public_url')).host)

  if (! conf.has('smtp.verification_url')) {
    conf.set('smtp.verification_url', conf.get('public_url') + '/v1/verify_email')
  }

  conf.validate()

  return conf
}
<commit_msg>Make TOOBUSY_MAX_LAG be automatically converted to an int.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

module.exports = function (fs, path, url, convict) {
  const AVAILABLE_BACKENDS = ["memory", "mysql", "memcached", "cassandra"]
  const STATS_BACKENDS = ['none', 'heka', 'statsd']

  var conf = convict({
    env: {
      doc: "The current node.js environment",
      default: "production",
      format: [ "production", "local", "test" ],
      env: 'NODE_ENV'
    },
    log: {
      level: {
        default: 'info'
      }
    },
    public_url: {
      format: "url",
      // the real url is set by awsbox
      default: "http://127.0.0.1:9000",
      env: "PUBLIC_URL"
    },
    domain: {
      format: "url",
      default: "127.0.0.1:9000"
    },
    secretKeyFile: {
      default: path.resolve(__dirname, '../config/secret-key.json')
    },
    publicKeyFile: {
      default: path.resolve(__dirname, '../config/public-key.json')
    },
    kvstore: {
      cache: {
        format: AVAILABLE_BACKENDS,
        default: 'memory',
        env: 'KVSTORE_CACHE'
      },
      backend: {
        format: AVAILABLE_BACKENDS,
        default: "memory",
        env: 'KVSTORE_BACKEND'
      },
      available_backends: {
        doc: "List of available key-value stores",
        default: AVAILABLE_BACKENDS
      }
    },
    memcached: {
      hosts: {
        default: '127.0.0.1:11211'
      },
      lifetime: {
        default: 1000 * 60 * 2
      }
    },
    mysql: {
      user: {
        default: 'root',
        env: 'MYSQL_USERNAME'
      },
      password: {
        default: '',
        env: 'MYSQL_PASSWORD'
      },
      database: {
        default: 'picl',
        env: 'MYSQL_DATABASE'
      },
      host: {
        default: '127.0.0.1',
        env: 'MYSQL_HOST'
      },
      port: {
        default: '3306',
        env: 'MYSQL_PORT'
      },
      create_schema: {
        default: true,
        env: 'CREATE_MYSQL_SCHEMA'
      },
      max_query_time_ms: {
        doc: "The maximum amount of time we'll allow a query to run before considering the database to be sick",
        default: 5000,
        format: 'duration',
        env: 'MAX_QUERY_TIME_MS'
      },
      max_reconnect_attempts: {
        doc: "The maximum number of times we'll attempt to reconnect to the database before failing all outstanding queries",
        default: 3,
        format: 'nat'
      }
    },
    bind_to: {
      host: {
        doc: "The ip address the server should bind",
        default: '127.0.0.1',
        format: 'ipaddress',
        env: 'IP_ADDRESS'
      },
      port: {
        doc: "The port the server should bind",
        default: 9000,
        format: 'port',
        env: 'PORT'
      }
    },
    bridge: {
      url: {
        doc: "Thes url of the bridge server",
        default: 'http://127.0.0.1:3030',
        env: 'FAB_URL'
      }
    },
    stats: {
      backend: {
        format: STATS_BACKENDS,
        default: 'none',
        env: 'STATS_BACKEND'
      }
    },
    heka: {
      host: {
        default: '127.0.0.1'
      },
      port: {
        default: 4880
      }
    },
    statsd: {
      host: {
        default: '127.0.0.1',
      },
      port: {
        default: 8125
      }
    },
    srp: {
      alg_name: {
        doc: "Name of secure hash algorithm to use",
        default: 'sha256',
        env: 'SRP_HASH_ALGORITHM'
      },
      N_bits: {
        doc: "Size of N",
        default: 2048,
        format: 'nat',
        env: 'SRP_N_BITS'
      },
      s_bytes: {
        doc: "Bytes in salt",
        default: 32,
        format: 'nat',
        env: 'SRP_S_BYTES'
      }
    },
    smtp: {
      listen: {
        host: {
          doc: 'host for bin/mailer.js',
          default: '127.0.0.1',
          env: 'MAILER_HOST'
        },
        port: {
          doc: 'port for bin/mailer.js',
          default: 9999,
          env: 'MAILER_PORT'
        }
      },
      host: {
        doc: 'SMTP host for sending email',
        default: 'smtp.gmail.com',
        env: 'SMTP_HOST'
      },
      port: {
        doc: 'SMTP port',
        default: 465,
        env: 'SMTP_PORT'
      },
      secure: {
        doc: 'Connect to SMTP host securely',
        default: true,
        env: 'SMTP_SECURE'
      },
      user: {
        doc: 'SMTP username',
        format: String,
        default: undefined,
        env: 'SMTP_USER'
      },
      password: {
        doc: 'SMTP password',
        format: String,
        default: undefined,
        env: 'SMTP_PASS'
      },
      sender: {
        doc: 'email address of the sender',
        default: 'Firefox Accounts <no-reply@lcip.org>',
        env: 'SMTP_SENDER'
      },
      verification_url: {
        doc: 'The landing page for verify emails',
        format: String,
        default: undefined,
        env: 'VERIFY_URL',
        arg: 'verify-url'
      },
      report_url: {
        doc: 'A page where users can report suspicious activity',
        format: String,
        default: '#'
      },
      template_path: {
        doc: 'path to the email template directory',
        default: path.resolve(__dirname, '../templates/email')
      }
    },
    toobusy: {
      max_lag: {
        doc: "Max event-loop lag before toobusy reports failure",
        default: 70,
        env: 'TOOBUSY_MAX_LAG'
      }
    },
    dev: {
      verified: {
        doc: 'new Accounts should start already verified',
        default: false,
        env: 'DEV_VERIFIED'
      }
    }
  })

  // handle configuration files.  you can specify a CSV list of configuration
  // files to process, which will be overlayed in order, in the CONFIG_FILES
  // environment variable. By default, the ./config/<env>.json file is loaded.

  var envConfig = path.join(__dirname, conf.get('env') + '.json')
  var files = (envConfig + ',' + process.env.CONFIG_FILES)
                .split(',').filter(fs.existsSync)
  conf.loadFile(files)

  // set the public url as the issuer domain for assertions
  conf.set('domain', url.parse(conf.get('public_url')).host)

  if (! conf.has('smtp.verification_url')) {
    conf.set('smtp.verification_url', conf.get('public_url') + '/v1/verify_email')
  }

  conf.validate()

  return conf
}
<|endoftext|>


<commit_before>var DEBUG_TAG = 'METEOR CORDOVA DEBUG (autoupdate_cordova.js) ';
var log = function (msg) {
  console.log(DEBUG_TAG + msg);
};

// This constant was picked by testing on iOS 7.1
// We limit the number of concurrent downloads because iOS gets angry on the
// application when a certain limit is exceeded and starts timing-out the
// connections in 1-2 minutes which makes the whole HCP really slow.
var MAX_NUM_CONCURRENT_DOWNLOADS = 30;
var MAX_RETRY_COUNT = 5;

var autoupdateVersionCordova = __meteor_runtime_config__.autoupdateVersionCordova || "unknown";

// The collection of acceptable client versions.
ClientVersions = new Mongo.Collection("meteor_autoupdate_clientVersions");

Autoupdate = {};

Autoupdate.newClientAvailable = function () {
  return !! ClientVersions.findOne({
    _id: 'version-cordova',
    version: {$ne: autoupdateVersionCordova}
  });
};

var writeFile = function (directoryPath, fileName, content, cb) {
  var fail = function (err) {
    cb(new Error("Failed to write file: ", err), null);
  };

  window.resolveLocalFileSystemURL(directoryPath, function (dirEntry) {
    var success = function (fileEntry) {
      fileEntry.createWriter(function (writer) {
        writer.onwrite = function (evt) {
          var result = evt.target.result;
          cb(null, result);
        };
        writer.onerror = fail;
        writer.write(content);
      }, fail);
    };

    dirEntry.getFile(fileName, {
      create: true,
      exclusive: false
    }, success, fail);
  }, fail);
};

var restartServer = function (location) {
  log('restartServer with location ' + location);
  var fail = function (err) { log("Unexpected error in restartServer: " + err.message) };
  var httpd = cordova && cordova.plugins && cordova.plugins.CordovaUpdate;

  if (! httpd) {
    fail(new Error('no httpd'));
    return;
  }

  var startServer = function (cordovajsRoot) {
    httpd.startServer({
      'www_root' : location,
      'cordovajs_root': cordovajsRoot
    }, function (url) {
      if (Package.reload) {
        Package.reload.Reload._reload();
      } else {
        window.location.reload();
      }
    }, fail);
  };

  httpd.getCordovajsRoot(function (cordovajsRoot) {
    startServer(cordovajsRoot);
  }, fail);
};

var hasCalledReload = false;
var updating = false;
var localPathPrefix = null;

var onNewVersion = function () {
  var ft = new FileTransfer();
  var urlPrefix = Meteor.absoluteUrl() + '__cordova';
  HTTP.get(urlPrefix + '/manifest.json', function (err, res) {
    if (err || ! res.data) {
      log('Failed to download the manifest ' + (err && err.message) + ' ' + (res && res.content));
      return;
    }

    updating = true;
    ensureLocalPathPrefix(_.bind(downloadNewVersion, null, res.data));
  });
};

var downloadNewVersion = function (program) {
  var urlPrefix = Meteor.absoluteUrl() + '__cordova';
  var manifest = _.clone(program.manifest);
  var version = program.version;
  var ft = new FileTransfer();

  manifest.push({ url: '/index.html?' + Random.id() });

  var versionPrefix = localPathPrefix + version;

  var queue = [];
  _.each(manifest, function (item) {
    if (! item.url) return;

    var url = item.url;
    url = url.replace(/\?.+$/, '');

    queue.push(url);
  });

  var afterAllFilesDownloaded = _.after(queue.length, function () {
    var wroteManifest = function (err) {
      if (err) {
        log("Failed to write manifest.json: " + err);
        // XXX do something smarter?
        return;
      }

      // success! downloaded all sources and saved the manifest
      // save the version string for atomicity
      writeFile(localPathPrefix, 'version', version, function (err) {
        if (err) {
          log("Failed to write version: " + err);
          return;
        }

        // don't call reload twice!
        if (! hasCalledReload) {
          var location = uriToPath(localPathPrefix + version);
          restartServer(location);
        }
      });
    };

    writeFile(versionPrefix, 'manifest.json',
              JSON.stringify(program, undefined, 2), wroteManifest);
  });

  var downloadUrl = function (url) {
    console.log(DEBUG_TAG + "start downloading " + url);
    // Add a cache buster to ensure that we don't cache an old asset.
    var uri = encodeURI(urlPrefix + url + '?' + Random.id());

    // Try to download the file a few times.
    var tries = 0;
    var tryDownload = function () {
      ft.download(uri, versionPrefix + encodeURI(url), function (entry) {
        if (entry) {
          console.log(DEBUG_TAG + "done downloading " + url);
          // start downloading next queued url
          if (queue.length)
            downloadUrl(queue.shift());
          afterAllFilesDownloaded();
        }
      }, function (err) {
        // It failed, try again if we have tried less than 5 times.
        if (tries++ < MAX_RETRY_COUNT) {
          log("Download error, will retry (#" + tries + "): " + uri);
          tryDownload();
        } else {
          log('Download failed: ' + JSON.stringify(err) + ", source=" + err.source + ", target=" + err.target);
        }
      });
    };

    tryDownload();
  };

  _.times(Math.min(MAX_NUM_CONCURRENT_DOWNLOADS, queue.length), function () {
    var nextUrl = queue.shift();
    // XXX defer the next download so iOS doesn't rate limit us on concurrent
    // downloads
    Meteor.setTimeout(downloadUrl.bind(null, nextUrl), 50);
  });
};

var retry = new Retry({
  minCount: 0, // don't do any immediate retries
  baseTimeout: 30*1000 // start with 30s
});
var failures = 0;

Autoupdate._retrySubscription = function () {
  var appId = __meteor_runtime_config__.appId;
  Meteor.subscribe("meteor_autoupdate_clientVersions", appId, {
    onError: function (err) {
      Meteor._debug("autoupdate subscription failed:", err);
      failures++;
      retry.retryLater(failures, function () {
        // Just retry making the subscription, don't reload the whole
        // page. While reloading would catch more cases (for example,
        // the server went back a version and is now doing old-style hot
        // code push), it would also be more prone to reload loops,
        // which look really bad to the user. Just retrying the
        // subscription over DDP means it is at least possible to fix by
        // updating the server.
        Autoupdate._retrySubscription();
      });
    }
  });
  if (Package.reload) {
    var checkNewVersionDocument = function (doc) {
      var self = this;
      if (doc.version !== autoupdateVersionCordova) {
        window.fireGlobalEvent('onNewVersion', doc.version)
        onNewVersion();
      }
    };

    var handle = ClientVersions.find({
      _id: 'version-cordova'
    }).observe({
      added: checkNewVersionDocument,
      changed: checkNewVersionDocument
    });
  }
};

Meteor.startup(function () {
  clearAutoupdateCache(autoupdateVersionCordova);
});
Meteor.startup(Autoupdate._retrySubscription);

// A helper that removes old directories left from previous autoupdates
var clearAutoupdateCache = function (currentVersion) {
  ensureLocalPathPrefix(function () {
    // Try to clean up our cache directory, make sure to scan the directory
    // *before* loading the actual app. This ordering will prevent race
    // conditions when the app code tries to download a new version before
    // the old-cache removal has scanned the cache folder.
    listDirectory(localPathPrefix, {dirsOnly: true}, function (err, names) {
      // Couldn't get the list of dirs or risking to get into a race with an
      // on-going update to disk.
      if (err || updating) {
        return;
      }

      _.each(names, function (name) {
        // Skip the folder with the latest version
        if (name === currentVersion)
          return;

        // remove everything else, as we don't want to keep too much cache
        // around on disk
        removeDirectory(localPathPrefix + name + '/', function (err) {
          if (err) {
            log('Failed to remove an old cache folder '
                + name + ':' + err.message);
          } else {
            log('Successfully removed an old cache folder ' + name);
          }
        });
      });
    });
  })
};

// Cordova File plugin helpers
var listDirectory = function (url, options, cb) {
  if (typeof options === 'function')
    cb = options, options = {};

  var fail = function (err) { cb(err); };
  window.resolveLocalFileSystemURL(url, function (entry) {
    var reader = entry.createReader();
    reader.readEntries(function (entries) {
      var names = [];
      _.each(entries, function (entry) {
        if (! options.dirsOnly || entry.isDirectory)
          names.push(entry.name);
      });
      cb(null, names);
    }, fail);
  }, fail);
};

var removeDirectory = function (url, cb) {
  var fail = function (err) {
    cb(err);
  };
  window.resolveLocalFileSystemURL(url, function (entry) {
    entry.removeRecursively(function () { cb(); }, fail);
  }, fail);
};

var uriToPath = function (uri) {
  return decodeURI(uri).replace(/^file:\/\//g, '');
};

var ensureLocalPathPrefix = function (cb) {
  if (! localPathPrefix) {
    if (! cordova.file.dataDirectory) {
      // Since ensureLocalPathPrefix function is always called on
      // Meteor.startup, all Cordova plugins should be ready.
      // XXX Experiments have shown that it is not always the case, even when
      // the cordova.file symbol is attached, properties like dataDirectory
      // still can be null. Poll until we are sure the property is attached.
      console.log(DEBUG_TAG + 'cordova.file.dataDirectory is null, retrying in 20ms');
      // REMOVED to prevent loop in new app
      // Meteor.setTimeout(_.bind(ensureLocalPathPrefix, null, cb), 20);
    } else {
      localPathPrefix = cordova.file.dataDirectory + 'meteor/';
      cb();
    }
  } else {
    cb();
  }
};

<commit_msg>Fix error with autoupdate with the new mobile app<commit_after>var DEBUG_TAG = 'METEOR CORDOVA DEBUG (autoupdate_cordova.js) ';
var log = function (msg) {
  console.log(DEBUG_TAG + msg);
};

// This constant was picked by testing on iOS 7.1
// We limit the number of concurrent downloads because iOS gets angry on the
// application when a certain limit is exceeded and starts timing-out the
// connections in 1-2 minutes which makes the whole HCP really slow.
var MAX_NUM_CONCURRENT_DOWNLOADS = 30;
var MAX_RETRY_COUNT = 5;

var autoupdateVersionCordova = __meteor_runtime_config__.autoupdateVersionCordova || "unknown";

// The collection of acceptable client versions.
ClientVersions = new Mongo.Collection("meteor_autoupdate_clientVersions");

Autoupdate = {};

Autoupdate.newClientAvailable = function () {
  return !! ClientVersions.findOne({
    _id: 'version-cordova',
    version: {$ne: autoupdateVersionCordova}
  });
};

var writeFile = function (directoryPath, fileName, content, cb) {
  var fail = function (err) {
    cb(new Error("Failed to write file: ", err), null);
  };

  window.resolveLocalFileSystemURL(directoryPath, function (dirEntry) {
    var success = function (fileEntry) {
      fileEntry.createWriter(function (writer) {
        writer.onwrite = function (evt) {
          var result = evt.target.result;
          cb(null, result);
        };
        writer.onerror = fail;
        writer.write(content);
      }, fail);
    };

    dirEntry.getFile(fileName, {
      create: true,
      exclusive: false
    }, success, fail);
  }, fail);
};

var restartServer = function (location) {
  log('restartServer with location ' + location);
  var fail = function (err) { log("Unexpected error in restartServer: " + err.message) };
  var httpd = cordova && cordova.plugins && cordova.plugins.CordovaUpdate;

  if (! httpd) {
    fail(new Error('no httpd'));
    return;
  }

  var startServer = function (cordovajsRoot) {
    httpd.startServer({
      'www_root' : location,
      'cordovajs_root': cordovajsRoot
    }, function (url) {
      if (Package.reload) {
        Package.reload.Reload._reload();
      } else {
        window.location.reload();
      }
    }, fail);
  };

  httpd.getCordovajsRoot(function (cordovajsRoot) {
    startServer(cordovajsRoot);
  }, fail);
};

var hasCalledReload = false;
var updating = false;
var localPathPrefix = null;

var onNewVersion = function () {
  if (!window.FileTransfer) {
    return;
  }
  var ft = new FileTransfer();
  var urlPrefix = Meteor.absoluteUrl() + '__cordova';
  HTTP.get(urlPrefix + '/manifest.json', function (err, res) {
    if (err || ! res.data) {
      log('Failed to download the manifest ' + (err && err.message) + ' ' + (res && res.content));
      return;
    }

    updating = true;
    ensureLocalPathPrefix(_.bind(downloadNewVersion, null, res.data));
  });
};

var downloadNewVersion = function (program) {
  if (!window.FileTransfer) {
    return;
  }
  var urlPrefix = Meteor.absoluteUrl() + '__cordova';
  var manifest = _.clone(program.manifest);
  var version = program.version;
  var ft = new FileTransfer();

  manifest.push({ url: '/index.html?' + Random.id() });

  var versionPrefix = localPathPrefix + version;

  var queue = [];
  _.each(manifest, function (item) {
    if (! item.url) return;

    var url = item.url;
    url = url.replace(/\?.+$/, '');

    queue.push(url);
  });

  var afterAllFilesDownloaded = _.after(queue.length, function () {
    var wroteManifest = function (err) {
      if (err) {
        log("Failed to write manifest.json: " + err);
        // XXX do something smarter?
        return;
      }

      // success! downloaded all sources and saved the manifest
      // save the version string for atomicity
      writeFile(localPathPrefix, 'version', version, function (err) {
        if (err) {
          log("Failed to write version: " + err);
          return;
        }

        // don't call reload twice!
        if (! hasCalledReload) {
          var location = uriToPath(localPathPrefix + version);
          restartServer(location);
        }
      });
    };

    writeFile(versionPrefix, 'manifest.json',
              JSON.stringify(program, undefined, 2), wroteManifest);
  });

  var downloadUrl = function (url) {
    console.log(DEBUG_TAG + "start downloading " + url);
    // Add a cache buster to ensure that we don't cache an old asset.
    var uri = encodeURI(urlPrefix + url + '?' + Random.id());

    // Try to download the file a few times.
    var tries = 0;
    var tryDownload = function () {
      ft.download(uri, versionPrefix + encodeURI(url), function (entry) {
        if (entry) {
          console.log(DEBUG_TAG + "done downloading " + url);
          // start downloading next queued url
          if (queue.length)
            downloadUrl(queue.shift());
          afterAllFilesDownloaded();
        }
      }, function (err) {
        // It failed, try again if we have tried less than 5 times.
        if (tries++ < MAX_RETRY_COUNT) {
          log("Download error, will retry (#" + tries + "): " + uri);
          tryDownload();
        } else {
          log('Download failed: ' + JSON.stringify(err) + ", source=" + err.source + ", target=" + err.target);
        }
      });
    };

    tryDownload();
  };

  _.times(Math.min(MAX_NUM_CONCURRENT_DOWNLOADS, queue.length), function () {
    var nextUrl = queue.shift();
    // XXX defer the next download so iOS doesn't rate limit us on concurrent
    // downloads
    Meteor.setTimeout(downloadUrl.bind(null, nextUrl), 50);
  });
};

var retry = new Retry({
  minCount: 0, // don't do any immediate retries
  baseTimeout: 30*1000 // start with 30s
});
var failures = 0;

Autoupdate._retrySubscription = function () {
  var appId = __meteor_runtime_config__.appId;
  Meteor.subscribe("meteor_autoupdate_clientVersions", appId, {
    onError: function (err) {
      Meteor._debug("autoupdate subscription failed:", err);
      failures++;
      retry.retryLater(failures, function () {
        // Just retry making the subscription, don't reload the whole
        // page. While reloading would catch more cases (for example,
        // the server went back a version and is now doing old-style hot
        // code push), it would also be more prone to reload loops,
        // which look really bad to the user. Just retrying the
        // subscription over DDP means it is at least possible to fix by
        // updating the server.
        Autoupdate._retrySubscription();
      });
    }
  });
  if (Package.reload) {
    var checkNewVersionDocument = function (doc) {
      var self = this;
      if (doc.version !== autoupdateVersionCordova) {
        window.fireGlobalEvent('onNewVersion', doc.version)
        onNewVersion();
      }
    };

    var handle = ClientVersions.find({
      _id: 'version-cordova'
    }).observe({
      added: checkNewVersionDocument,
      changed: checkNewVersionDocument
    });
  }
};

Meteor.startup(function () {
  clearAutoupdateCache(autoupdateVersionCordova);
});
Meteor.startup(Autoupdate._retrySubscription);

// A helper that removes old directories left from previous autoupdates
var clearAutoupdateCache = function (currentVersion) {
  ensureLocalPathPrefix(function () {
    // Try to clean up our cache directory, make sure to scan the directory
    // *before* loading the actual app. This ordering will prevent race
    // conditions when the app code tries to download a new version before
    // the old-cache removal has scanned the cache folder.
    listDirectory(localPathPrefix, {dirsOnly: true}, function (err, names) {
      // Couldn't get the list of dirs or risking to get into a race with an
      // on-going update to disk.
      if (err || updating) {
        return;
      }

      _.each(names, function (name) {
        // Skip the folder with the latest version
        if (name === currentVersion)
          return;

        // remove everything else, as we don't want to keep too much cache
        // around on disk
        removeDirectory(localPathPrefix + name + '/', function (err) {
          if (err) {
            log('Failed to remove an old cache folder '
                + name + ':' + err.message);
          } else {
            log('Successfully removed an old cache folder ' + name);
          }
        });
      });
    });
  })
};

// Cordova File plugin helpers
var listDirectory = function (url, options, cb) {
  if (typeof options === 'function')
    cb = options, options = {};

  var fail = function (err) { cb(err); };
  window.resolveLocalFileSystemURL(url, function (entry) {
    var reader = entry.createReader();
    reader.readEntries(function (entries) {
      var names = [];
      _.each(entries, function (entry) {
        if (! options.dirsOnly || entry.isDirectory)
          names.push(entry.name);
      });
      cb(null, names);
    }, fail);
  }, fail);
};

var removeDirectory = function (url, cb) {
  var fail = function (err) {
    cb(err);
  };
  window.resolveLocalFileSystemURL(url, function (entry) {
    entry.removeRecursively(function () { cb(); }, fail);
  }, fail);
};

var uriToPath = function (uri) {
  return decodeURI(uri).replace(/^file:\/\//g, '');
};

var ensureLocalPathPrefix = function (cb) {
  if (! localPathPrefix) {
    if (! cordova.file.dataDirectory) {
      // Since ensureLocalPathPrefix function is always called on
      // Meteor.startup, all Cordova plugins should be ready.
      // XXX Experiments have shown that it is not always the case, even when
      // the cordova.file symbol is attached, properties like dataDirectory
      // still can be null. Poll until we are sure the property is attached.
      console.log(DEBUG_TAG + 'cordova.file.dataDirectory is null, retrying in 20ms');
      // REMOVED to prevent loop in new app
      // Meteor.setTimeout(_.bind(ensureLocalPathPrefix, null, cb), 20);
    } else {
      localPathPrefix = cordova.file.dataDirectory + 'meteor/';
      cb();
    }
  } else {
    cb();
  }
};

<|endoftext|>


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

var ref = require('ref')
var assert = require('assert')
var debug = require('debug')('ffi:types')
var Struct = require('ref-struct')
var bindings = require('./bindings')

/**
 * Define the `ffi_type` struct (see deps/libffi/include/ffi.h) for use in JS.
 * This struct type is used internally to define custom struct rtn/arg types.
 */

var FFI_TYPE = Type.FFI_TYPE = Struct()
FFI_TYPE.defineProperty('size',      ref.types.size_t)
FFI_TYPE.defineProperty('alignment', ref.types.ushort)
FFI_TYPE.defineProperty('type',      ref.types.ushort)
// this last prop is a C Array of `ffi_type *` elements, so this is `ffi_type **`
var ffi_type_ptr_array = ref.refType(ref.refType(FFI_TYPE))
FFI_TYPE.defineProperty('elements',  ffi_type_ptr_array)
assert.equal(bindings.FFI_TYPE_SIZE, FFI_TYPE.size)

/**
 * Returns a `ffi_type *` Buffer appropriate for the given "type".
 *
 * @param {Type|String} type A "ref" type (or string) to get the `ffi_type` for
 * @return {Buffer} A buffer pointing to a `ffi_type` instance for "type"
 * @api private
 */

function Type (type) {
  type = ref.coerceType(type)
  debug('Type()', type.name || type)
  assert(type.indirection >= 1, 'invalid "type" given: ' + (type.name || type))
  var rtn

  // first we assume it's a regular "type". if the "indirection" is greater than
  // 1, then we can just use "pointer" ffi_type, otherwise we hope "ffi_type" is
  // set
  if (type.indirection === 1) {
    rtn = type.ffi_type
  } else {
    rtn = bindings.FFI_TYPES.pointer
  }

  // if "rtn" isn't set (ffi_type was not set) then we check for "ref-array" type
  if (!rtn && type.type) {
    // got a "ref-array" type
    // passing arrays to C functions are always by reference, so we use "pointer"
    rtn = bindings.FFI_TYPES.pointer
  }

  if (!rtn && type.fields) {
    // got a "ref-struct" type
    // need to create the `ffi_type` instance manually
    debug('creating an `ffi_type` for given "ref-struct" type')
    var fields = type.fields
      , fieldNames = Object.keys(fields)
      , numFields = fieldNames.length
      , ffi_type = new FFI_TYPE
      , i = 0

    ffi_type.size = 0
    ffi_type.alignment = 0
    ffi_type.type = 13 // FFI_TYPE_STRUCT

    // hand-crafting a null-terminated array here.
    // XXX: use "ref-array"?
    var elementsSize = ref.sizeof.pointer * (numFields + 1) // +1 because of the NULL terminator
    var elements = ffi_type.elements = new Buffer(elementsSize)
    for (i = 0; i < numFields; i++) {
      var field = fields[fieldNames[i]]
      var ffi_type_ptr = Type(field.type)
      // TODO: handle "fixedLength" arrays within structs (figure out what libffi
      // wants us to do...)
      elements.writePointer(ffi_type_ptr, i * ref.sizeof.pointer)
    }
    // final NULL pointer to terminate the Array
    elements.writePointer(ref.NULL, i * ref.sizeof.pointer)
    // also set the `ffi_type` property to that it's cached for next time
    rtn = type.ffi_type = ffi_type.ref()
  }

  if (!rtn && type.name) {
    // handle "ref" types other than the set that node-ffi is using (i.e.
    // a separate copy)
    rtn = type.ffi_type = bindings.FFI_TYPES[type.name]
  }

  assert(rtn, 'Could not determine the `ffi_type` instance for type: ' + (type.name || type))
  debug('returning `ffi_type`', rtn.name)
  return rtn
}
module.exports = Type
<commit_msg>type: make arrays within structs work as expected<commit_after>
/**
 * Module dependencies.
 */

var ref = require('ref')
var assert = require('assert')
var debug = require('debug')('ffi:types')
var Struct = require('ref-struct')
var bindings = require('./bindings')

/**
 * Define the `ffi_type` struct (see deps/libffi/include/ffi.h) for use in JS.
 * This struct type is used internally to define custom struct rtn/arg types.
 */

var FFI_TYPE = Type.FFI_TYPE = Struct()
FFI_TYPE.defineProperty('size',      ref.types.size_t)
FFI_TYPE.defineProperty('alignment', ref.types.ushort)
FFI_TYPE.defineProperty('type',      ref.types.ushort)
// this last prop is a C Array of `ffi_type *` elements, so this is `ffi_type **`
var ffi_type_ptr_array = ref.refType(ref.refType(FFI_TYPE))
FFI_TYPE.defineProperty('elements',  ffi_type_ptr_array)
assert.equal(bindings.FFI_TYPE_SIZE, FFI_TYPE.size)

/**
 * Returns a `ffi_type *` Buffer appropriate for the given "type".
 *
 * @param {Type|String} type A "ref" type (or string) to get the `ffi_type` for
 * @return {Buffer} A buffer pointing to a `ffi_type` instance for "type"
 * @api private
 */

function Type (type) {
  type = ref.coerceType(type)
  debug('Type()', type.name || type)
  assert(type.indirection >= 1, 'invalid "type" given: ' + (type.name || type))
  var rtn

  // first we assume it's a regular "type". if the "indirection" is greater than
  // 1, then we can just use "pointer" ffi_type, otherwise we hope "ffi_type" is
  // set
  if (type.indirection === 1) {
    rtn = type.ffi_type
  } else {
    rtn = bindings.FFI_TYPES.pointer
  }

  // if "rtn" isn't set (ffi_type was not set) then we check for "ref-array" type
  if (!rtn && type.type) {
    // got a "ref-array" type
    // passing arrays to C functions are always by reference, so we use "pointer"
    rtn = bindings.FFI_TYPES.pointer
  }

  if (!rtn && type.fields) {
    // got a "ref-struct" type
    // need to create the `ffi_type` instance manually
    debug('creating an `ffi_type` for given "ref-struct" type')
    var fields = type.fields
      , fieldNames = Object.keys(fields)
      , numFields = fieldNames.length
      , numElements = 0
      , ffi_type = new FFI_TYPE
      , i = 0
      , field
      , ffi_type_ptr

    // these are the "ffi_type" values expected for a struct
    ffi_type.size = 0
    ffi_type.alignment = 0
    ffi_type.type = 13 // FFI_TYPE_STRUCT

    // first we have to figure out the number of "elements" that will go in the
    // array. this would normally just be "numFields" but we also have to account
    // for arrays, which each act as their own element
    for (i = 0; i < numFields; i++) {
      field = fields[fieldNames[i]]
      if (field.type.fixedLength > 0) {
        // a fixed-length "ref-array" type
        numElements += field.type.fixedLength
      } else {
        numElements += 1
      }
    }

    // hand-crafting a null-terminated array here.
    // XXX: use "ref-array"?
    var size = ref.sizeof.pointer * (numElements + 1) // +1 because of the NULL terminator
    var elements = ffi_type.elements = new Buffer(size)
    var index = 0
    for (i = 0; i < numFields; i++) {
      field = fields[fieldNames[i]]
      if (field.type.fixedLength > 0) {
        // a fixed-length "ref-array" type
        ffi_type_ptr = Type(field.type.type)
        for (var j = 0; j < field.type.fixedLength; j++) {
          elements.writePointer(ffi_type_ptr, (index++) * ref.sizeof.pointer)
        }
      } else {
        ffi_type_ptr = Type(field.type)
        elements.writePointer(ffi_type_ptr, (index++) * ref.sizeof.pointer)
      }
    }
    // final NULL pointer to terminate the Array
    elements.writePointer(ref.NULL, index * ref.sizeof.pointer)
    // also set the `ffi_type` property to that it's cached for next time
    rtn = type.ffi_type = ffi_type.ref()
  }

  if (!rtn && type.name) {
    // handle "ref" types other than the set that node-ffi is using (i.e.
    // a separate copy)
    rtn = type.ffi_type = bindings.FFI_TYPES[type.name]
  }

  assert(rtn, 'Could not determine the `ffi_type` instance for type: ' + (type.name || type))
  debug('returning `ffi_type`', rtn.name)
  return rtn
}
module.exports = Type
<|endoftext|>


<commit_before>/**
 * This file is a bit of a mess. If you're looking at it as a reference for how to write a preset,
 * I'd recommend looking only at `function preset(){}` and ignoring the rest, unless your new preset
 * really needs to work on babel-core < 6.13.x, which is unlikely.
 */

/**
 * This preset was originally an object, before function-based configurable presets were introduced.
 * For backward-compatibility with anything that may have been loading this preset and expecting
 * it to be a simple Babel config object, we maintain the old config here.
 */
module.exports = preset({});

// For backward compatibility with babel-core < v6.13.x, we use the 'buildPreset' property
// of the preset object for the preset creation function.
Object.defineProperty(module.exports, "buildPreset", {
  configurable: true,
  writable: true,
  // We make this non-enumerable so old versions of babel-core won't see it as an unknown property,
  // while allowing new versions to see it as a preset builder function.
  enumerable: false,
  value: preset,
});

function preset(context, opts) {
  const moduleTypes = ["commonjs", "amd", "umd", "systemjs"];
  let loose = false;
  let modules = "commonjs";

  if (opts !== undefined) {
    if (opts.loose !== undefined) loose = opts.loose;
    if (opts.modules !== undefined) modules = opts.modules;
  }

  if (typeof loose !== "boolean") throw new Error("Preset es2015 'loose' option must be a boolean.");
  if (modules !== false && moduleTypes.indexOf(modules) === -1) {
    throw new Error("Preset es2015 'modules' option must be 'false' to indicate no modules\n" +
      "or a module type which be be one of: 'commonjs' (default), 'amd', 'umd', 'systemjs'");
  }

  return {
    plugins: [
      [require("babel-plugin-transform-es2015-template-literals"), { loose }],
      require("babel-plugin-transform-es2015-literals"),
      require("babel-plugin-transform-es2015-function-name"),
      [require("babel-plugin-transform-es2015-arrow-functions")],
      require("babel-plugin-transform-es2015-block-scoped-functions"),
      [require("babel-plugin-transform-es2015-classes"), { loose }],
      require("babel-plugin-transform-es2015-object-super"),
      require("babel-plugin-transform-es2015-shorthand-properties"),
      require("babel-plugin-transform-es2015-duplicate-keys"),
      [require("babel-plugin-transform-es2015-computed-properties"), { loose }],
      [require("babel-plugin-transform-es2015-for-of"), { loose }],
      require("babel-plugin-transform-es2015-sticky-regex"),
      require("babel-plugin-transform-es2015-unicode-regex"),
      require("babel-plugin-check-es2015-constants"),
      [require("babel-plugin-transform-es2015-spread"), { loose }],
      require("babel-plugin-transform-es2015-parameters"),
      [require("babel-plugin-transform-es2015-destructuring"), { loose }],
      require("babel-plugin-transform-es2015-block-scoping"),
      require("babel-plugin-transform-es2015-typeof-symbol"),
      modules === "commonjs" && [require("babel-plugin-transform-es2015-modules-commonjs"), { loose }],
      modules === "systemjs" && [require("babel-plugin-transform-es2015-modules-systemjs"), { loose }],
      modules === "amd" && [require("babel-plugin-transform-es2015-modules-amd"), { loose }],
      modules === "umd" && [require("babel-plugin-transform-es2015-modules-umd"), { loose }],
      [require("babel-plugin-transform-regenerator"), { async: false, asyncGenerators: false }]
    // filter out falsy values
    ].filter(Boolean)
  };
}

<commit_msg>Support 'spec' option on babel-preset-es2015 (#3671)<commit_after>/**
 * This file is a bit of a mess. If you're looking at it as a reference for how to write a preset,
 * I'd recommend looking only at `function preset(){}` and ignoring the rest, unless your new preset
 * really needs to work on babel-core < 6.13.x, which is unlikely.
 */

/**
 * This preset was originally an object, before function-based configurable presets were introduced.
 * For backward-compatibility with anything that may have been loading this preset and expecting
 * it to be a simple Babel config object, we maintain the old config here.
 */
module.exports = preset({});

// For backward compatibility with babel-core < v6.13.x, we use the 'buildPreset' property
// of the preset object for the preset creation function.
Object.defineProperty(module.exports, "buildPreset", {
  configurable: true,
  writable: true,
  // We make this non-enumerable so old versions of babel-core won't see it as an unknown property,
  // while allowing new versions to see it as a preset builder function.
  enumerable: false,
  value: preset,
});

function preset(context, opts) {
  const moduleTypes = ["commonjs", "amd", "umd", "systemjs"];
  let loose = false;
  let modules = "commonjs";
  let spec = false;

  if (opts !== undefined) {
    if (opts.loose !== undefined) loose = opts.loose;
    if (opts.modules !== undefined) modules = opts.modules;
    if (opts.spec !== undefined) spec = opts.spec;
  }

  if (typeof loose !== "boolean") throw new Error("Preset es2015 'loose' option must be a boolean.");
  if (typeof spec !== "boolean") throw new Error("Preset es2015 'spec' option must be a boolean.");
  if (modules !== false && moduleTypes.indexOf(modules) === -1) {
    throw new Error("Preset es2015 'modules' option must be 'false' to indicate no modules\n" +
      "or a module type which be be one of: 'commonjs' (default), 'amd', 'umd', 'systemjs'");
  }

  return {
    plugins: [
      [require("babel-plugin-transform-es2015-template-literals"), { loose, spec }],
      require("babel-plugin-transform-es2015-literals"),
      require("babel-plugin-transform-es2015-function-name"),
      [require("babel-plugin-transform-es2015-arrow-functions"), { spec }],
      require("babel-plugin-transform-es2015-block-scoped-functions"),
      [require("babel-plugin-transform-es2015-classes"), { loose }],
      require("babel-plugin-transform-es2015-object-super"),
      require("babel-plugin-transform-es2015-shorthand-properties"),
      require("babel-plugin-transform-es2015-duplicate-keys"),
      [require("babel-plugin-transform-es2015-computed-properties"), { loose }],
      [require("babel-plugin-transform-es2015-for-of"), { loose }],
      require("babel-plugin-transform-es2015-sticky-regex"),
      require("babel-plugin-transform-es2015-unicode-regex"),
      require("babel-plugin-check-es2015-constants"),
      [require("babel-plugin-transform-es2015-spread"), { loose }],
      require("babel-plugin-transform-es2015-parameters"),
      [require("babel-plugin-transform-es2015-destructuring"), { loose }],
      require("babel-plugin-transform-es2015-block-scoping"),
      require("babel-plugin-transform-es2015-typeof-symbol"),
      modules === "commonjs" && [require("babel-plugin-transform-es2015-modules-commonjs"), { loose }],
      modules === "systemjs" && [require("babel-plugin-transform-es2015-modules-systemjs"), { loose }],
      modules === "amd" && [require("babel-plugin-transform-es2015-modules-amd"), { loose }],
      modules === "umd" && [require("babel-plugin-transform-es2015-modules-umd"), { loose }],
      [require("babel-plugin-transform-regenerator"), { async: false, asyncGenerators: false }]
    // filter out falsy values
    ].filter(Boolean)
  };
}

<|endoftext|>


<commit_before>/*global config*/
import Reflux from 'reflux';
import InterProjectActions from '../actions/interProjectActions';
import InterProjectApi from '../data/InterProjectApi';

import BranchActions from '../actions/branchActions';

const InterProjectStore = Reflux.createStore({

  listenables: InterProjectActions,

  init() {
    this.interProjectBuild = {};
    this.interProjectBuildMappings = [];
    this.interProjectBuildMappingByRepoBuildId = [];
    this.upAndDownstreamModules = {};
  },

  onTriggerInterProjectBuild(params, state) {
    const {selectedModules, buildDownstreamModules, resetCache} = state;
    InterProjectApi.triggerInterProjectBuild(selectedModules, resetCache, (error, resp) => {
      if (error) {
        this.error = error;
        return this.triggerErrorUpdate();
      }

      BranchActions.loadBranchBuildHistory(params);
    });
  },

  onGetUpAndDownstreamModules(repoBuildId) {
    InterProjectApi.getUpAndDownstreamModules(repoBuildId, (resp) => {
      this.upAndDownstreamModules = resp;

      this.trigger({
        upAndDownstreamModules: this.upAndDownstreamModules
      });
    });
  }
});

export default InterProjectStore;
<commit_msg>remove unused class fields from the store as well<commit_after>/*global config*/
import Reflux from 'reflux';
import InterProjectActions from '../actions/interProjectActions';
import InterProjectApi from '../data/InterProjectApi';

import BranchActions from '../actions/branchActions';

const InterProjectStore = Reflux.createStore({

  listenables: InterProjectActions,

  init() {
    this.upAndDownstreamModules = {};
  },

  onTriggerInterProjectBuild(params, state) {
    const {selectedModules, buildDownstreamModules, resetCache} = state;
    InterProjectApi.triggerInterProjectBuild(selectedModules, resetCache, (error, resp) => {
      if (error) {
        this.error = error;
        return this.triggerErrorUpdate();
      }

      BranchActions.loadBranchBuildHistory(params);
    });
  },

  onGetUpAndDownstreamModules(repoBuildId) {
    InterProjectApi.getUpAndDownstreamModules(repoBuildId, (resp) => {
      this.upAndDownstreamModules = resp;

      this.trigger({
        upAndDownstreamModules: this.upAndDownstreamModules
      });
    });
  }
});

export default InterProjectStore;
<|endoftext|>


<commit_before>const { promisify } = require('util');
const fs = require('fs');
const path = require('path');
const symlink = promisify(fs.symlink);
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
const mkdirp = promisify(require('mkdirp'));
const chokidar = require('chokidar');
const chalk = require('chalk');
const globby = require('globby');
const ora = require('ora');
const sharp = require('sharp');
const SVGO = require('svgo');
const { spawnSync } = require('child_process');
const log = require('../utils/log');
const timer = require('../utils/timer');
const { getConfig } = require('../utils/config-store');
const { flattenArray } = require('../utils/general');
let config;

const {
  TRAVIS,
  TRAVIS_BRANCH,
  TRAVIS_PULL_REQUEST_BRANCH,
  TRAVIS_PULL_REQUEST,
} = process.env;

let branchName = 'detached-HEAD';
try {
  branchName = spawnSync('git', ['symbolic-ref', 'HEAD'], {
    encoding: 'utf8',
  })
    .stdout.replace('refs/heads/', '')
    .replace(/\//g, '-')
    .trim();
} catch (error) {
  process.exit(1);
}

if (TRAVIS === 'true') {
  if (TRAVIS_PULL_REQUEST === 'false') {
    branchName = TRAVIS_BRANCH;
  } else {
    branchName = TRAVIS_PULL_REQUEST_BRANCH;
  }
}

const svgo = new SVGO({
  plugins: [
    {
      removeViewBox: false,
    },
    {
      removeXMLNS: false,
    },
  ],
});

// full set of image sizes used by default unless being run on a feature-specific branch
let boltImageSizes = [
  50,
  100,
  200,
  320,
  480,
  640,
  800,
  1024,
  1366,
  1536,
  1920,
  2560,
  2880,
];

// don't resize images to all available options on feature-specific branches to speed up build times
// if (branchName.includes('feature') === true) {
//  boltImageSizes = [320, 640, 1024, 1920];
// }

function makeLocalPath(imagePath) {
  return `${path.join(config.wwwDir, imagePath)}`;
}

function makeWebPath(imagePath) {
  return `${path.relative(config.wwwDir, imagePath)}`;
}

async function writeImageManifest(imgManifest) {
  config = config || (await getConfig());

  await writeFile(
    path.join(config.dataDir, 'images.bolt.json'),
    JSON.stringify(imgManifest, null, '  '),
  );
}

async function processImage(file, set) {
  config = config || (await getConfig());

  if (config.verbosity > 3) {
    log.dim(`Processing image: ${file}`);
  }
  // If `set.base` is `images/` and `file` is `images/header/main.png`, then `fileId` is `header/main.png`
  const fileId = path.relative(set.base, file);
  const newPath = path.join(set.dist, fileId);
  const pathInfo = path.parse(newPath);
  // pathInfo.ext and pathInfo.name are ignored if pathInfo.base exists
  delete pathInfo.base;

  await mkdirp(pathInfo.dir);

  // we want to read the original file once, instead of reading for each size
  const originalFileBuffer = await readFile(file);
  // http://sharp.pixelplumbing.com/en/stable/api-input/#metadata
  const { width, height } = await sharp(originalFileBuffer).metadata();

  // We add `null` to beginning b/c we want the original file too
  // Filter the list to not include sizes bigger than our file
  const sizes = [null, ...boltImageSizes].filter(size => width > size);

  // looping through all sizes and resizing
  return Promise.all(
    sizes.map(async size => {
      const isOrig = size === null; // original file
      if (!isOrig) {
        // no need to resize these file extensions
        if (pathInfo.ext === '.svg' || pathInfo.ext === '.gif') {
          return;
        }
      }

      // Goes on end of filename
      const sizeSuffix = size ? `-${size}` : '';
      const thisPathInfo = Object.assign({}, pathInfo, {
        name: `${pathInfo.name}${sizeSuffix}`,
      });
      const newSizedPath = path.format(thisPathInfo);
      const newSizeWebPath = makeWebPath(newSizedPath);
      const newSizeLocalPath = makeLocalPath(newSizedPath);

      if (config.prod) {
        if (isOrig) {
          await sharp(originalFileBuffer)
            .jpeg({
              quality: 50,
              progressive: true,
              optimiseScans: true,
              force: false,
            })
            .png({
              progressive: true,
              force: false,
              compressionLevel: 9,
            })
            .toFile(newSizedPath);

          if (
            pathInfo.ext === '.jpeg' ||
            pathInfo.ext === '.jpg' ||
            pathInfo.ext === '.png'
          ) {
            await sharp(originalFileBuffer)
              .resize(size)
              .jpeg({
                quality: 50,
                progressive: true,
                optimiseScans: true,
                force: false,
              })
              .png({
                progressive: true,
                force: false,
                compressionLevel: 9,
              })
              .toFile(newSizedPath);
          } else if (pathInfo.ext === '.svg') {
            const result = await svgo.optimize(originalFileBuffer);
            const optimizedSVG = result.data;
            await writeFile(newSizeLocalPath, optimizedSVG);
          } else {
            await sharp(originalFileBuffer)
              .jpeg({
                quality: 50,
                progressive: true,
                optimiseScans: true,
                force: false,
              })
              .png({
                progressive: true,
                force: false,
                compressionLevel: 9,
              })
              .toFile(newSizedPath);
          }
        } else {
          // http://sharp.pixelplumbing.com/en/stable/
          if (
            pathInfo.ext === '.jpeg' ||
            pathInfo.ext === '.jpg' ||
            pathInfo.ext === '.png'
          ) {
            await sharp(originalFileBuffer)
              .resize(size)
              .jpeg({
                quality: 50,
                progressive: true,
                optimiseScans: true,
                force: false,
              })
              .png({
                progressive: true,
                force: false,
                compressionLevel: 9,
              })
              .toFile(newSizedPath);
          } else {
            await sharp(originalFileBuffer)
              .resize(size)
              .toFile(newSizedPath);
          }
        }
      } else {
        // Not prod, so let's be quick.
        // Symlinking works even if the original file is not served
        const symlinkPath = path.relative(thisPathInfo.dir, file);
        try {
          await symlink(symlinkPath, newSizedPath);
        } catch (error) {
          // If it's the error for symlink already exists, we don't care.
          if (error.code !== 'EEXIST') {
            log.errorAndExit(
              `Problem when attempting to symlink ${file} to ${newSizedPath}.`,
              error,
            );
          }
        }
      }

      if (!isOrig) {
        return {
          path: newSizeWebPath,
          size,
        };
      }
    }),
  ).then(resizedImagePaths => {
    // removes `undefined` & other non-truthy values (mainly original images & non processed file types like SVG or GIF)
    const sets = resizedImagePaths.filter(resizedImagePath => resizedImagePath);
    const imageMeta = {
      original: file,
      // width,
      // height,
      fileId,
      src: makeWebPath(newPath),
      sizePaths: sets,
      srcset: sets.map(set => `${set.path} ${set.size}w`).join(', '),
    };

    return imageMeta;
  });
}

async function processImages() {
  config = config || (await getConfig());

  if (!config.images) {
    return;
  }
  const startMessage = chalk.blue('Processing images...');
  const startTime = timer.start();
  let spinner;
  if (config.verbosity > 2) {
    console.log(startMessage);
  } else {
    spinner = ora(startMessage).start();
  }

  return Promise.all(
    config.images.sets.map(async set => {
      const imagePaths = await globby(path.join(set.base, set.glob));
      return Promise.all(
        imagePaths.map(imagePath => processImage(imagePath, set)),
      );
    }),
  ).then(async setsOfImageMetas => {
    // When it's all done
    const imageMetas = flattenArray(setsOfImageMetas);
    const imageManifest = {};
    imageMetas.forEach(imageMeta => {
      imageManifest[imageMeta.src] = imageMeta;
    });
    await writeImageManifest(imageManifest);

    const endMessage = chalk.green(
      `Processed images in ${timer.end(startTime)}`,
    );
    if (config.verbosity > 2) {
      console.log(endMessage);
    } else {
      spinner.succeed(endMessage);
    }
  });
}

module.exports = {
  processImages,
};
<commit_msg>chore: revert commenting out quicker image task config<commit_after>const { promisify } = require('util');
const fs = require('fs');
const path = require('path');
const symlink = promisify(fs.symlink);
const readFile = promisify(fs.readFile);
const writeFile = promisify(fs.writeFile);
const mkdirp = promisify(require('mkdirp'));
const chokidar = require('chokidar');
const chalk = require('chalk');
const globby = require('globby');
const ora = require('ora');
const sharp = require('sharp');
const SVGO = require('svgo');
const { spawnSync } = require('child_process');
const log = require('../utils/log');
const timer = require('../utils/timer');
const { getConfig } = require('../utils/config-store');
const { flattenArray } = require('../utils/general');
let config;

const {
  TRAVIS,
  TRAVIS_BRANCH,
  TRAVIS_PULL_REQUEST_BRANCH,
  TRAVIS_PULL_REQUEST,
} = process.env;

let branchName = 'detached-HEAD';
try {
  branchName = spawnSync('git', ['symbolic-ref', 'HEAD'], {
    encoding: 'utf8',
  })
    .stdout.replace('refs/heads/', '')
    .replace(/\//g, '-')
    .trim();
} catch (error) {
  process.exit(1);
}

if (TRAVIS === 'true') {
  if (TRAVIS_PULL_REQUEST === 'false') {
    branchName = TRAVIS_BRANCH;
  } else {
    branchName = TRAVIS_PULL_REQUEST_BRANCH;
  }
}

const svgo = new SVGO({
  plugins: [
    {
      removeViewBox: false,
    },
    {
      removeXMLNS: false,
    },
  ],
});

// full set of image sizes used by default unless being run on a feature-specific branch
let boltImageSizes = [
  50,
  100,
  200,
  320,
  480,
  640,
  800,
  1024,
  1366,
  1536,
  1920,
  2560,
  2880,
];

// don't resize images to all available options on feature-specific branches to speed up build times
if (branchName.includes('feature') === true) {
  boltImageSizes = [320, 640, 1024, 1920];
}

function makeLocalPath(imagePath) {
  return `${path.join(config.wwwDir, imagePath)}`;
}

function makeWebPath(imagePath) {
  return `${path.relative(config.wwwDir, imagePath)}`;
}

async function writeImageManifest(imgManifest) {
  config = config || (await getConfig());

  await writeFile(
    path.join(config.dataDir, 'images.bolt.json'),
    JSON.stringify(imgManifest, null, '  '),
  );
}

async function processImage(file, set) {
  config = config || (await getConfig());

  if (config.verbosity > 3) {
    log.dim(`Processing image: ${file}`);
  }
  // If `set.base` is `images/` and `file` is `images/header/main.png`, then `fileId` is `header/main.png`
  const fileId = path.relative(set.base, file);
  const newPath = path.join(set.dist, fileId);
  const pathInfo = path.parse(newPath);
  // pathInfo.ext and pathInfo.name are ignored if pathInfo.base exists
  delete pathInfo.base;

  await mkdirp(pathInfo.dir);

  // we want to read the original file once, instead of reading for each size
  const originalFileBuffer = await readFile(file);
  // http://sharp.pixelplumbing.com/en/stable/api-input/#metadata
  const { width, height } = await sharp(originalFileBuffer).metadata();

  // We add `null` to beginning b/c we want the original file too
  // Filter the list to not include sizes bigger than our file
  const sizes = [null, ...boltImageSizes].filter(size => width > size);

  // looping through all sizes and resizing
  return Promise.all(
    sizes.map(async size => {
      const isOrig = size === null; // original file
      if (!isOrig) {
        // no need to resize these file extensions
        if (pathInfo.ext === '.svg' || pathInfo.ext === '.gif') {
          return;
        }
      }

      // Goes on end of filename
      const sizeSuffix = size ? `-${size}` : '';
      const thisPathInfo = Object.assign({}, pathInfo, {
        name: `${pathInfo.name}${sizeSuffix}`,
      });
      const newSizedPath = path.format(thisPathInfo);
      const newSizeWebPath = makeWebPath(newSizedPath);
      const newSizeLocalPath = makeLocalPath(newSizedPath);

      if (config.prod) {
        if (isOrig) {
          await sharp(originalFileBuffer)
            .jpeg({
              quality: 50,
              progressive: true,
              optimiseScans: true,
              force: false,
            })
            .png({
              progressive: true,
              force: false,
              compressionLevel: 9,
            })
            .toFile(newSizedPath);

          if (
            pathInfo.ext === '.jpeg' ||
            pathInfo.ext === '.jpg' ||
            pathInfo.ext === '.png'
          ) {
            await sharp(originalFileBuffer)
              .resize(size)
              .jpeg({
                quality: 50,
                progressive: true,
                optimiseScans: true,
                force: false,
              })
              .png({
                progressive: true,
                force: false,
                compressionLevel: 9,
              })
              .toFile(newSizedPath);
          } else if (pathInfo.ext === '.svg') {
            const result = await svgo.optimize(originalFileBuffer);
            const optimizedSVG = result.data;
            await writeFile(newSizeLocalPath, optimizedSVG);
          } else {
            await sharp(originalFileBuffer)
              .jpeg({
                quality: 50,
                progressive: true,
                optimiseScans: true,
                force: false,
              })
              .png({
                progressive: true,
                force: false,
                compressionLevel: 9,
              })
              .toFile(newSizedPath);
          }
        } else {
          // http://sharp.pixelplumbing.com/en/stable/
          if (
            pathInfo.ext === '.jpeg' ||
            pathInfo.ext === '.jpg' ||
            pathInfo.ext === '.png'
          ) {
            await sharp(originalFileBuffer)
              .resize(size)
              .jpeg({
                quality: 50,
                progressive: true,
                optimiseScans: true,
                force: false,
              })
              .png({
                progressive: true,
                force: false,
                compressionLevel: 9,
              })
              .toFile(newSizedPath);
          } else {
            await sharp(originalFileBuffer)
              .resize(size)
              .toFile(newSizedPath);
          }
        }
      } else {
        // Not prod, so let's be quick.
        // Symlinking works even if the original file is not served
        const symlinkPath = path.relative(thisPathInfo.dir, file);
        try {
          await symlink(symlinkPath, newSizedPath);
        } catch (error) {
          // If it's the error for symlink already exists, we don't care.
          if (error.code !== 'EEXIST') {
            log.errorAndExit(
              `Problem when attempting to symlink ${file} to ${newSizedPath}.`,
              error,
            );
          }
        }
      }

      if (!isOrig) {
        return {
          path: newSizeWebPath,
          size,
        };
      }
    }),
  ).then(resizedImagePaths => {
    // removes `undefined` & other non-truthy values (mainly original images & non processed file types like SVG or GIF)
    const sets = resizedImagePaths.filter(resizedImagePath => resizedImagePath);
    const imageMeta = {
      original: file,
      // width,
      // height,
      fileId,
      src: makeWebPath(newPath),
      sizePaths: sets,
      srcset: sets.map(set => `${set.path} ${set.size}w`).join(', '),
    };

    return imageMeta;
  });
}

async function processImages() {
  config = config || (await getConfig());

  if (!config.images) {
    return;
  }
  const startMessage = chalk.blue('Processing images...');
  const startTime = timer.start();
  let spinner;
  if (config.verbosity > 2) {
    console.log(startMessage);
  } else {
    spinner = ora(startMessage).start();
  }

  return Promise.all(
    config.images.sets.map(async set => {
      const imagePaths = await globby(path.join(set.base, set.glob));
      return Promise.all(
        imagePaths.map(imagePath => processImage(imagePath, set)),
      );
    }),
  ).then(async setsOfImageMetas => {
    // When it's all done
    const imageMetas = flattenArray(setsOfImageMetas);
    const imageManifest = {};
    imageMetas.forEach(imageMeta => {
      imageManifest[imageMeta.src] = imageMeta;
    });
    await writeImageManifest(imageManifest);

    const endMessage = chalk.green(
      `Processed images in ${timer.end(startTime)}`,
    );
    if (config.verbosity > 2) {
      console.log(endMessage);
    } else {
      spinner.succeed(endMessage);
    }
  });
}

module.exports = {
  processImages,
};
<|endoftext|>


<commit_before>angular.module('manufacturingWeb')
    .controller('history', [
        '$scope', '$http', function($scope, $http) {
            $scope.parameterUpdate = function() {
                //$scope.startDate

                var getConfig = {
                    url: "http://localhost:16683/api/history", //todo: unhardcode this
                    method: "GET",
                    params: {}
                }

                if ($scope.startDate) {
                    getConfig.params.startTime = $scope.startDate.toISOString();
                }
                if ($scope.endDate) {
                    getConfig.params.endTime = $scope.endDate.toISOString();
                }

                $http(getConfig).success(function(historyData) {
                    $scope.history = historyData;
                });
            }
        }
    ]);<commit_msg>Removed URL hardcoding<commit_after>angular.module('manufacturingWeb')
    .controller('history', [
        '$scope', '$http', 'config', function($scope, $http, config) {
            $scope.parameterUpdate = function() {
                //$scope.startDate

                var getConfig = {
                    url: config.apiUrl + "/api/history",
                    method: "GET",
                    params: {}
                };

                if ($scope.startDate) {
                    getConfig.params.startTime = $scope.startDate.toISOString();
                }
                if ($scope.endDate) {
                    getConfig.params.endTime = $scope.endDate.toISOString();
                }

                $http(getConfig).success(function(historyData) {
                    $scope.history = historyData;
                });
            }
        }
    ]);<|endoftext|>


<commit_before>/**
  The `Session` class holds the current access token and other session data. There will always be a
  session regardless of whether a user is currently authenticated or not. That (singleton) instance
  of this class is automatically injected into all models, controller, routes and views so you should
  never instantiate this class directly but always use the auto-injected instance.

  @class Session
  @namespace Ember.SimpleAuth
  @extends Ember.Object
  @constructor
*/
Ember.SimpleAuth.Session = Ember.Object.extend({
  init: function() {
    this._super();
    this.setProperties({
      authToken:       sessionStorage.authToken,
      refreshToken:    sessionStorage.refreshToken,
      authTokenExpiry: sessionStorage.authTokenExpiry
    });
    this.handleAuthTokenRefresh();
  },

  /**
    Sets up the session from a plain JavaScript object. This does not create a new isntance but sets up
    the instance with the data that is passed.

    @method setup
    @param {Object} data The data to set the session up with
      @param {String} data.access_token The access token that will be included in the `Authorization` header
      @param {String} [data.refresh_token] An optional refresh token that will be used for obtaining fresh tokens
      @param {String} [data.expires_in] An optional expiry for the access_token in seconds; if both expires_in and refresh_token are set,
        Ember.SimpleAuth will automatically refresh access tokens before they expire

    @example
      this.get('session').setup({
        access_token:  'the secret token!',
        refresh_token: 'a secret refresh token!',
        expires_in:    3600 // 1 minute
      })
  */
  setup: function(data) {
    data = data || {};
    this.setProperties({
      authToken:       data.access_token,
      refreshToken:    (data.refresh_token || this.get('refreshToken')),
      authTokenExpiry: (data.expires_in > 0 ? data.expires_in * 1000 : this.get('authTokenExpiry')) || 0
    });
  },

  /**
    Destroys the session by setting all properties to undefined (see {{#crossLink "Ember.SimpleAuth.Session/setup:method"}}Session.setup{{/crossLink}}). This also deletes any
    saved data from the sessionStorage and effectively logs the current user out.

    @method destroy
  */
  destroy: function() {
    this.setProperties({
      authToken:       undefined,
      refreshToken:    undefined,
      authTokenExpiry: undefined
    });
  },

  /**
    Returns whether a user is currently authenticated.

    @method isAuthenticated
    @return {Boolean} true if a user is authenticated, false otherwise
  */
  isAuthenticated: Ember.computed('authToken', function() {
    return !Ember.isEmpty(this.get('authToken'));
  }),

  /**
    @method handlePropertyChange
    @private
  */
  handlePropertyChange: function(property) {
    var value = this.get(property);
    if (Ember.isEmpty(value)) {
      delete sessionStorage[property];
    } else {
      sessionStorage[property] = value;
    }
  },

  /**
    @method authTokenObserver
    @private
  */
  authTokenObserver: Ember.observer(function() {
    this.handlePropertyChange('authToken');
  }, 'authToken'),

  /**
    @method refreshTokenObserver
    @private
  */
  refreshTokenObserver: Ember.observer(function() {
    this.handlePropertyChange('refreshToken');
    this.handleAuthTokenRefresh();
  }, 'refreshToken'),

  /**
    @method authTokenExpiryObserver
    @private
  */
  authTokenExpiryObserver: Ember.observer(function() {
    this.handlePropertyChange('authTokenExpiry');
    this.handleAuthTokenRefresh();
  }, 'authTokenExpiry'),

  /**
    @method handleAuthTokenRefresh
    @private
  */
  handleAuthTokenRefresh: function() {
    if (Ember.SimpleAuth.autoRefreshToken) {
      Ember.run.cancel(this.get('refreshAuthTokenTimeout'));
      this.set('refreshAuthTokenTimeout', undefined);
      var waitTime = this.get('authTokenExpiry') - 5000;
      if (!Ember.isEmpty(this.get('refreshToken')) && waitTime > 0) {
        this.set('refreshAuthTokenTimeout', Ember.run.later(this, function() {
          var self = this;
          Ember.$.ajax(Ember.SimpleAuth.serverTokenEndpoint, {
            type:        'POST',
            data:        'grant_type=refresh_token&refresh_token=' + this.get('refreshToken'),
            contentType: 'application/x-www-form-urlencoded'
          }).then(function(response) {
            self.setup(response);
            self.handleAuthTokenRefresh();
          });
        }, waitTime));
      }
    }
  }
});
<commit_msg>fixed example<commit_after>/**
  The `Session` class holds the current access token and other session data. There will always be a
  session regardless of whether a user is currently authenticated or not. That (singleton) instance
  of this class is automatically injected into all models, controller, routes and views so you should
  never instantiate this class directly but always use the auto-injected instance.

  @class Session
  @namespace Ember.SimpleAuth
  @extends Ember.Object
  @constructor
*/
Ember.SimpleAuth.Session = Ember.Object.extend({
  init: function() {
    this._super();
    this.setProperties({
      authToken:       sessionStorage.authToken,
      refreshToken:    sessionStorage.refreshToken,
      authTokenExpiry: sessionStorage.authTokenExpiry
    });
    this.handleAuthTokenRefresh();
  },

  /**
    Sets up the session from a plain JavaScript object. This does not create a new isntance but sets up
    the instance with the data that is passed.

    @method setup
    @param {Object} data The data to set the session up with
      @param {String} data.access_token The access token that will be included in the `Authorization` header
      @param {String} [data.refresh_token] An optional refresh token that will be used for obtaining fresh tokens
      @param {String} [data.expires_in] An optional expiry for the access_token in seconds; if both expires_in and refresh_token are set,
        Ember.SimpleAuth will automatically refresh access tokens before they expire

    @example
      ```javascript
      this.get('session').setup({
        access_token:  'the secret token!',
        refresh_token: 'a secret refresh token!',
        expires_in:    3600 // 1 minute
      })
      ```
  */
  setup: function(data) {
    data = data || {};
    this.setProperties({
      authToken:       data.access_token,
      refreshToken:    (data.refresh_token || this.get('refreshToken')),
      authTokenExpiry: (data.expires_in > 0 ? data.expires_in * 1000 : this.get('authTokenExpiry')) || 0
    });
  },

  /**
    Destroys the session by setting all properties to undefined (see {{#crossLink "Ember.SimpleAuth.Session/setup:method"}}Session.setup{{/crossLink}}). This also deletes any
    saved data from the sessionStorage and effectively logs the current user out.

    @method destroy
  */
  destroy: function() {
    this.setProperties({
      authToken:       undefined,
      refreshToken:    undefined,
      authTokenExpiry: undefined
    });
  },

  /**
    Returns whether a user is currently authenticated.

    @method isAuthenticated
    @return {Boolean} true if a user is authenticated, false otherwise
  */
  isAuthenticated: Ember.computed('authToken', function() {
    return !Ember.isEmpty(this.get('authToken'));
  }),

  /**
    @method handlePropertyChange
    @private
  */
  handlePropertyChange: function(property) {
    var value = this.get(property);
    if (Ember.isEmpty(value)) {
      delete sessionStorage[property];
    } else {
      sessionStorage[property] = value;
    }
  },

  /**
    @method authTokenObserver
    @private
  */
  authTokenObserver: Ember.observer(function() {
    this.handlePropertyChange('authToken');
  }, 'authToken'),

  /**
    @method refreshTokenObserver
    @private
  */
  refreshTokenObserver: Ember.observer(function() {
    this.handlePropertyChange('refreshToken');
    this.handleAuthTokenRefresh();
  }, 'refreshToken'),

  /**
    @method authTokenExpiryObserver
    @private
  */
  authTokenExpiryObserver: Ember.observer(function() {
    this.handlePropertyChange('authTokenExpiry');
    this.handleAuthTokenRefresh();
  }, 'authTokenExpiry'),

  /**
    @method handleAuthTokenRefresh
    @private
  */
  handleAuthTokenRefresh: function() {
    if (Ember.SimpleAuth.autoRefreshToken) {
      Ember.run.cancel(this.get('refreshAuthTokenTimeout'));
      this.set('refreshAuthTokenTimeout', undefined);
      var waitTime = this.get('authTokenExpiry') - 5000;
      if (!Ember.isEmpty(this.get('refreshToken')) && waitTime > 0) {
        this.set('refreshAuthTokenTimeout', Ember.run.later(this, function() {
          var self = this;
          Ember.$.ajax(Ember.SimpleAuth.serverTokenEndpoint, {
            type:        'POST',
            data:        'grant_type=refresh_token&refresh_token=' + this.get('refreshToken'),
            contentType: 'application/x-www-form-urlencoded'
          }).then(function(response) {
            self.setup(response);
            self.handleAuthTokenRefresh();
          });
        }, waitTime));
      }
    }
  }
});
<|endoftext|>