<commit_before>var _ = require('underscore');
var BaseWidget = require('./base');
var debug = require('debug')('windshaft:widget:aggregation');

const filteredQueryTpl = ctx => `
    filtered_source AS (
        SELECT *
        FROM (${ctx._query}) _cdb_filtered_source
        ${ctx._aggregationColumn && ctx._isFloatColumn ? `
        WHERE
            ${ctx._aggregationColumn} != 'infinity'::float
        AND
            ${ctx._aggregationColumn} != '-infinity'::float
        AND
            ${ctx._aggregationColumn} != 'NaN'::float` :
        ''
        }
    )
`;

const summaryQueryTpl = ctx => `
    summary AS (
        SELECT
            count(1) AS count,
            sum(CASE WHEN ${ctx._column} IS NULL THEN 1 ELSE 0 END) AS nulls_count
            ${ctx._isFloatColumn ? `,
            sum(
                CASE
                    WHEN ${ctx._aggregationColumn} = 'infinity'::float OR ${ctx._aggregationColumn} = '-infinity'::float
                    THEN 1
                    ELSE 0
                    END
            ) AS infinities_count,
            sum(CASE WHEN ${ctx._aggregationColumn} = 'NaN'::float THEN 1 ELSE 0 END) AS nans_count` :
            ''
            }
        FROM (${ctx._query}) _cdb_aggregation_nulls
    )
`;

const rankedCategoriesQueryTpl = ctx => `
    categories AS(
        SELECT
            ${ctx._column} AS category,
            ${ctx._aggregation} AS value,
            row_number() OVER (ORDER BY ${ctx._aggregation} desc) as rank
        FROM filtered_source
        ${ctx._aggregationColumn !== null ? `WHERE ${ctx._aggregationColumn} IS NOT NULL` : ''}
        GROUP BY ${ctx._column}
        ORDER BY 2 DESC
    )
`;

const categoriesSummaryMinMaxQueryTpl = () => `
    categories_summary_min_max AS(
        SELECT
            max(value) max_val,
            min(value) min_val
        FROM categories
    )
`;

const categoriesSummaryCountQueryTpl = ctx => `
    categories_summary_count AS(
        SELECT count(1) AS categories_count
        FROM (
            SELECT ${ctx._column} AS category
            FROM (${ctx._query}) _cdb_categories
            GROUP BY ${ctx._column}
        ) _cdb_categories_count
    )
`;

const specialNumericValuesColumns = () => `, nans_count, infinities_count`;

const rankedAggregationQueryTpl = ctx => `
    SELECT
        CAST(category AS text),
        value,
        false as agg,
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
        FROM categories, summary, categories_summary_min_max, categories_summary_count
        WHERE rank < ${ctx._limit}
    UNION ALL
    SELECT
        'Other' category,
        ${ctx._aggregationFn}(value) as value,
        true as agg,
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
        FROM categories, summary, categories_summary_min_max, categories_summary_count
        WHERE rank >= ${ctx._limit}
    GROUP BY
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
`;

const aggregationQueryTpl = ctx => `
    SELECT
        CAST(${ctx._column} AS text) AS category,
        ${ctx._aggregation} AS value,
        false as agg,
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
    FROM (${ctx._query}) _cdb_aggregation_all, summary, categories_summary_min_max, categories_summary_count
    GROUP BY
        category,
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
    ORDER BY value DESC
`;

var CATEGORIES_LIMIT = 6;

var VALID_OPERATIONS = {
    count: [],
    sum: ['aggregationColumn'],
    avg: ['aggregationColumn'],
    min: ['aggregationColumn'],
    max: ['aggregationColumn']
};

var TYPE = 'aggregation';

/**
 {
     type: 'aggregation',
     options: {
         column: 'name',
         aggregation: 'count' // it could be, e.g., sum if column is numeric
     }
 }
 */
function Aggregation(query, options, queries) {
    if (!_.isString(options.column)) {
        throw new Error('Aggregation expects `column` in widget options');
    }

    if (!_.isString(options.aggregation)) {
        throw new Error('Aggregation expects `aggregation` operation in widget options');
    }

    if (!VALID_OPERATIONS[options.aggregation]) {
        throw new Error("Aggregation does not support '" + options.aggregation + "' operation");
    }

    var requiredOptions = VALID_OPERATIONS[options.aggregation];
    var missingOptions = _.difference(requiredOptions, Object.keys(options));
    if (missingOptions.length > 0) {
        throw new Error(
            "Aggregation '" + options.aggregation + "' is missing some options: " + missingOptions.join(',')
        );
    }

    BaseWidget.apply(this);

    this.query = query;
    this.queries = queries;
    this.column = options.column;
    this.aggregation = options.aggregation;
    this.aggregationColumn = options.aggregationColumn;
    this._isFloatColumn = null;
}

Aggregation.prototype = new BaseWidget();
Aggregation.prototype.constructor = Aggregation;

module.exports = Aggregation;

Aggregation.prototype.sql = function(psql, override, callback) {
    var self = this;

    if (!callback) {
        callback = override;
        override = {};
    }

    if (this.aggregationColumn && this._isFloatColumn === null) {
        this._isFloatColumn = false;
        this.getColumnType(psql, this.aggregationColumn, this.queries.no_filters, function (err, type) {
            if (!err && !!type) {
                self._isFloatColumn = type.float;
            }
            self.sql(psql, override, callback);
        });
        return null;
    }

    var _query = this.query;

    var aggregationSql;

    if (!!override.ownFilter) {
        aggregationSql = [
            this.getCategoriesCTESql(
                _query,
                this.column,
                this.aggregation,
                this.aggregationColumn,
                this._isFloatColumn
            ),
            aggregationQueryTpl({
                _isFloatColumn: this._isFloatColumn,
                _query: _query,
                _column: this.column,
                _aggregation: this.getAggregationSql(),
                _limit: CATEGORIES_LIMIT
            })
        ].join('\n');
    } else {
        aggregationSql = [
            this.getCategoriesCTESql(
                _query,
                this.column,
                this.aggregation,
                this.aggregationColumn,
                this._isFloatColumn
            ),
            rankedAggregationQueryTpl({
                _isFloatColumn: this._isFloatColumn,
                _query: _query,
                _column: this.column,
                _aggregationFn: this.aggregation !== 'count' ? this.aggregation : 'sum',
                _limit: CATEGORIES_LIMIT
            })
        ].join('\n');
    }

    debug(aggregationSql);

    return callback(null, aggregationSql);
};

Aggregation.prototype.getCategoriesCTESql = function(query, column, aggregation, aggregationColumn, isFloatColumn) {
    return [
        "WITH",
        [
            filteredQueryTpl({
                _isFloatColumn: isFloatColumn,
                _query: this.query,
                _column: this.column,
                _aggregationColumn: aggregation !== 'count' ? aggregationColumn : null
            }),
            summaryQueryTpl({
                _isFloatColumn: isFloatColumn,
                _query: query,
                _column: column,
                _aggregationColumn: aggregation !== 'count' ? aggregationColumn : null
            }),
            rankedCategoriesQueryTpl({
                _query: query,
                _column: column,
                _aggregation: this.getAggregationSql(),
                _aggregationColumn: aggregation !== 'count' ? aggregationColumn : null
            }),
            categoriesSummaryMinMaxQueryTpl({
                _query: query,
                _column: column
            }),
            categoriesSummaryCountQueryTpl({
                _query: query,
                _column: column
            })
        ].join(',\n')
    ].join('\n');
};

const aggregationFnQueryTpl = ctx => `${ctx._aggregationFn}(${ctx._aggregationColumn})`;

Aggregation.prototype.getAggregationSql = function() {
    return aggregationFnQueryTpl({
        _aggregationFn: this.aggregation,
        _aggregationColumn: this.aggregationColumn || 1
    });
};

Aggregation.prototype.format = function(result) {
    var categories = [];
    var count = 0;
    var nulls = 0;
    var nans = 0;
    var infinities = 0;
    var minValue = 0;
    var maxValue = 0;
    var categoriesCount = 0;

    if (result.rows.length) {
        var firstRow = result.rows[0];
        count = firstRow.count;
        nulls = firstRow.nulls_count;
        nans = firstRow.nans_count;
        infinities = firstRow.infinities_count;
        minValue = firstRow.min_val;
        maxValue = firstRow.max_val;
        categoriesCount = firstRow.categories_count;

        result.rows.forEach(function(row) {
            categories.push(_.omit(row, 'count', 'nulls_count', 'min_val',
                'max_val', 'categories_count', 'nans_count', 'infinities_count'));
        });
    }

    return {
        aggregation: this.aggregation,
        count: count,
        nulls: nulls,
        nans: nans,
        infinities: infinities,
        min: minValue,
        max: maxValue,
        categoriesCount: categoriesCount,
        categories: categories
    };
};

const filterCategoriesQueryTpl = ctx => `
    SELECT
        ${ctx._column} AS category,
        ${ctx._value} AS value
    FROM (${ctx._query}) _cdb_aggregation_search
    WHERE CAST(${ctx._column} as text) ILIKE ${ctx._userQuery}
    GROUP BY ${ctx._column}
`;

const searchQueryTpl = ctx => `
    WITH
    search_unfiltered AS (
        ${ctx._searchUnfiltered}
    ),
    search_filtered AS (
        ${ctx._searchFiltered}
    ),
    search_union AS (
        SELECT * FROM search_unfiltered
        UNION ALL
        SELECT * FROM search_filtered
    )
    SELECT category, sum(value) AS value
    FROM search_union
    GROUP BY category
    ORDER BY value desc
`;

Aggregation.prototype.search = function(psql, userQuery, callback) {
    var self = this;

    var _userQuery = psql.escapeLiteral('%' + userQuery + '%');
    var _value = this.aggregation !== 'count' && this.aggregationColumn ?
        this.aggregation + '(' + this.aggregationColumn + ')' : 'count(1)';

    // TODO unfiltered will be wrong as filters are already applied at this point
    var query = searchQueryTpl({
        _searchUnfiltered: filterCategoriesQueryTpl({
            _query: this.query,
            _column: this.column,
            _value: '0',
            _userQuery: _userQuery
        }),
        _searchFiltered: filterCategoriesQueryTpl({
            _query: this.query,
            _column: this.column,
            _value: _value,
            _userQuery: _userQuery
        })
    });

    psql.query(query, function(err, result) {
        if (err) {
            return callback(err, result);
        }

        return callback(null, {type: self.getType(), categories: result.rows });
    }, true); // use read-only transaction
};

Aggregation.prototype.getType = function() {
    return TYPE;
};

Aggregation.prototype.toString = function() {
    return JSON.stringify({
        _type: TYPE,
        _query: this.query,
        _column: this.column,
        _aggregation: this.aggregation
    });
};
<commit_msg>Declare constants with const keyword<commit_after>var _ = require('underscore');
var BaseWidget = require('./base');
var debug = require('debug')('windshaft:widget:aggregation');

const filteredQueryTpl = ctx => `
    filtered_source AS (
        SELECT *
        FROM (${ctx._query}) _cdb_filtered_source
        ${ctx._aggregationColumn && ctx._isFloatColumn ? `
        WHERE
            ${ctx._aggregationColumn} != 'infinity'::float
        AND
            ${ctx._aggregationColumn} != '-infinity'::float
        AND
            ${ctx._aggregationColumn} != 'NaN'::float` :
        ''
        }
    )
`;

const summaryQueryTpl = ctx => `
    summary AS (
        SELECT
            count(1) AS count,
            sum(CASE WHEN ${ctx._column} IS NULL THEN 1 ELSE 0 END) AS nulls_count
            ${ctx._isFloatColumn ? `,
            sum(
                CASE
                    WHEN ${ctx._aggregationColumn} = 'infinity'::float OR ${ctx._aggregationColumn} = '-infinity'::float
                    THEN 1
                    ELSE 0
                    END
            ) AS infinities_count,
            sum(CASE WHEN ${ctx._aggregationColumn} = 'NaN'::float THEN 1 ELSE 0 END) AS nans_count` :
            ''
            }
        FROM (${ctx._query}) _cdb_aggregation_nulls
    )
`;

const rankedCategoriesQueryTpl = ctx => `
    categories AS(
        SELECT
            ${ctx._column} AS category,
            ${ctx._aggregation} AS value,
            row_number() OVER (ORDER BY ${ctx._aggregation} desc) as rank
        FROM filtered_source
        ${ctx._aggregationColumn !== null ? `WHERE ${ctx._aggregationColumn} IS NOT NULL` : ''}
        GROUP BY ${ctx._column}
        ORDER BY 2 DESC
    )
`;

const categoriesSummaryMinMaxQueryTpl = () => `
    categories_summary_min_max AS(
        SELECT
            max(value) max_val,
            min(value) min_val
        FROM categories
    )
`;

const categoriesSummaryCountQueryTpl = ctx => `
    categories_summary_count AS(
        SELECT count(1) AS categories_count
        FROM (
            SELECT ${ctx._column} AS category
            FROM (${ctx._query}) _cdb_categories
            GROUP BY ${ctx._column}
        ) _cdb_categories_count
    )
`;

const specialNumericValuesColumns = () => `, nans_count, infinities_count`;

const rankedAggregationQueryTpl = ctx => `
    SELECT
        CAST(category AS text),
        value,
        false as agg,
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
        FROM categories, summary, categories_summary_min_max, categories_summary_count
        WHERE rank < ${ctx._limit}
    UNION ALL
    SELECT
        'Other' category,
        ${ctx._aggregationFn}(value) as value,
        true as agg,
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
        FROM categories, summary, categories_summary_min_max, categories_summary_count
        WHERE rank >= ${ctx._limit}
    GROUP BY
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
`;

const aggregationQueryTpl = ctx => `
    SELECT
        CAST(${ctx._column} AS text) AS category,
        ${ctx._aggregation} AS value,
        false as agg,
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
    FROM (${ctx._query}) _cdb_aggregation_all, summary, categories_summary_min_max, categories_summary_count
    GROUP BY
        category,
        nulls_count,
        min_val,
        max_val,
        count,
        categories_count
        ${ctx._isFloatColumn ? `${specialNumericValuesColumns(ctx)}` : '' }
    ORDER BY value DESC
`;

const CATEGORIES_LIMIT = 6;

const VALID_OPERATIONS = {
    count: [],
    sum: ['aggregationColumn'],
    avg: ['aggregationColumn'],
    min: ['aggregationColumn'],
    max: ['aggregationColumn']
};

const TYPE = 'aggregation';

/**
 {
     type: 'aggregation',
     options: {
         column: 'name',
         aggregation: 'count' // it could be, e.g., sum if column is numeric
     }
 }
 */
function Aggregation(query, options, queries) {
    if (!_.isString(options.column)) {
        throw new Error('Aggregation expects `column` in widget options');
    }

    if (!_.isString(options.aggregation)) {
        throw new Error('Aggregation expects `aggregation` operation in widget options');
    }

    if (!VALID_OPERATIONS[options.aggregation]) {
        throw new Error("Aggregation does not support '" + options.aggregation + "' operation");
    }

    var requiredOptions = VALID_OPERATIONS[options.aggregation];
    var missingOptions = _.difference(requiredOptions, Object.keys(options));
    if (missingOptions.length > 0) {
        throw new Error(
            "Aggregation '" + options.aggregation + "' is missing some options: " + missingOptions.join(',')
        );
    }

    BaseWidget.apply(this);

    this.query = query;
    this.queries = queries;
    this.column = options.column;
    this.aggregation = options.aggregation;
    this.aggregationColumn = options.aggregationColumn;
    this._isFloatColumn = null;
}

Aggregation.prototype = new BaseWidget();
Aggregation.prototype.constructor = Aggregation;

module.exports = Aggregation;

Aggregation.prototype.sql = function(psql, override, callback) {
    var self = this;

    if (!callback) {
        callback = override;
        override = {};
    }

    if (this.aggregationColumn && this._isFloatColumn === null) {
        this._isFloatColumn = false;
        this.getColumnType(psql, this.aggregationColumn, this.queries.no_filters, function (err, type) {
            if (!err && !!type) {
                self._isFloatColumn = type.float;
            }
            self.sql(psql, override, callback);
        });
        return null;
    }

    var _query = this.query;

    var aggregationSql;

    if (!!override.ownFilter) {
        aggregationSql = [
            this.getCategoriesCTESql(
                _query,
                this.column,
                this.aggregation,
                this.aggregationColumn,
                this._isFloatColumn
            ),
            aggregationQueryTpl({
                _isFloatColumn: this._isFloatColumn,
                _query: _query,
                _column: this.column,
                _aggregation: this.getAggregationSql(),
                _limit: CATEGORIES_LIMIT
            })
        ].join('\n');
    } else {
        aggregationSql = [
            this.getCategoriesCTESql(
                _query,
                this.column,
                this.aggregation,
                this.aggregationColumn,
                this._isFloatColumn
            ),
            rankedAggregationQueryTpl({
                _isFloatColumn: this._isFloatColumn,
                _query: _query,
                _column: this.column,
                _aggregationFn: this.aggregation !== 'count' ? this.aggregation : 'sum',
                _limit: CATEGORIES_LIMIT
            })
        ].join('\n');
    }

    debug(aggregationSql);

    return callback(null, aggregationSql);
};

Aggregation.prototype.getCategoriesCTESql = function(query, column, aggregation, aggregationColumn, isFloatColumn) {
    return [
        "WITH",
        [
            filteredQueryTpl({
                _isFloatColumn: isFloatColumn,
                _query: this.query,
                _column: this.column,
                _aggregationColumn: aggregation !== 'count' ? aggregationColumn : null
            }),
            summaryQueryTpl({
                _isFloatColumn: isFloatColumn,
                _query: query,
                _column: column,
                _aggregationColumn: aggregation !== 'count' ? aggregationColumn : null
            }),
            rankedCategoriesQueryTpl({
                _query: query,
                _column: column,
                _aggregation: this.getAggregationSql(),
                _aggregationColumn: aggregation !== 'count' ? aggregationColumn : null
            }),
            categoriesSummaryMinMaxQueryTpl({
                _query: query,
                _column: column
            }),
            categoriesSummaryCountQueryTpl({
                _query: query,
                _column: column
            })
        ].join(',\n')
    ].join('\n');
};

const aggregationFnQueryTpl = ctx => `${ctx._aggregationFn}(${ctx._aggregationColumn})`;

Aggregation.prototype.getAggregationSql = function() {
    return aggregationFnQueryTpl({
        _aggregationFn: this.aggregation,
        _aggregationColumn: this.aggregationColumn || 1
    });
};

Aggregation.prototype.format = function(result) {
    var categories = [];
    var count = 0;
    var nulls = 0;
    var nans = 0;
    var infinities = 0;
    var minValue = 0;
    var maxValue = 0;
    var categoriesCount = 0;

    if (result.rows.length) {
        var firstRow = result.rows[0];
        count = firstRow.count;
        nulls = firstRow.nulls_count;
        nans = firstRow.nans_count;
        infinities = firstRow.infinities_count;
        minValue = firstRow.min_val;
        maxValue = firstRow.max_val;
        categoriesCount = firstRow.categories_count;

        result.rows.forEach(function(row) {
            categories.push(_.omit(row, 'count', 'nulls_count', 'min_val',
                'max_val', 'categories_count', 'nans_count', 'infinities_count'));
        });
    }

    return {
        aggregation: this.aggregation,
        count: count,
        nulls: nulls,
        nans: nans,
        infinities: infinities,
        min: minValue,
        max: maxValue,
        categoriesCount: categoriesCount,
        categories: categories
    };
};

const filterCategoriesQueryTpl = ctx => `
    SELECT
        ${ctx._column} AS category,
        ${ctx._value} AS value
    FROM (${ctx._query}) _cdb_aggregation_search
    WHERE CAST(${ctx._column} as text) ILIKE ${ctx._userQuery}
    GROUP BY ${ctx._column}
`;

const searchQueryTpl = ctx => `
    WITH
    search_unfiltered AS (
        ${ctx._searchUnfiltered}
    ),
    search_filtered AS (
        ${ctx._searchFiltered}
    ),
    search_union AS (
        SELECT * FROM search_unfiltered
        UNION ALL
        SELECT * FROM search_filtered
    )
    SELECT category, sum(value) AS value
    FROM search_union
    GROUP BY category
    ORDER BY value desc
`;

Aggregation.prototype.search = function(psql, userQuery, callback) {
    var self = this;

    var _userQuery = psql.escapeLiteral('%' + userQuery + '%');
    var _value = this.aggregation !== 'count' && this.aggregationColumn ?
        this.aggregation + '(' + this.aggregationColumn + ')' : 'count(1)';

    // TODO unfiltered will be wrong as filters are already applied at this point
    var query = searchQueryTpl({
        _searchUnfiltered: filterCategoriesQueryTpl({
            _query: this.query,
            _column: this.column,
            _value: '0',
            _userQuery: _userQuery
        }),
        _searchFiltered: filterCategoriesQueryTpl({
            _query: this.query,
            _column: this.column,
            _value: _value,
            _userQuery: _userQuery
        })
    });

    psql.query(query, function(err, result) {
        if (err) {
            return callback(err, result);
        }

        return callback(null, {type: self.getType(), categories: result.rows });
    }, true); // use read-only transaction
};

Aggregation.prototype.getType = function() {
    return TYPE;
};

Aggregation.prototype.toString = function() {
    return JSON.stringify({
        _type: TYPE,
        _query: this.query,
        _column: this.column,
        _aggregation: this.aggregation
    });
};
<|endoftext|>


<commit_before>// Copyright 2014-2015, University of Colorado Boulder

/**
 * Model for the 'Energy Systems' screen of the Energy Forms And Changes simulation.
 *
 * @author John Blanco
 * @author Jesse Greenberg
 * @author Andrew Adare
 */
define( function( require ) {
  'use strict';

  // Modules
  var BeakerHeater = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/BeakerHeater' );
  var Biker = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Biker' );
  var Belt = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Belt' );
  var energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );
  var EnergySystemElementCarousel = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/EnergySystemElementCarousel' );
  var FaucetAndWater = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/FaucetAndWater' );
  var FluorescentBulb = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/FluorescentBulb' );
  var Generator = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Generator' );
  var inherit = require( 'PHET_CORE/inherit' );
  var PropertySet = require( 'AXON/PropertySet' );
  var SolarPanel = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/SolarPanel' );
  var SunEnergySource = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/SunEnergySource' );
  var IncandescentBulb = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/IncandescentBulb' );
  var TeaPot = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/TeaPot' );
  var Vector2 = require( 'DOT/Vector2' );

  // Constants

  // For the images (sun, teapot, biker, ...) scrolling like a one-armed bandit,
  // this is the offset between them (purely vertical).
  var OFFSET_BETWEEN_ELEMENTS_ON_CAROUSEL = new Vector2( 0, -0.4 );

  /**
   * Main constructor for EnergySystemsModel, which contains all of the model
   * logic for the entire sim screen.
   * @constructor
   */
  function EnergySystemsModel() {

    PropertySet.call( this, {

      // Boolean property that controls whether the energy chunks are visible to the user.
      energyChunksVisible: false,

      steamPowerableElementInPlace: false,

      waterPowerableElementInPlace: false,

      // Play/pause state
      isPlaying: true
    } );

    var self = this;

    // Carousels that control the positions of the energy sources, converters,
    // and users.
    this.energySourcesCarousel = new EnergySystemElementCarousel( new Vector2( -0.15, 0 ), OFFSET_BETWEEN_ELEMENTS_ON_CAROUSEL );
    this.energyConvertersCarousel = new EnergySystemElementCarousel( new Vector2( -0.025, 0 ), OFFSET_BETWEEN_ELEMENTS_ON_CAROUSEL );
    this.energyUsersCarousel = new EnergySystemElementCarousel( new Vector2( 0.09, 0 ), OFFSET_BETWEEN_ELEMENTS_ON_CAROUSEL );

    // Energy converters
    this.generator = new Generator( this.energyChunksVisibleProperty );
    this.solarPanel = new SolarPanel( this.energyChunksVisibleProperty );
    this.energyConvertersCarousel.add( this.generator );
    this.energyConvertersCarousel.add( this.solarPanel );

    // Energy sources
    var wheel1Center = this.energySourcesCarousel.selectedElementPosition.plus( Biker.CENTER_OF_BACK_WHEEL_OFFSET ).plusXY( 0.005, 0 );
    var wheel2Center = this.energyConvertersCarousel.selectedElementPosition.plus( Generator.WHEEL_CENTER_OFFSET );

    this.faucet = new FaucetAndWater( this.energyChunksVisibleProperty, this.generator.activeProperty );
    this.sun = new SunEnergySource( this.solarPanel, this.energyChunksVisibleProperty );
    this.teaPot = new TeaPot( this.energyChunksVisibleProperty, this.generator.activeProperty );

    this.belt = new Belt( Biker.REAR_WHEEL_RADIUS, wheel1Center, Generator.WHEEL_RADIUS, wheel2Center );
    this.biker = new Biker( this.energyChunksVisibleProperty, this.generator.activeProperty );
    this.energySourcesCarousel.add( this.faucet );
    this.energySourcesCarousel.add( this.sun );
    this.energySourcesCarousel.add( this.teaPot );
    this.energySourcesCarousel.add( this.biker );

    // Energy users
    this.incandescentBulb = new IncandescentBulb( this.energyChunksVisibleProperty );
    this.fluorescentBulb = new FluorescentBulb( this.energyChunksVisibleProperty );
    this.beakerHeater = new BeakerHeater( this.energyChunksVisibleProperty );
    this.energyUsersCarousel.add( this.beakerHeater );
    this.energyUsersCarousel.add( this.incandescentBulb );
    this.energyUsersCarousel.add( this.fluorescentBulb );

    this.carousels = [
      this.energySourcesCarousel,
      this.energyConvertersCarousel,
      this.energyUsersCarousel
    ];

    // Set isActive = true for the first element in each carousel.
    this.carousels.forEach( function( carousel ) {
      carousel.managedElements[ 0 ].activate();
    } );

    // Add the functionality to show/hide the belt that interconnects the
    // biker and the generator.
    function beltVisibilityUpdated( isAnimating ) {
      var bikerAndGeneratorSelected = ( !isAnimating && self.biker.active && self.generator.active );
      self.belt.isVisibleProperty.set( bikerAndGeneratorSelected );
      self.generator.directCouplingModeProperty.set( bikerAndGeneratorSelected );
    }

    this.energySourcesCarousel.animationInProgressProperty.link( beltVisibilityUpdated );
    this.energyConvertersCarousel.animationInProgressProperty.link( beltVisibilityUpdated );
  }

  energyFormsAndChanges.register( 'EnergySystemsModel', EnergySystemsModel );

  return inherit( PropertySet, EnergySystemsModel, {

    reset: function() {
      this.energyChunksVisibleProperty.reset();

      this.carousels.forEach( function( carousel ) {
        carousel.getSelectedElement().deactivate();
        carousel.targetIndexProperty.set( 0 );
        carousel.getSelectedElement().activate();
      } );
    },

    /**
     * @param  {Number} dt timestep
     * @public
     */
    step: function( dt ) {

      // Elements managed by carousels need to be scrollable/selectable regardless
      // of play/pause state.
      this.carousels.forEach( function( carousel ) {
        carousel.step( dt );
      } );

      if ( this.isPlaying ) {
        var source = this.energySourcesCarousel.getSelectedElement();
        var converter = this.energyConvertersCarousel.getSelectedElement();
        var user = this.energyUsersCarousel.getSelectedElement();

        // Step selected energy system elements
        var energyFromSource = source.step( dt );
        var energyFromConverter = converter.step( dt, energyFromSource );
        user.step( dt, energyFromConverter );

        // Transfer energy chunks between the elements.
        converter.injectEnergyChunks( source.extractOutgoingEnergyChunks() );
        user.injectEnergyChunks( converter.extractOutgoingEnergyChunks() );
      }
    },

    /**
     * Pre-load the currently active energy system elements with energy
     * chunks so that the energy chunks are fully propagated into the
     * elements.
     */
    preLoadEnergyChunks: function() {
      var source = this.energySourcesCarousel.getSelectedElement();
      var converter = this.energyConvertersCarousel.getSelectedElement();
      var user = this.energyUsersCarousel.getSelectedElement();

      source.preLoadEnergyChunks();
      converter.preLoadEnergyChunks( source.getEnergyOutputRate() );
      user.preLoadEnergyChunks( converter.getEnergyOutputRate() );
    }
  } );
} );

<commit_msg>Property -> PropertySet<commit_after>// Copyright 2014-2015, University of Colorado Boulder

/**
 * Model for the 'Energy Systems' screen of the Energy Forms And Changes simulation.
 *
 * @author John Blanco
 * @author Jesse Greenberg
 * @author Andrew Adare
 */
define( function( require ) {
  'use strict';

  // Modules
  var BeakerHeater = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/BeakerHeater' );
  var Biker = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Biker' );
  var Belt = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Belt' );
  var energyFormsAndChanges = require( 'ENERGY_FORMS_AND_CHANGES/energyFormsAndChanges' );
  var EnergySystemElementCarousel = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/EnergySystemElementCarousel' );
  var FaucetAndWater = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/FaucetAndWater' );
  var FluorescentBulb = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/FluorescentBulb' );
  var Generator = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/Generator' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Property = require( 'AXON/Property' );
  var SolarPanel = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/SolarPanel' );
  var SunEnergySource = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/SunEnergySource' );
  var IncandescentBulb = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/IncandescentBulb' );
  var TeaPot = require( 'ENERGY_FORMS_AND_CHANGES/energy-systems/model/TeaPot' );
  var Vector2 = require( 'DOT/Vector2' );

  // Constants

  // For the images (sun, teapot, biker, ...) scrolling like a one-armed bandit,
  // this is the offset between them (purely vertical).
  var OFFSET_BETWEEN_ELEMENTS_ON_CAROUSEL = new Vector2( 0, -0.4 );

  /**
   * Main constructor for EnergySystemsModel, which contains all of the model
   * logic for the entire sim screen.
   * @constructor
   */
  function EnergySystemsModel() {

    this.energyChunksVisibleProperty = new Property( false );
    this.steamPowerableElementInPlaceProperty = new Property( false );
    this.waterPowerableElementInPlaceProperty = new Property( false );
    this.isPlayingProperty = new Property( true );

    var self = this;

    // Carousels that control the positions of the energy sources, converters,
    // and users.
    this.energySourcesCarousel = new EnergySystemElementCarousel( new Vector2( -0.15, 0 ), OFFSET_BETWEEN_ELEMENTS_ON_CAROUSEL );
    this.energyConvertersCarousel = new EnergySystemElementCarousel( new Vector2( -0.025, 0 ), OFFSET_BETWEEN_ELEMENTS_ON_CAROUSEL );
    this.energyUsersCarousel = new EnergySystemElementCarousel( new Vector2( 0.09, 0 ), OFFSET_BETWEEN_ELEMENTS_ON_CAROUSEL );

    // Energy converters
    this.generator = new Generator( this.energyChunksVisibleProperty );
    this.solarPanel = new SolarPanel( this.energyChunksVisibleProperty );
    this.energyConvertersCarousel.add( this.generator );
    this.energyConvertersCarousel.add( this.solarPanel );

    // Energy sources
    var wheel1Center = this.energySourcesCarousel.selectedElementPosition.plus( Biker.CENTER_OF_BACK_WHEEL_OFFSET ).plusXY( 0.005, 0 );
    var wheel2Center = this.energyConvertersCarousel.selectedElementPosition.plus( Generator.WHEEL_CENTER_OFFSET );

    this.faucet = new FaucetAndWater( this.energyChunksVisibleProperty, this.generator.activeProperty );
    this.sun = new SunEnergySource( this.solarPanel, this.energyChunksVisibleProperty );
    this.teaPot = new TeaPot( this.energyChunksVisibleProperty, this.generator.activeProperty );

    this.belt = new Belt( Biker.REAR_WHEEL_RADIUS, wheel1Center, Generator.WHEEL_RADIUS, wheel2Center );
    this.biker = new Biker( this.energyChunksVisibleProperty, this.generator.activeProperty );
    this.energySourcesCarousel.add( this.faucet );
    this.energySourcesCarousel.add( this.sun );
    this.energySourcesCarousel.add( this.teaPot );
    this.energySourcesCarousel.add( this.biker );

    // Energy users
    this.incandescentBulb = new IncandescentBulb( this.energyChunksVisibleProperty );
    this.fluorescentBulb = new FluorescentBulb( this.energyChunksVisibleProperty );
    this.beakerHeater = new BeakerHeater( this.energyChunksVisibleProperty );
    this.energyUsersCarousel.add( this.beakerHeater );
    this.energyUsersCarousel.add( this.incandescentBulb );
    this.energyUsersCarousel.add( this.fluorescentBulb );

    this.carousels = [
      this.energySourcesCarousel,
      this.energyConvertersCarousel,
      this.energyUsersCarousel
    ];

    // Set isActive = true for the first element in each carousel.
    this.carousels.forEach( function( carousel ) {
      carousel.managedElements[ 0 ].activate();
    } );

    // Add the functionality to show/hide the belt that interconnects the
    // biker and the generator.
    function beltVisibilityUpdated( isAnimating ) {
      var bikerAndGeneratorSelected = ( !isAnimating && self.biker.active && self.generator.active );
      self.belt.isVisibleProperty.set( bikerAndGeneratorSelected );
      self.generator.directCouplingModeProperty.set( bikerAndGeneratorSelected );
    }

    this.energySourcesCarousel.animationInProgressProperty.link( beltVisibilityUpdated );
    this.energyConvertersCarousel.animationInProgressProperty.link( beltVisibilityUpdated );
  }

  energyFormsAndChanges.register( 'EnergySystemsModel', EnergySystemsModel );

  return inherit( Object, EnergySystemsModel, {

    reset: function() {
      this.energyChunksVisibleProperty.reset();
      this.steamPowerableElementInPlaceProperty.reset();
      this.waterPowerableElementInPlaceProperty.reset();
      this.isPlayingProperty.reset();

      this.carousels.forEach( function( carousel ) {
        carousel.getSelectedElement().deactivate();
        carousel.targetIndexProperty.set( 0 );
        carousel.getSelectedElement().activate();
      } );
    },

    /**
     * @param  {Number} dt timestep
     * @public
     */
    step: function( dt ) {

      // Elements managed by carousels need to be scrollable/selectable regardless
      // of play/pause state.
      this.carousels.forEach( function( carousel ) {
        carousel.step( dt );
      } );

      if ( this.isPlayingProperty.value ) {
        var source = this.energySourcesCarousel.getSelectedElement();
        var converter = this.energyConvertersCarousel.getSelectedElement();
        var user = this.energyUsersCarousel.getSelectedElement();

        // Step selected energy system elements
        var energyFromSource = source.step( dt );
        var energyFromConverter = converter.step( dt, energyFromSource );
        user.step( dt, energyFromConverter );

        // Transfer energy chunks between the elements.
        converter.injectEnergyChunks( source.extractOutgoingEnergyChunks() );
        user.injectEnergyChunks( converter.extractOutgoingEnergyChunks() );
      }
    },

    /**
     * Pre-load the currently active energy system elements with energy
     * chunks so that the energy chunks are fully propagated into the
     * elements.
     */
    preLoadEnergyChunks: function() {
      var source = this.energySourcesCarousel.getSelectedElement();
      var converter = this.energyConvertersCarousel.getSelectedElement();
      var user = this.energyUsersCarousel.getSelectedElement();

      source.preLoadEnergyChunks();
      converter.preLoadEnergyChunks( source.getEnergyOutputRate() );
      user.preLoadEnergyChunks( converter.getEnergyOutputRate() );
    }
  } );
} );

<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var sys = require('sys');
var fs = require('fs');
var path = require('path');
var http = require('http');
var crypto = require('crypto');
var pumpfile = require('util/http_pumpfile');
var client_config = require('util/config');
var misc = require('util/misc');
var spinner = require('util/spinner');
var manifest = require('manifest/index');
var MANIFEST_FILENAME = require('manifest/constants').MANIFEST_FILENAME;
var async = require('extern/async');

var config = {
  short_description: 'Upload an application bundle.',
  long_description: 'Upload an application bundle to a remote server.',
  required_arguments: [],
  optional_arguments: [['version', 'The bundle version to upload, defaults to the newest available']],
  switches: []
};

function handle_command(args) {
  var manifest_path = path.join(process.cwd(), MANIFEST_FILENAME);
  var bundledir = path.join(process.cwd(), client_config.get().temp_directory);
  var version = args.version;
  var bundlename;
  var fpath;
  var sha1;
  var size = 0;

  async.series([
    function(callback) {
      // If no version was specified then look up the most recently modified bundle
      if (!version) {
        fs.readdir(bundledir, function(err, files) {
          var msg;

          if (err) {
            msg = "Unable to read " + bundledir + ", have you created a bundle yet?";;
            return callback(new Error(msg));
          }

          var newestfile;
          var newestmtime;

          async.forEach(files, function(file, callback) {
            fs.stat(path.join(bundledir, file), function(err, stats) {
              if (!err && stats.isFile() && (!newestmtime || stats.mtime > newestmtime)) {
                newestmtime = stats.mtime;
                newestfile = file;
              }
              return callback();
            });
          },
          function(err) {
            if (!err && !newestfile) {
              msg = "No bundles found in " + bundledir + " have you created one yet?";
              err = new Error(msg);
            }
            else {
              fpath = path.join(bundledir, newestfile);
            }
            return callback(err);
          });
        });
      }

      // If a version was specified, make sure it exists
      else {
        fpath = path.join(bundledir, version + '.tar.gz');
        fs.stat(fpath, function(err, stats) {
          if (err || !stats.isFile()) {
            err = new Error("Specified version does not exist.");
          }
          return callback(err);
        });
      }
    },

    // Validate the manifest and get the bundle name
    function(callback) {
      manifest.validate_manifest(manifest_path, function(err, app_manifest) {
        if (!err) {
          bundlename = misc.get_valid_bundle_name(app_manifest.name);
        }
        return callback(err);
      });
    },

    // Calculate the SHA1
    function(callback) {
      sha1 = crypto.createHash('sha1');
      var fstream = fs.createReadStream(fpath, {'bufferSize': client_config.get().fileread_buffer_size});
      var errstate = false;

      fstream.on('data', function(data) {
        sha1.update(data);
        size += data.length;
      });

      fstream.on('error', function(err) {
        errstate = true;
        return callback(new Error("Error reading bundle file."));
      });

      fstream.on('end', function() {
        if (!errstate) {
          return callback();
        }
      });
    },

    function(callback) {
      process.nextTick(function(){
        var remotepath = path.join('/', 'bundles', bundlename, path.basename(fpath));
        var pbar = spinner.percentbar("Uploading " + path.basename(fpath), size);

        pbar.start();
        // TODO: Allow custom remotes
        var client = http.createClient(8010, 'localhost');
        var bytes = 0;

        var request = client.request('PUT', remotepath, {
          'host': 'localhost',
          'content-length': size,
          'transfer-encoding': 'chunked',
          'x-content-sha1': sha1.digest('base64')
        });

        // TODO: We should try to use sys.pump here
        var fstream = fs.createReadStream(fpath, {'bufferSize': 512});
        var errstate = false;

        function handle_error(err) {
          if (!errstate) {
            errstate = true;
            fstream.removeAllListeners('data');
            fstream.destroy();
            request.end();
            pbar.end();
            return callback(new Error("A connection error occurred"));
          }
        }

        client.on('error', handle_error);

        request.on('error', handle_error);

        fstream.on('data', function(data) {
          request.write(data);
          bytes += data.length;
          pbar.tick(bytes);
        });

        fstream.on('error', function(err) {
          errstate = true;
          request.end();
          return callback(new Error("Error reading bundle file."));
        });

        fstream.on('end', function() {
          if (!errstate) {
            pbar.end();
            request.end();
            sys.puts("Waiting for response...");
          }
        });

        request.on('response', function(response) {
          if (!errstate) {
            if (response.statusCode === 204) {
              return callback();
            }
            var chunks = [];

            response.on('data', function(data) {
              chunks.push(data);
            });

            response.on('end', function() {
              try {
                var err = JSON.parse(chunks.join(''));
                return callback(new Error(err.message));
              }
              catch (err) {
                return callback(new Error("Unexpected response from agent"));
              }
            });
          }
        });
      });
    },
  ],
  function(err) {
    if (err) {
      sys.puts("Error: " + err.message);
    }
    else {
      sys.puts("Upload Successful");
    }
  });
}

exports.config = config;
exports.handle_command = handle_command;
<commit_msg>Improve file uploading efficiency and stability.<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var sys = require('sys');
var fs = require('fs');
var path = require('path');
var http = require('http');
var crypto = require('crypto');
var pumpfile = require('util/http_pumpfile');
var client_config = require('util/config');
var misc = require('util/misc');
var spinner = require('util/spinner');
var manifest = require('manifest/index');
var MANIFEST_FILENAME = require('manifest/constants').MANIFEST_FILENAME;
var async = require('extern/async');

var config = {
  short_description: 'Upload an application bundle.',
  long_description: 'Upload an application bundle to a remote server.',
  required_arguments: [],
  optional_arguments: [['version', 'The bundle version to upload, defaults to the newest available']],
  switches: []
};

function handle_command(args) {
  var manifest_path = path.join(process.cwd(), MANIFEST_FILENAME);
  var bundledir = path.join(process.cwd(), client_config.get().temp_directory);
  var version = args.version;
  var bundlename;
  var fpath;
  var sha1;
  var size = 0;

  async.series([
    function(callback) {
      // If no version was specified then look up the most recently modified bundle
      if (!version) {
        fs.readdir(bundledir, function(err, files) {
          var msg;

          if (err) {
            msg = "Unable to read " + bundledir + ", have you created a bundle yet?";;
            return callback(new Error(msg));
          }

          var newestfile;
          var newestmtime;

          async.forEach(files, function(file, callback) {
            fs.stat(path.join(bundledir, file), function(err, stats) {
              if (!err && stats.isFile() && (!newestmtime || stats.mtime > newestmtime)) {
                newestmtime = stats.mtime;
                newestfile = file;
              }
              return callback();
            });
          },
          function(err) {
            if (!err && !newestfile) {
              msg = "No bundles found in " + bundledir + " have you created one yet?";
              err = new Error(msg);
            }
            else {
              fpath = path.join(bundledir, newestfile);
            }
            return callback(err);
          });
        });
      }

      // If a version was specified, make sure it exists
      else {
        fpath = path.join(bundledir, version + '.tar.gz');
        fs.stat(fpath, function(err, stats) {
          if (err || !stats.isFile()) {
            err = new Error("Specified version does not exist.");
          }
          return callback(err);
        });
      }
    },

    // Validate the manifest and get the bundle name
    function(callback) {
      manifest.validate_manifest(manifest_path, function(err, app_manifest) {
        if (!err) {
          bundlename = misc.get_valid_bundle_name(app_manifest.name);
        }
        return callback(err);
      });
    },

    // Calculate the SHA1
    function(callback) {
      sha1 = crypto.createHash('sha1');
      var fstream = fs.createReadStream(fpath, {'bufferSize': client_config.get().fileread_buffer_size});
      var errstate = false;

      fstream.on('data', function(data) {
        sha1.update(data);
        size += data.length;
      });

      fstream.on('error', function(err) {
        errstate = true;
        return callback(new Error("Error reading bundle file."));
      });

      fstream.on('end', function() {
        if (!errstate) {
          return callback();
        }
      });
    },

    function(callback) {
      var remotepath = path.join('/', 'bundles', bundlename, path.basename(fpath));
      var pbar = spinner.percentbar("Uploading " + path.basename(fpath), size);

      pbar.start();
      // TODO: Allow custom remotes
      var client = http.createClient(8010, 'localhost');
      var bytes = 0;

      var request = client.request('PUT', remotepath, {
        'host': 'localhost',
        'content-length': size,
        'transfer-encoding': 'chunked',
        'x-content-sha1': sha1.digest('base64')
      });

      // TODO: We should try to use sys.pump here
      var fstream = fs.createReadStream(fpath, {'bufferSize': client_config.get().fileread_buffer_size});
      fstream.on('open', function() {
        var errstate = false;

        function handle_error(err) {
          if (!errstate) {
            errstate = true;
            fstream.removeAllListeners('data');
            fstream.destroy();
            request.end();
            pbar.end();
            return callback(new Error("A connection error occurred"));
          }
        }

        client.on('error', handle_error);

        request.on('error', handle_error);

        fstream.on('data', function(data) {
          if (request.write(data) === false) fstream.pause();
          bytes += data.length;
          pbar.tick(bytes);
        });

        request.on('drain', function() {
          if (!errstate) {
            fstream.resume();
          }
        });

        fstream.on('error', function(err) {
          errstate = true;
          request.end();
          return callback(new Error("Error reading bundle file."));
        });

        fstream.on('end', function() {
          if (!errstate) {
            pbar.end();
            request.end();
            sys.puts("Waiting for response...");
          }
        });

        request.on('response', function(response) {
          if (!errstate) {
            if (response.statusCode === 204) {
              return callback();
            }
            var chunks = [];

            response.on('data', function(data) {
              chunks.push(data);
            });

            response.on('end', function() {
              try {
                var err = JSON.parse(chunks.join(''));
                return callback(new Error(err.message));
              }
              catch (err) {
                return callback(new Error("Unexpected response from agent"));
              }
            });
          }
        });
      });
    },
  ],
  function(err) {
    if (err) {
      sys.puts("Error: " + err.message);
    }
    else {
      sys.puts("Upload Successful");
    }
  });
}

exports.config = config;
exports.handle_command = handle_command;
<|endoftext|>


<commit_before>/* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */
/* global Flash */

((global) => {
  class Profile {
    constructor({ form } = {}) {
      this.onSubmitForm = this.onSubmitForm.bind(this);
      this.form = form || $('.edit-user');
      this.bindEvents();
      this.initAvatarGlCrop();
    }

    initAvatarGlCrop() {
      const cropOpts = {
        filename: '.js-avatar-filename',
        previewImage: '.avatar-image .avatar',
        modalCrop: '.modal-profile-crop',
        pickImageEl: '.js-choose-user-avatar-button',
        uploadImageBtn: '.js-upload-user-avatar',
        modalCropImg: '.modal-profile-crop-image'
      };
      this.avatarGlCrop = $('.js-user-avatar-input').glCrop(cropOpts).data('glcrop');
    }

    bindEvents() {
      $('.js-preferences-form').on('change.preference', 'input[type=radio]', this.submitForm);
      $('#user_notification_email').on('change', this.submitForm);
      $('.update-username').on('ajax:before', this.beforeUpdateUsername);
      $('.update-username').on('ajax:complete', this.afterUpdateUsername);
      $('.update-notifications').on('ajax:success', this.onUpdateNotifs);
      this.form.on('submit', this.onSubmitForm);
    }

    submitForm() {
      return $(this).parents('form').submit();
    }

    onSubmitForm(e) {
      return this.saveForm();
    }

    beforeUpdateUsername() {
      $('.loading-username', this).removeClass('hidden');
    }

    afterUpdateUsername() {
      $('.loading-username', this).addClass('hidden');
      $('button[type=submit]', this).enable();
    }

    onUpdateNotifs(e, data) {
      return data.saved ?
        new Flash("Notification settings saved", "notice") :
        new Flash("Failed to save new settings", "alert");
    }

    saveForm() {
      const self = this;
      const formData = new FormData(this.form[0]);
      const avatarBlob = this.avatarGlCrop.getBlob();

      if (avatarBlob != null) {
        formData.append('user[avatar]', avatarBlob, 'avatar.png');
      }

      return $.ajax({
        url: this.form.attr('action'),
        type: this.form.attr('method'),
        data: formData,
        dataType: "json",
        processData: false,
        contentType: false,
        success: response => new Flash(response.message, 'notice'),
        error: jqXHR => new Flash(jqXHR.responseJSON.message, 'alert'),
        complete: () => {
          window.scrollTo(0, 0);
          // Enable submit button after requests ends
          return self.form.find(':input[disabled]').enable();
        }
      });
    }
  }

  $(function() {
    $(document).on('focusout.ssh_key', '#key_key', function() {
      const $title = $('#key_title');
      const comment = $(this).val().match(/^\S+ \S+ (.+)\n?$/);
      if (comment && comment.length > 1 && $title.val() === '') {
        return $title.val(comment[1]).change();
      }
    // Extract the SSH Key title from its comment
    });
    if (global.utils.getPagePath() === 'profiles') {
      return new Profile();
    }
  });
})(window.gl || (window.gl = {}));
<commit_msg>Prevent form to be submitted twice<commit_after>/* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */
/* global Flash */

((global) => {
  class Profile {
    constructor({ form } = {}) {
      this.onSubmitForm = this.onSubmitForm.bind(this);
      this.form = form || $('.edit-user');
      this.bindEvents();
      this.initAvatarGlCrop();
    }

    initAvatarGlCrop() {
      const cropOpts = {
        filename: '.js-avatar-filename',
        previewImage: '.avatar-image .avatar',
        modalCrop: '.modal-profile-crop',
        pickImageEl: '.js-choose-user-avatar-button',
        uploadImageBtn: '.js-upload-user-avatar',
        modalCropImg: '.modal-profile-crop-image'
      };
      this.avatarGlCrop = $('.js-user-avatar-input').glCrop(cropOpts).data('glcrop');
    }

    bindEvents() {
      $('.js-preferences-form').on('change.preference', 'input[type=radio]', this.submitForm);
      $('#user_notification_email').on('change', this.submitForm);
      $('.update-username').on('ajax:before', this.beforeUpdateUsername);
      $('.update-username').on('ajax:complete', this.afterUpdateUsername);
      $('.update-notifications').on('ajax:success', this.onUpdateNotifs);
      this.form.on('submit', this.onSubmitForm);
    }

    submitForm() {
      return $(this).parents('form').submit();
    }

    onSubmitForm(e) {
      e.preventDefault();
      return this.saveForm();
    }

    beforeUpdateUsername() {
      $('.loading-username', this).removeClass('hidden');
    }

    afterUpdateUsername() {
      $('.loading-username', this).addClass('hidden');
      $('button[type=submit]', this).enable();
    }

    onUpdateNotifs(e, data) {
      return data.saved ?
        new Flash("Notification settings saved", "notice") :
        new Flash("Failed to save new settings", "alert");
    }

    saveForm() {
      const self = this;
      const formData = new FormData(this.form[0]);
      const avatarBlob = this.avatarGlCrop.getBlob();

      if (avatarBlob != null) {
        formData.append('user[avatar]', avatarBlob, 'avatar.png');
      }

      return $.ajax({
        url: this.form.attr('action'),
        type: this.form.attr('method'),
        data: formData,
        dataType: "json",
        processData: false,
        contentType: false,
        success: response => new Flash(response.message, 'notice'),
        error: jqXHR => new Flash(jqXHR.responseJSON.message, 'alert'),
        complete: () => {
          window.scrollTo(0, 0);
          // Enable submit button after requests ends
          return self.form.find(':input[disabled]').enable();
        }
      });
    }
  }

  $(function() {
    $(document).on('focusout.ssh_key', '#key_key', function() {
      const $title = $('#key_title');
      const comment = $(this).val().match(/^\S+ \S+ (.+)\n?$/);
      if (comment && comment.length > 1 && $title.val() === '') {
        return $title.val(comment[1]).change();
      }
    // Extract the SSH Key title from its comment
    });
    if (global.utils.getPagePath() === 'profiles') {
      return new Profile();
    }
  });
})(window.gl || (window.gl = {}));
<|endoftext|>


<commit_before>
var count = 0;
function sayHello(text){
    alert('Hello' + text + 'count is ' + count);
}
<commit_msg>adding counter++<commit_after>
var count = 0;
function sayHello(text){
	count++;
    alert('Hello' + text + 'count is ' + count);
}
<|endoftext|>


<commit_before>(function ($) {
  jQuery.expr[':'].contains = function (obj, index, meta){
    return (obj.textContent || obj.innerText || "").toUpperCase().indexOf(meta[3].toUpperCase()) >= 0;
  };

  var input = $("form#country-filter input#country");
  var list = $("ul.countries li");

  $(input).change(function () {
    var filter = $(this).val();

    if (filter && filter.length > 0) {
      $(list).find("a:not(:contains(" + filter + "))").parent().hide();
      $(list).find("a:contains(" + filter + ")").parent().show();
    } else {
      $(list).find("a").parent().show();
    }

    return false;
  }).keyup(function () {
    $(this).change();
  });
}(jQuery));
<commit_msg>Hide headings with no visible items when filtering<commit_after>(function ($) {
  jQuery.expr[':'].contains = function (obj, index, meta){
    return (obj.textContent || obj.innerText || "").toUpperCase().indexOf(meta[3].toUpperCase()) >= 0;
  };

  var headingHasVisibleCountries = function(headingFirstLetter) {
    return $("section#" + headingFirstLetter.toUpperCase()).find("li:visible").length > 0;
  };

  var input = $("form#country-filter input#country");
  var listItems = $("ul.countries li");
  var countryHeadings = $(".inner section").not(":first").children("h1");

  var filterHeadings = function() {
    countryHeadings.each(function(index, elem) {
      var $elem = $(elem),
          header = $elem.text();
      if(headingHasVisibleCountries(header)) {
        $elem.show();
      } else {
        $elem.hide();
      }
    });
  };

  input.change(function () {
    var filter = $(this).val();

    if (filter && filter.length > 0) {
      listItems.show();
      listItems.filter(":not(:contains(" + filter + "))").hide();
      filterHeadings();
    } else {
      listItems.show();
      countryHeadings.show();
    }

    return false;
  }).keyup(function () {
    $(this).change();
  });
}(jQuery));
<|endoftext|>


<commit_before>var _ = require('underscore');
var cdb = require('cartodb.js');
var Dashboard = require('./dashboard');
var DashboardView = require('../dashboard-view');
var WidgetsCollection = require('../widgets/widgets-collection');
var WidgetsService = require('../widgets-service');
var URLHelper = require('./url-helper');

/**
 * Translates a vizJSON v3 datastructure into a working dashboard which will be rendered in given selector.
 *
 * @param {String} selector e.g. "#foobar-id", ".some-class"
 * @param {Object} vizJSON JSON datastructure
 * @param {Object} opts (Optional) flags, see 3rd param for cdb.createVis for available ones. Keys used here:
 *   renderMenu: {Boolean} If true (default), render a top-level menu on the left side.
 * @return {Object} with keys:
 *   dashboardView: root (backbone) view of the dashboard
 *   vis: the instantiated vis map, same result as given from cdb.createVis()
 */
var createDashboard = function (selector, vizJSON, opts, callback) {
  var dashboardEl = document.querySelector(selector);
  if (!dashboardEl) throw new Error('no element found with selector ' + selector);

  // Default options
  opts = opts || {};
  opts.renderMenu = _.isBoolean(opts.renderMenu)
    ? opts.renderMenu
    : true;

  var widgets = new WidgetsCollection();

  var model = new cdb.core.Model({
    title: vizJSON.title,
    description: vizJSON.description,
    updatedAt: vizJSON.updated_at,
    userName: vizJSON.user.fullname,
    userProfileURL: vizJSON.user.profile_url,
    userAvatarURL: vizJSON.user.avatar_url,
    renderMenu: opts.renderMenu,
    initialPosition: {
      bounds: vizJSON.bounds
    }
  });
  var dashboardView = new DashboardView({
    el: dashboardEl,
    widgets: widgets,
    model: model
  });
  var stateFromURL = opts.state || URLHelper.getStateFromCurrentURL();
  if (stateFromURL && !_.isEmpty(stateFromURL.map)) {
    vizJSON.bounds = [stateFromURL.map.ne, stateFromURL.map.sw];
  }

  var vis = cdb.createVis(dashboardView.$('#map'), vizJSON, _.extend(opts, {
    skipMapInstantiation: true
  }));

  vis.once('load', function (vis) {
    if (stateFromURL && !_.isEmpty(stateFromURL.map)) {
      vis.map.setBounds([stateFromURL.map.ne, stateFromURL.map.sw]);
    }

    var widgetsState = stateFromURL && stateFromURL.widgets || {};

    // Create widgets
    var widgetsService = new WidgetsService(widgets, vis.dataviews);
    var widgetModelsMap = {
      list: widgetsService.createListModel.bind(widgetsService),
      formula: widgetsService.createFormulaModel.bind(widgetsService),
      histogram: widgetsService.createHistogramModel.bind(widgetsService),
      'time-series': widgetsService.createTimeSeriesModel.bind(widgetsService),
      category: widgetsService.createCategoryModel.bind(widgetsService)
    };
    vizJSON.widgets.forEach(function (d) {
      // Flatten the data structure given in vizJSON, the widgetsService will use whatever it needs and ignore the rest
      var attrs = _.extend({}, d, d.options);
      var newWidgetModel = widgetModelsMap[d.type];
      var state = widgetsState[d.id];

      if (_.isFunction(newWidgetModel)) {
        // Find the Layer that the Widget should be created for.
        var layer;
        if (d.layer_id) {
          layer = vis.map.layers.get(d.layer_id);
        } else if (Number.isInteger(d.layerIndex)) {
          // TODO Since namedmap doesn't have ids we need to map in another way, here using index
          //   should we solve this in another way?
          layer = vis.map.layers.at(d.layerIndex);
        }

        newWidgetModel(attrs, layer, state);
      } else {
        cdb.log.error('No widget found for type ' + d.type);
      }
    });

    dashboardView.render();

    if (widgets.size() > 0) {
      vis.centerMapToOrigin();
    }

    vis.instantiateMap({
      success: function () {
        callback && callback(null, {
          dashboardView: dashboardView,
          widgets: widgetsService,
          vis: vis
        });
      },
      error: function () {
        var error = new Error('Map instantiation failed');
        console.log(error);
        callback && callback(error, {
          dashboardView: dashboardView,
          widgets: widgetsService,
          vis: vis
        });
      }
    });
  });
};

module.exports = function (selector, vizJSON, opts, callback) {
  var args = arguments;
  var fn = args[args.length - 1];

  if (_.isFunction(fn)) {
    callback = fn;
  }

  function _load (vizJSON) {
    createDashboard(selector, vizJSON, opts, function (error, dashboard) {
      var dash = new Dashboard(dashboard);
      if (opts.share_urls) {
        dash.onStateChanged(_.debounce(function (state, url) {
          window.history.replaceState('Object', 'Title', url);
        }, 500));
      }

      callback && callback(error, dash);
    });
  }

  if (typeof vizJSON === 'string') {
    cdb.core.Loader.get(vizJSON, function (data) {
      if (data) {
        _load(data, opts);
      } else {
        callback && callback(new Error('error fetching viz.json file'));
      }
    });
  } else {
    _load(vizJSON, opts);
  }
};
<commit_msg>Zoom and center for old maps fallback.<commit_after>var _ = require('underscore');
var cdb = require('cartodb.js');
var Dashboard = require('./dashboard');
var DashboardView = require('../dashboard-view');
var WidgetsCollection = require('../widgets/widgets-collection');
var WidgetsService = require('../widgets-service');
var URLHelper = require('./url-helper');

/**
 * Translates a vizJSON v3 datastructure into a working dashboard which will be rendered in given selector.
 *
 * @param {String} selector e.g. "#foobar-id", ".some-class"
 * @param {Object} vizJSON JSON datastructure
 * @param {Object} opts (Optional) flags, see 3rd param for cdb.createVis for available ones. Keys used here:
 *   renderMenu: {Boolean} If true (default), render a top-level menu on the left side.
 * @return {Object} with keys:
 *   dashboardView: root (backbone) view of the dashboard
 *   vis: the instantiated vis map, same result as given from cdb.createVis()
 */
var createDashboard = function (selector, vizJSON, opts, callback) {
  var dashboardEl = document.querySelector(selector);
  if (!dashboardEl) throw new Error('no element found with selector ' + selector);

  // Default options
  opts = opts || {};
  opts.renderMenu = _.isBoolean(opts.renderMenu)
    ? opts.renderMenu
    : true;

  var widgets = new WidgetsCollection();

  var model = new cdb.core.Model({
    title: vizJSON.title,
    description: vizJSON.description,
    updatedAt: vizJSON.updated_at,
    userName: vizJSON.user.fullname,
    userProfileURL: vizJSON.user.profile_url,
    userAvatarURL: vizJSON.user.avatar_url,
    renderMenu: opts.renderMenu,
    initialPosition: {
      bounds: vizJSON.bounds
    }
  });
  var dashboardView = new DashboardView({
    el: dashboardEl,
    widgets: widgets,
    model: model
  });
  var stateFromURL = opts.state || URLHelper.getStateFromCurrentURL();
  if (stateFromURL && !_.isEmpty(stateFromURL.map)) {
    vizJSON.bounds = [stateFromURL.map.ne, stateFromURL.map.sw];
  }

  var vis = cdb.createVis(dashboardView.$('#map'), vizJSON, _.extend(opts, {
    skipMapInstantiation: true
  }));

  vis.once('load', function (vis) {
    if (stateFromURL && !_.isEmpty(stateFromURL.map)) {
      if (!_.isUndefined(stateFromURL.map.ne) && !_.isUndefined(stateFromURL.map.sw)) {
        vis.map.setBounds([stateFromURL.map.ne, stateFromURL.map.sw]);
      } else if (!_.isUndefined(stateFromURL.map.center) && !_.isUndefined(stateFromURL.map.zoom)) {
        vis.map.setView(stateFromURL.map.center, stateFromURL.map.zoom);
      }
    }

    var widgetsState = stateFromURL && stateFromURL.widgets || {};

    // Create widgets
    var widgetsService = new WidgetsService(widgets, vis.dataviews);
    var widgetModelsMap = {
      list: widgetsService.createListModel.bind(widgetsService),
      formula: widgetsService.createFormulaModel.bind(widgetsService),
      histogram: widgetsService.createHistogramModel.bind(widgetsService),
      'time-series': widgetsService.createTimeSeriesModel.bind(widgetsService),
      category: widgetsService.createCategoryModel.bind(widgetsService)
    };
    vizJSON.widgets.forEach(function (d) {
      // Flatten the data structure given in vizJSON, the widgetsService will use whatever it needs and ignore the rest
      var attrs = _.extend({}, d, d.options);
      var newWidgetModel = widgetModelsMap[d.type];
      var state = widgetsState[d.id];

      if (_.isFunction(newWidgetModel)) {
        // Find the Layer that the Widget should be created for.
        var layer;
        if (d.layer_id) {
          layer = vis.map.layers.get(d.layer_id);
        } else if (Number.isInteger(d.layerIndex)) {
          // TODO Since namedmap doesn't have ids we need to map in another way, here using index
          //   should we solve this in another way?
          layer = vis.map.layers.at(d.layerIndex);
        }

        newWidgetModel(attrs, layer, state);
      } else {
        cdb.log.error('No widget found for type ' + d.type);
      }
    });

    dashboardView.render();

    if (widgets.size() > 0) {
      vis.centerMapToOrigin();
    }

    vis.instantiateMap({
      success: function () {
        callback && callback(null, {
          dashboardView: dashboardView,
          widgets: widgetsService,
          vis: vis
        });
      },
      error: function () {
        var error = new Error('Map instantiation failed');
        console.log(error);
        callback && callback(error, {
          dashboardView: dashboardView,
          widgets: widgetsService,
          vis: vis
        });
      }
    });
  });
};

module.exports = function (selector, vizJSON, opts, callback) {
  var args = arguments;
  var fn = args[args.length - 1];

  if (_.isFunction(fn)) {
    callback = fn;
  }

  function _load (vizJSON) {
    createDashboard(selector, vizJSON, opts, function (error, dashboard) {
      var dash = new Dashboard(dashboard);
      if (opts.share_urls) {
        dash.onStateChanged(_.debounce(function (state, url) {
          window.history.replaceState('Object', 'Title', url);
        }, 500));
      }

      callback && callback(error, dash);
    });
  }

  if (typeof vizJSON === 'string') {
    cdb.core.Loader.get(vizJSON, function (data) {
      if (data) {
        _load(data, opts);
      } else {
        callback && callback(new Error('error fetching viz.json file'));
      }
    });
  } else {
    _load(vizJSON, opts);
  }
};
<|endoftext|>


<commit_before>odoo.define('js_parameterization.form_widgets', function (require) {
    "use strict";

    var core = require('web.core');
    var common = require('web.form_common');
    var FieldPercentPie = core.form_widget_registry.get('percentpie');
    var FieldMany2ManyTags = core.form_widget_registry.get('many2many_tags');
    var _t = core._t;

    var JsPercentPie = FieldPercentPie.extend({
        render_value: function(){
            this._super.apply(this, arguments);
            var value = this.get_value();
            this.$el.find('.o_pie').attr('data-value', value);

            if (value == 100){
                this.$el.find('span').text(_t('Completada'));
                this.$pie_value.html('');
            }
        }
    });

    var JsFieldMany2ManyTags = FieldMany2ManyTags.extend({
        get_badge_id: function(el){
            if ($(el).hasClass('badge')) return $(el).data('id');
            return $(el).closest('.badge').data('id');
        },
        events: {
            'click .o_delete': function(e) {
                e.stopPropagation();
                this.remove_id(this.get_badge_id(e.target));
            },
            'click .badge': function(e) {
                e.stopPropagation();

                if (typeof(this.many2one) == 'undefined'){
                    alert(_t("Can't open this item on view mode!"));
                    return false;
                }

                var self = this;
                var record_id = this.get_badge_id(e.target);
                new common.FormViewDialog(self, {
                    res_model: self.many2one.field.relation,
                    res_id: record_id,
                    context: self.dataset.context.add({ 'hide_fields': true }),
                    title: _t('Open: ') + self.many2one.string,
                    readonly: true
                }).on('write_completed', self, function() {
                    self.dataset.cache[record_id].from_read = {};
                    self.dataset.evict_record(record_id);
                    self.render_value();
                }).open();
            }
        }
    });

    core.form_widget_registry.add('js_percentpie', JsPercentPie);
    core.form_widget_registry.add('js_many2many_tags', JsFieldMany2ManyTags);

    return {
        JsPercentPie : JsPercentPie,
        JsFieldMany2ManyTags: JsFieldMany2ManyTags
    };

});
<commit_msg>Update form_widgets.js<commit_after>odoo.define('js_parameterization.form_widgets', function (require) {
    "use strict";

    var core = require('web.core');
    var common = require('web.form_common');
    var FieldPercentPie = core.form_widget_registry.get('percentpie');
    var FieldMany2ManyTags = core.form_widget_registry.get('many2many_tags');
    var _t = core._t;

    var JsPercentPie = FieldPercentPie.extend({
        render_value: function(){
            this._super.apply(this, arguments);
            var value = this.get_value();
            this.$el.find('.o_pie').attr('data-value', value);

            if (value == 100){
                this.$el.find('span').text(_t('Completada'));
                this.$pie_value.html('');
            }
        }
    });

    var JsFieldMany2ManyTags = FieldMany2ManyTags.extend({
        get_badge_id: function(el){
            if ($(el).hasClass('badge')) return $(el).data('id');
            return $(el).closest('.badge').data('id');
        },
        events: {
            'click .o_delete': function(e) {
                e.stopPropagation();
                this.remove_id(this.get_badge_id(e.target));
            },
            'click .badge': function(e) {
                e.stopPropagation();

                if (typeof(this.many2one) == 'undefined'){
                    alert(_t("Can't open this item on view mode!"));
                    return false;
                }

                var self = this;
                var record_id = this.get_badge_id(e.target);
                new common.FormViewDialog(self, {
                    res_model: self.many2one.field.relation,
                    res_id: record_id,
                    context: self.dataset.context.add({ 'hide_fields': true }),
                    title: _t('Open: ') + self.many2one.string,
                    readonly: true // self.many2one.get('effective_readonly')
                }).on('write_completed', self, function() {
                    self.dataset.cache[record_id].from_read = {};
                    self.dataset.evict_record(record_id);
                    self.render_value();
                }).open();
            }
        }
    });

    core.form_widget_registry.add('js_percentpie', JsPercentPie);
    core.form_widget_registry.add('js_many2many_tags', JsFieldMany2ManyTags);

    return {
        JsPercentPie : JsPercentPie,
        JsFieldMany2ManyTags: JsFieldMany2ManyTags
    };

});
<|endoftext|>


<commit_before>import querystring from 'querystring';
import fetch from 'cross-fetch';
import { btoa, removeUndefined } from '../../utils/index';

/**
 * To perform fetch request
 * @param {Object} args
 * @param {String} args.method
 * @param {String} args.path
 * @param {Object} args.params
 * @param {Object} args.body
 */
function fetchRequest(args) {
  return new Promise((resolve, reject) => {
    const parsedArgs = removeUndefined(args);
    try {
      const {
 method, path, params, body,
} = parsedArgs;
      let bodyCopy = body;
      const contentType = path.endsWith('msearch') || path.endsWith('bulk')
          ? 'application/x-ndjson'
          : 'application/json';
      const headers = Object.assign(
        {},
        {
          Accept: 'application/json',
          'Content-Type': contentType,
        },
        this.headers,
      );
      const timestamp = Date.now();
      if (this.credentials) {
        headers.Authorization = `Basic ${btoa(this.credentials)}`;
      }
      const requestOptions = {
        method,
        headers,
      };
      if (Array.isArray(bodyCopy)) {
        let arrayBody = '';
        bodyCopy.forEach((item) => {
          arrayBody += JSON.stringify(item);
          arrayBody += '\n';
        });

        bodyCopy = arrayBody;
      } else {
        bodyCopy = JSON.stringify(bodyCopy) || {};
      }

      if (Object.keys(bodyCopy).length !== 0) {
        requestOptions.body = bodyCopy;
      }

      let finalRequest = requestOptions;
      if (this.transformRequest) {
        finalRequest = this.transformRequest(requestOptions);
      }
      let responseHeaders = {};
      return fetch(
        `${this.protocol}://${this.url}/${this.app}/${path}?${querystring.stringify(params)}`,
        finalRequest,
      ).then((res) => {
        if (res.status >= 500) {
          return reject(res);
        }
        responseHeaders = res.headers;
        return res.json().then((data) => {
          if (res.status >= 400) {
            return reject(res);
          }
          const response = Object.assign({}, data, {
            _timestamp: timestamp,
            _headers: responseHeaders,
          });
          return resolve(response);
        });
      });
    } catch (e) {
      return reject(e);
    }
  });
}
export default fetchRequest;
<commit_msg>fix(): catch error when network is not present<commit_after>import querystring from 'querystring';
import fetch from 'cross-fetch';
import { btoa, removeUndefined } from '../../utils/index';

/**
 * To perform fetch request
 * @param {Object} args
 * @param {String} args.method
 * @param {String} args.path
 * @param {Object} args.params
 * @param {Object} args.body
 */
function fetchRequest(args) {
  return new Promise((resolve, reject) => {
    const parsedArgs = removeUndefined(args);
    try {
      const {
 method, path, params, body,
} = parsedArgs;
      let bodyCopy = body;
      const contentType = path.endsWith('msearch') || path.endsWith('bulk')
          ? 'application/x-ndjson'
          : 'application/json';
      const headers = Object.assign(
        {},
        {
          Accept: 'application/json',
          'Content-Type': contentType,
        },
        this.headers,
      );
      const timestamp = Date.now();
      if (this.credentials) {
        headers.Authorization = `Basic ${btoa(this.credentials)}`;
      }
      const requestOptions = {
        method,
        headers,
      };
      if (Array.isArray(bodyCopy)) {
        let arrayBody = '';
        bodyCopy.forEach((item) => {
          arrayBody += JSON.stringify(item);
          arrayBody += '\n';
        });

        bodyCopy = arrayBody;
      } else {
        bodyCopy = JSON.stringify(bodyCopy) || {};
      }

      if (Object.keys(bodyCopy).length !== 0) {
        requestOptions.body = bodyCopy;
      }

      let finalRequest = requestOptions;
      if (this.transformRequest) {
        finalRequest = this.transformRequest(requestOptions);
      }
      let responseHeaders = {};
      return fetch(
        `${this.protocol}://${this.url}/${this.app}/${path}?${querystring.stringify(params)}`,
        finalRequest,
      ).then((res) => {
        if (res.status >= 500) {
          return reject(res);
        }
        responseHeaders = res.headers;
        return res.json().then((data) => {
          if (res.status >= 400) {
            return reject(res);
          }
          const response = Object.assign({}, data, {
            _timestamp: timestamp,
            _headers: responseHeaders,
          });
          return resolve(response);
        });
      }).catch(e => reject(e));
    } catch (e) {
      return reject(e);
    }
  });
}
export default fetchRequest;
<|endoftext|>