<commit_before>/* Copyright 2015 Bloomberg Finance L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var d3 = require("d3");
var _ = require("underscore");
var markmodel = require("./MarkModel");

var ScatterBaseModel = markmodel.MarkModel.extend({

    defaults: _.extend({}, markmodel.MarkModel.prototype.defaults, {
        _model_name: "ScatterBaseModel",
        _view_name: "ScatterBase",

        x: [],
        y: [],
        color: null,
        opacity: null,
        size: null,
        rotation: null,
        hovered_point: null,
        scales_metadata: {
            x: { orientation: "horizontal", dimension: "x" },
            y: { orientation: "vertical", dimension: "y" },
            color: { dimension: "color" },
            size: { dimension: "size" },
            opacity: { dimension: "opacity" }
        },
        colors: [],
        default_opacities: [],
        enable_move: false,
        enable_delete: false,
        restrict_x: false,
        restrict_y: false,
        update_on_move: false
    }),

    initialize: function() {
        // TODO: Normally, color, opacity and size should not require a redraw
        ScatterBaseModel.__super__.initialize.apply(this, arguments);
        this.on_some_change(["x", "y", "color", "opacity", "size", "rotation"], this.update_data, this);
        // FIXME: replace this with on("change:preserve_domain"). It is not done here because
        // on_some_change depends on the GLOBAL backbone on("change") handler which
        // is called AFTER the specific handlers on("change:foobar") and we make that
        // assumption.
        this.on_some_change(["preserve_domain"], this.update_domains, this);
        this.update_data();
    },

    update_mark_data: function() {
        var x_data = this.get_typed_field("x"),
            y_data = this.get_typed_field("y"),
            scales = this.get("scales"),
            x_scale = scales.x,
            y_scale = scales.y,
            color_scale = scales.color;

        if (x_data.length === 0 || y_data.length === 0) {
            this.mark_data = [];
        } else {
            //FIXME:Temporary fix to avoid misleading NaN error due to X and Y
            //being of different lengths. In particular, if Y is of a smaller
            //length, throws an error on the JS side
            var min_len = Math.min(x_data.length, y_data.length);
            x_data = x_data.slice(0, min_len);
            var color = this.get_typed_field("color"),
                size = this.get_typed_field("size"),
                opacity = this.get_typed_field("opacity"),
                rotation = this.get_typed_field("rotation");

            if(color_scale) {
                if(!this.get("preserve_domain").color) {
                    color_scale.compute_and_set_domain(color, this.id + "_color");
                } else {
                    color_scale.del_domain([], this.id + "_color");
                }
            }

            this.mark_data = x_data.map(function(d, i) {
                return {
                    x: d,
                    y: y_data[i],
                    color: color[i],
                    size: size[i],
                    opacity: opacity[i],
                    rotation: rotation[i],
                    index: i
                };
            });
        }
    },

    update_data: function() {
        this.dirty = true;
        this.update_mark_data();
        this.update_unique_ids();
        this.update_domains();
        this.dirty = false;
        this.trigger("data_updated");
    },

    update_unique_ids: function() {},

    get_data_dict: function(data, index) {
        return data;
    },

    update_domains: function() {
        if (!this.mark_data) {
            return;
        }
        // color scale needs an issue in DateScaleModel to be fixed. It
        // should be moved here as soon as that is fixed.

       var scales = this.get("scales");
       for (var key in scales) {
            if(scales.hasOwnProperty(key) && key != "color") {
                var scale = scales[key];
                if(!this.get("preserve_domain")[key]) {
                    scale.compute_and_set_domain(this.mark_data.map(function(elem) {
                        return elem[key];
                    }), this.id + key);
                } else {
                    scale.del_domain([], this.id + key);
                }
            }
       }
    }
});

module.exports = {
    ScatterBaseModel: ScatterBaseModel
};
<commit_msg>defaults bug<commit_after>/* Copyright 2015 Bloomberg Finance L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var d3 = require("d3");
var _ = require("underscore");
var markmodel = require("./MarkModel");

var ScatterBaseModel = markmodel.MarkModel.extend({

    defaults: function() {
        return _.extend({}, markmodel.MarkModel.prototype.defaults, {
        _model_name: "ScatterBaseModel",
        _view_name: "ScatterBase",

        x: [],
        y: [],
        color: null,
        opacity: null,
        size: null,
        rotation: null,
        hovered_point: null,
        scales_metadata: {
            x: { orientation: "horizontal", dimension: "x" },
            y: { orientation: "vertical", dimension: "y" },
            color: { dimension: "color" },
            size: { dimension: "size" },
            opacity: { dimension: "opacity" }
        },
        colors: [],
        default_opacities: [],
        enable_move: false,
        enable_delete: false,
        restrict_x: false,
        restrict_y: false,
        update_on_move: false
        });
    },

    initialize: function() {
        // TODO: Normally, color, opacity and size should not require a redraw
        ScatterBaseModel.__super__.initialize.apply(this, arguments);
        this.on_some_change(["x", "y", "color", "opacity", "size", "rotation"], this.update_data, this);
        // FIXME: replace this with on("change:preserve_domain"). It is not done here because
        // on_some_change depends on the GLOBAL backbone on("change") handler which
        // is called AFTER the specific handlers on("change:foobar") and we make that
        // assumption.
        this.on_some_change(["preserve_domain"], this.update_domains, this);
        this.update_data();
    },

    update_mark_data: function() {
        var x_data = this.get_typed_field("x"),
            y_data = this.get_typed_field("y"),
            scales = this.get("scales"),
            x_scale = scales.x,
            y_scale = scales.y,
            color_scale = scales.color;

        if (x_data.length === 0 || y_data.length === 0) {
            this.mark_data = [];
        } else {
            //FIXME:Temporary fix to avoid misleading NaN error due to X and Y
            //being of different lengths. In particular, if Y is of a smaller
            //length, throws an error on the JS side
            var min_len = Math.min(x_data.length, y_data.length);
            x_data = x_data.slice(0, min_len);
            var color = this.get_typed_field("color"),
                size = this.get_typed_field("size"),
                opacity = this.get_typed_field("opacity"),
                rotation = this.get_typed_field("rotation");

            if(color_scale) {
                if(!this.get("preserve_domain").color) {
                    color_scale.compute_and_set_domain(color, this.id + "_color");
                } else {
                    color_scale.del_domain([], this.id + "_color");
                }
            }

            this.mark_data = x_data.map(function(d, i) {
                return {
                    x: d,
                    y: y_data[i],
                    color: color[i],
                    size: size[i],
                    opacity: opacity[i],
                    rotation: rotation[i],
                    index: i
                };
            });
        }
    },

    update_data: function() {
        this.dirty = true;
        this.update_mark_data();
        this.update_unique_ids();
        this.update_domains();
        this.dirty = false;
        this.trigger("data_updated");
    },

    update_unique_ids: function() {},

    get_data_dict: function(data, index) {
        return data;
    },

    update_domains: function() {
        if (!this.mark_data) {
            return;
        }
        // color scale needs an issue in DateScaleModel to be fixed. It
        // should be moved here as soon as that is fixed.

       var scales = this.get("scales");
       for (var key in scales) {
            if(scales.hasOwnProperty(key) && key != "color") {
                var scale = scales[key];
                if(!this.get("preserve_domain")[key]) {
                    scale.compute_and_set_domain(this.mark_data.map(function(elem) {
                        return elem[key];
                    }), this.id + key);
                } else {
                    scale.del_domain([], this.id + key);
                }
            }
       }
    }
});

module.exports = {
    ScatterBaseModel: ScatterBaseModel
};
<|endoftext|>


<commit_before>export {
  version
} from "./package.json";

export {
  bisect,
  bisectRight,
  bisectLeft,
  ascending,
  bisector,
  descending,
  deviation,
  extent,
  histogram,
  thresholdFreedmanDiaconis,
  thresholdScott,
  thresholdSturges,
  max,
  mean,
  median,
  merge,
  min,
  pairs,
  permute,
  quantile,
  range,
  scan,
  shuffle,
  sum,
  ticks,
  transpose,
  variance,
  zip
} from "d3-array";

export {
  entries,
  keys,
  values,
  map,
  set,
  nest
} from "d3-collection";

export {
  randomUniform,
  randomNormal,
  randomLogNormal,
  randomBates,
  randomIrwinHall,
  randomExponential
} from "d3-random";

export {
  easeLinearIn,
  easeLinearOut,
  easeLinearInOut,
  easeQuadIn,
  easeQuadOut,
  easeQuadInOut,
  easeCubicIn,
  easeCubicOut,
  easeCubicInOut,
  easePolyIn,
  easePolyOut,
  easePolyInOut,
  easeSinIn,
  easeSinOut,
  easeSinInOut,
  easeExpIn,
  easeExpOut,
  easeExpInOut,
  easeCircleIn,
  easeCircleOut,
  easeCircleInOut,
  easeBounceIn,
  easeBounceOut,
  easeBounceInOut,
  easeBackIn,
  easeBackOut,
  easeBackInOut,
  easeElasticIn,
  easeElasticOut,
  easeElasticInOut
} from "d3-ease";

export {
  polygonArea,
  polygonCentroid,
  polygonHull,
  polygonContains,
  polygonLength
} from "d3-polygon";

export {
  path
} from "d3-path";

export {
  quadtree
} from "d3-quadtree";

export {
  queue
} from "d3-queue";

export {
  arc,
  area,
  line,
  pie,
  radialArea,
  radialLine,
  symbol,
  symbols,
  symbolCircle,
  symbolCross,
  symbolDiamond,
  symbolSquare,
  symbolStar,
  symbolTriangle,
  symbolWye,
  curveBasisClosed,
  curveBasisOpen,
  curveBasis,
  curveBundle,
  curveCardinalClosed,
  curveCardinalOpen,
  curveCardinal,
  curveCatmullRomClosed,
  curveCatmullRomOpen,
  curveCatmullRom,
  curveLinearClosed,
  curveLinear,
  curveMonotoneX,
  curveMonotoneY,
  curveNatural,
  curveStep,
  curveStepAfter,
  curveStepBefore,
  stack,
  stackOffsetExpand,
  stackOffsetNone,
  stackOffsetSilhouette,
  stackOffsetWiggle,
  stackOrderAscending,
  stackOrderDescending,
  stackOrderInsideOut,
  stackOrderNone,
  stackOrderReverse
} from "d3-shape"

export {
  color,
  rgb,
  hsl,
  lab,
  hcl,
  cubehelix
} from "d3-color";

export {
  interpolate,
  interpolators,
  interpolateArray,
  interpolateNumber,
  interpolateObject,
  interpolateRound,
  interpolateString,
  interpolateTransform,
  interpolateZoom,
  interpolateRgb,
  interpolateHsl,
  interpolateHslLong,
  interpolateLab,
  interpolateHcl,
  interpolateHclLong,
  interpolateCubehelix,
  interpolateCubehelixLong
} from "d3-interpolate";

export {
  dispatch
} from "d3-dispatch";

export {
  dsv,
  csv,
  tsv
} from "d3-dsv";

export {
  request,
  requestHtml,
  requestJson,
  requestText,
  requestXml,
  requestCsv,
  requestTsv
} from "d3-request";

export {
  timer,
  timerFlush
} from "d3-timer";

export {
  timeInterval,
  timeMillisecond,
  timeMilliseconds,
  timeSecond,
  timeSeconds,
  timeMinute,
  timeMinutes,
  timeHour,
  timeHours,
  timeDay,
  timeDays,
  timeWeek,
  timeWeeks,
  timeSunday,
  timeSundays,
  timeMonday,
  timeMondays,
  timeTuesday,
  timeTuesdays,
  timeWednesday,
  timeWednesdays,
  timeThursday,
  timeThursdays,
  timeFriday,
  timeFridays,
  timeSaturday,
  timeSaturdays,
  timeMonth,
  timeMonths,
  timeYear,
  timeYears,
  utcMillisecond,
  utcMilliseconds,
  utcSecond,
  utcSeconds,
  utcMinute,
  utcMinutes,
  utcHour,
  utcHours,
  utcDay,
  utcDays,
  utcWeek,
  utcWeeks,
  utcSunday,
  utcSundays,
  utcMonday,
  utcMondays,
  utcTuesday,
  utcTuesdays,
  utcWednesday,
  utcWednesdays,
  utcThursday,
  utcThursdays,
  utcFriday,
  utcFridays,
  utcSaturday,
  utcSaturdays,
  utcMonth,
  utcMonths,
  utcYear,
  utcYears
} from "d3-time";

export {
  format,
  formatPrefix,
  formatLocale,
  formatCaEs,
  formatCsCz,
  formatDeCh,
  formatDeDe,
  formatEnCa,
  formatEnGb,
  formatEnUs,
  formatEsEs,
  formatFiFi,
  formatFrCa,
  formatFrFr,
  formatHeIl,
  formatHuHu,
  formatItIt,
  formatJaJp,
  formatKoKr,
  formatMkMk,
  formatNlNl,
  formatPlPl,
  formatPtBr,
  formatRuRu,
  formatSvSe,
  formatZhCn,
  formatSpecifier,
  precisionFixed,
  precisionPrefix,
  precisionRound
} from "d3-format";

export {
  timeFormat,
  timeParse,
  utcFormat,
  utcParse,
  isoFormat,
  isoParse,
  timeFormatLocale,
  timeFormatCaEs,
  timeFormatDeCh,
  timeFormatDeDe,
  timeFormatEnCa,
  timeFormatEnGb,
  timeFormatEnUs,
  timeFormatEsEs,
  timeFormatFiFi,
  timeFormatFrCa,
  timeFormatFrFr,
  timeFormatHeIl,
  timeFormatHuHu,
  timeFormatItIt,
  timeFormatJaJp,
  timeFormatKoKr,
  timeFormatMkMk,
  timeFormatNlNl,
  timeFormatPlPl,
  timeFormatPtBr,
  timeFormatRuRu,
  timeFormatSvSe,
  timeFormatZhCn
} from "d3-time-format";

export {
  scaleBand,
  scalePoint,
  scaleIdentity,
  scaleLinear,
  scaleLog,
  scaleOrdinal,
  scaleImplicit,
  scalePow,
  scaleSqrt,
  scaleQuantile,
  scaleQuantize,
  scaleThreshold,
  scaleTime,
  scaleUtc,
  scaleCategory10,
  scaleCategory20b,
  scaleCategory20c,
  scaleCategory20,
  scaleCubehelix,
  scaleRainbow,
  scaleWarm,
  scaleCool,
  scaleViridis,
  scaleMagma,
  scaleInferno,
  scalePlasma
} from "d3-scale";

export {
  mouse,
  namespace,
  namespaces,
  select,
  selectAll,
  selection,
  touch,
  touches,
  event
} from "d3-selection";

export {
  axisTop,
  axisRight,
  axisBottom,
  axisLeft
} from "d3-axis";

export {
  voronoi
} from "d3-voronoi";
<commit_msg>Expose d3.timerOnce.<commit_after>export {
  version
} from "./package.json";

export {
  bisect,
  bisectRight,
  bisectLeft,
  ascending,
  bisector,
  descending,
  deviation,
  extent,
  histogram,
  thresholdFreedmanDiaconis,
  thresholdScott,
  thresholdSturges,
  max,
  mean,
  median,
  merge,
  min,
  pairs,
  permute,
  quantile,
  range,
  scan,
  shuffle,
  sum,
  ticks,
  transpose,
  variance,
  zip
} from "d3-array";

export {
  entries,
  keys,
  values,
  map,
  set,
  nest
} from "d3-collection";

export {
  randomUniform,
  randomNormal,
  randomLogNormal,
  randomBates,
  randomIrwinHall,
  randomExponential
} from "d3-random";

export {
  easeLinearIn,
  easeLinearOut,
  easeLinearInOut,
  easeQuadIn,
  easeQuadOut,
  easeQuadInOut,
  easeCubicIn,
  easeCubicOut,
  easeCubicInOut,
  easePolyIn,
  easePolyOut,
  easePolyInOut,
  easeSinIn,
  easeSinOut,
  easeSinInOut,
  easeExpIn,
  easeExpOut,
  easeExpInOut,
  easeCircleIn,
  easeCircleOut,
  easeCircleInOut,
  easeBounceIn,
  easeBounceOut,
  easeBounceInOut,
  easeBackIn,
  easeBackOut,
  easeBackInOut,
  easeElasticIn,
  easeElasticOut,
  easeElasticInOut
} from "d3-ease";

export {
  polygonArea,
  polygonCentroid,
  polygonHull,
  polygonContains,
  polygonLength
} from "d3-polygon";

export {
  path
} from "d3-path";

export {
  quadtree
} from "d3-quadtree";

export {
  queue
} from "d3-queue";

export {
  arc,
  area,
  line,
  pie,
  radialArea,
  radialLine,
  symbol,
  symbols,
  symbolCircle,
  symbolCross,
  symbolDiamond,
  symbolSquare,
  symbolStar,
  symbolTriangle,
  symbolWye,
  curveBasisClosed,
  curveBasisOpen,
  curveBasis,
  curveBundle,
  curveCardinalClosed,
  curveCardinalOpen,
  curveCardinal,
  curveCatmullRomClosed,
  curveCatmullRomOpen,
  curveCatmullRom,
  curveLinearClosed,
  curveLinear,
  curveMonotoneX,
  curveMonotoneY,
  curveNatural,
  curveStep,
  curveStepAfter,
  curveStepBefore,
  stack,
  stackOffsetExpand,
  stackOffsetNone,
  stackOffsetSilhouette,
  stackOffsetWiggle,
  stackOrderAscending,
  stackOrderDescending,
  stackOrderInsideOut,
  stackOrderNone,
  stackOrderReverse
} from "d3-shape"

export {
  color,
  rgb,
  hsl,
  lab,
  hcl,
  cubehelix
} from "d3-color";

export {
  interpolate,
  interpolators,
  interpolateArray,
  interpolateNumber,
  interpolateObject,
  interpolateRound,
  interpolateString,
  interpolateTransform,
  interpolateZoom,
  interpolateRgb,
  interpolateHsl,
  interpolateHslLong,
  interpolateLab,
  interpolateHcl,
  interpolateHclLong,
  interpolateCubehelix,
  interpolateCubehelixLong
} from "d3-interpolate";

export {
  dispatch
} from "d3-dispatch";

export {
  dsv,
  csv,
  tsv
} from "d3-dsv";

export {
  request,
  requestHtml,
  requestJson,
  requestText,
  requestXml,
  requestCsv,
  requestTsv
} from "d3-request";

export {
  timer,
  timerOnce,
  timerFlush
} from "d3-timer";

export {
  timeInterval,
  timeMillisecond,
  timeMilliseconds,
  timeSecond,
  timeSeconds,
  timeMinute,
  timeMinutes,
  timeHour,
  timeHours,
  timeDay,
  timeDays,
  timeWeek,
  timeWeeks,
  timeSunday,
  timeSundays,
  timeMonday,
  timeMondays,
  timeTuesday,
  timeTuesdays,
  timeWednesday,
  timeWednesdays,
  timeThursday,
  timeThursdays,
  timeFriday,
  timeFridays,
  timeSaturday,
  timeSaturdays,
  timeMonth,
  timeMonths,
  timeYear,
  timeYears,
  utcMillisecond,
  utcMilliseconds,
  utcSecond,
  utcSeconds,
  utcMinute,
  utcMinutes,
  utcHour,
  utcHours,
  utcDay,
  utcDays,
  utcWeek,
  utcWeeks,
  utcSunday,
  utcSundays,
  utcMonday,
  utcMondays,
  utcTuesday,
  utcTuesdays,
  utcWednesday,
  utcWednesdays,
  utcThursday,
  utcThursdays,
  utcFriday,
  utcFridays,
  utcSaturday,
  utcSaturdays,
  utcMonth,
  utcMonths,
  utcYear,
  utcYears
} from "d3-time";

export {
  format,
  formatPrefix,
  formatLocale,
  formatCaEs,
  formatCsCz,
  formatDeCh,
  formatDeDe,
  formatEnCa,
  formatEnGb,
  formatEnUs,
  formatEsEs,
  formatFiFi,
  formatFrCa,
  formatFrFr,
  formatHeIl,
  formatHuHu,
  formatItIt,
  formatJaJp,
  formatKoKr,
  formatMkMk,
  formatNlNl,
  formatPlPl,
  formatPtBr,
  formatRuRu,
  formatSvSe,
  formatZhCn,
  formatSpecifier,
  precisionFixed,
  precisionPrefix,
  precisionRound
} from "d3-format";

export {
  timeFormat,
  timeParse,
  utcFormat,
  utcParse,
  isoFormat,
  isoParse,
  timeFormatLocale,
  timeFormatCaEs,
  timeFormatDeCh,
  timeFormatDeDe,
  timeFormatEnCa,
  timeFormatEnGb,
  timeFormatEnUs,
  timeFormatEsEs,
  timeFormatFiFi,
  timeFormatFrCa,
  timeFormatFrFr,
  timeFormatHeIl,
  timeFormatHuHu,
  timeFormatItIt,
  timeFormatJaJp,
  timeFormatKoKr,
  timeFormatMkMk,
  timeFormatNlNl,
  timeFormatPlPl,
  timeFormatPtBr,
  timeFormatRuRu,
  timeFormatSvSe,
  timeFormatZhCn
} from "d3-time-format";

export {
  scaleBand,
  scalePoint,
  scaleIdentity,
  scaleLinear,
  scaleLog,
  scaleOrdinal,
  scaleImplicit,
  scalePow,
  scaleSqrt,
  scaleQuantile,
  scaleQuantize,
  scaleThreshold,
  scaleTime,
  scaleUtc,
  scaleCategory10,
  scaleCategory20b,
  scaleCategory20c,
  scaleCategory20,
  scaleCubehelix,
  scaleRainbow,
  scaleWarm,
  scaleCool,
  scaleViridis,
  scaleMagma,
  scaleInferno,
  scalePlasma
} from "d3-scale";

export {
  mouse,
  namespace,
  namespaces,
  select,
  selectAll,
  selection,
  touch,
  touches,
  event
} from "d3-selection";

export {
  axisTop,
  axisRight,
  axisBottom,
  axisLeft
} from "d3-axis";

export {
  voronoi
} from "d3-voronoi";
<|endoftext|>


<commit_before><commit_msg>created constants for blocks and inline<commit_after>export const Block = {
    UNSTYLED: 'unstyled',
    PARAGRAPH: 'unstyled',
    OL: 'ordered-list-item',
    UL: 'unordered-list-item',
    H1: 'header-one',
    H2: 'header-two',
    H3: 'header-three',
    H4: 'header-four',
    H5: 'header-five',
    H6: 'header-six',
    CODE: 'code-block',
    BLOCKQUOTE: 'blockquote',
    PULLQUOTE: 'pullquote',
    ATOMIC: 'atomic',
    BLOCKQUOTE_CAPTION: 'block-quote-caption',
    CAPTION: 'caption',
    TODO: 'todo',
    IMAGE: 'atomic:image',
    BREAK: 'atomic:break'
};

export const Inline = {
    BOLD: 'BOLD',
    CODE: 'CODE',
    ITALIC: 'ITALIC',
    STRIKETHROUGH: 'STRIKETHROUGH',
    UNDERLINE: 'UNDERLINE',
    HIGHLIGHT: 'HIGHLIGHT'
};
<|endoftext|>


<commit_before>(function(window, angular, Bitcoin) {
    'use strict';

    angular.module('bitcoin')
        .factory('bitloxTransaction', TransactionFactory);

    TransactionFactory.$inject = ['hexUtil', 'DEFAULT_FEE', 'MIN_OUTPUT'];

    function TransactionFactory(hexUtil, DEFAULT_FEE, MIN_OUTPUT) {

        var ERR_INVALID_FEE          = Transaction.ERR_INVALID_FEE         = "Invalid fee";
        var ERR_NO_OUTPUTS           = Transaction.ERR_NO_OUTPUTS          = "No outputs";
        var ERR_INVALID_AMOUNT       = Transaction.ERR_INVALID_AMOUNT      = "Invalid amount";
        var ERR_AMOUNT_TOO_LOW       = Transaction.ERR_AMOUNT_TOO_LOW      = "Amount must be greater than " + MIN_OUTPUT;
        var ERR_NO_INPUTS            = Transaction.ERR_NO_INPUTS           = "Missing input array";
        var ERR_NO_CHANGE_ADDRESS    = Transaction.ERR_NO_CHANGE_ADDRESS   = "Missing change address";
        var ERR_INSUFFICIENT_INPUTS  = Transaction.ERR_INSUFFICIENT_INPUTS = "Not enough inputs";
        var ERR_BAD_SIGNED_SCRIPTS   = Transaction.ERR_BAD_SIGNED_SCRIPTS  = "Invalid signed scripts";

        function Transaction(options) {
            var fee = this.fee = options.fee === undefined ? DEFAULT_FEE : parseInt(options.fee, 10);
            if (isNaN(fee) || fee < 0) {
                throw ERR_INVALID_FEE;
            }
            options.forceSmallChange = true
            var outputs = this.outputs = options.outputs;
            // dave says no more of this, we let the BWS choose
            // if (!outputs) {
            //     // if no outputs in the options, look for "to" and
            //     // "amount" and make an output object
            //     var to = options.to;
            //     if (!to) {
            //         throw ERR_NO_OUTPUTS;
            //     }
            //     var amount = parseInt(options.amount, 10);
            //     if (isNaN(amount)) {
            //         throw ERR_INVALID_AMOUNT;
            //     }
            //     outputs = this.outputs = [{
            //         address: to,
            //         amount: amount
            //     }];
            // }
            // if (!Array.isArray(outputs)) {
            //     outputs = [outputs];
            // }
            // var inputs = options.inputs;
            // if (!inputs || !Array.isArray(inputs)) {
            //     throw ERR_NO_INPUTS;
            // }
            // sort inputs by most to least confirmations
            // dave says no more of this, we let the server choose and sort inputs now
            // inputs.sort(function(a, b) {
            //     return a.confirmations > b.confirmations ? -1 : 1;
            // });
            var changeAddress = this.changeAddress = options.changeAddress.address;
            if (!changeAddress) {
                throw ERR_NO_CHANGE_ADDRESS;
            }

            // make a new transaction
            this.tx = new Bitcoin.Transaction();
            // initialize total out and in
            this.totalOut = 0;
            this.totalIn = 0;
            // set up empty input array on 'this', it gets filled with
            // the inputs we actually use on calling addInputs
            this.inputs = [];
            // now add the outputs
            this.addOutputs(outputs);
            // set the target amount
            this.target = this.totalOut + this.fee;
            // then add inputs
            var change = this.changeAmount = this.addInputs(inputs);
            console.log(inputs)
            console.log(outputs)
            console.log(change + ' change')
            if (change < 0) {
                // if change is less than 0, out inputs were not enough to
                // cover the outputs
                throw ERR_INSUFFICIENT_INPUTS;
            } else if (change > 0 && change < MIN_OUTPUT) {
                if (options.forceSmallChange) {
                    this.addOutput({
                        toAddress: changeAddress,
                        amount: change
                    }, 'force it');
                } else {
                    throw {
                        change: change
                    };
                }
            } else if (change > 0) {
                // if greater than 0, then we have change left over,
                // send it to the change address provided
                this.addOutput({
                    toAddress: changeAddress,
                    amount: change
                });
            }
            // set the unsigned tx to this instance
            this.unsignedHex = Bitcoin.Util.bytesToHex(this.tx.serialize());
            console.debug("transaction assembled", this);
        }

        // add outputs will take the outputs for our API and convert
        // them to the bitcoinjs API and add them to the transaction.
        // return the total of the output values we encountered this
        // run

        Transaction.prototype.addOutputs = function(outputs) {
            outputs.forEach(this.addOutput, this);
        };

        Transaction.prototype.addOutput = function(output, forceSmall) {
            var amount = parseInt(output.amount, 10);
            if (isNaN(amount)) {
                throw ERR_INVALID_AMOUNT;
            }
            if (amount < MIN_OUTPUT && !forceSmall) {
                throw ERR_AMOUNT_TOO_LOW;
            }
            this.totalOut += amount;
            var address = output.toAddress;
            var bcAddr = new Bitcoin.Address(address);
            var bcOut = new Bitcoin.TransactionOut({
                value: hexUtil.intToBigEndianValue(amount, 8),
                script: Bitcoin.Script.createOutputScript(bcAddr)
            });
            this.tx.addOutput(bcOut);
        };

        // add inputs will take the inputs for our API and convert
        // them to the bitcoinjs API and add them to the transaction.
        // add all inputs we use to the 'inputs' array on our
        // Transaction instance

        // return the remainder to send to change
        Transaction.prototype.addInputs = function(inputs) {
            inputs.forEach(this.addInput, this);
            return this.totalIn - this.target;
        };

        Transaction.prototype.addInput = function(input) {
            // if we have all the inputs we need to cover the
            // output and the fee, just move on
            if (this.totalIn >= this.target) {
                return;
            }
            if (input.confirmations < 1) {
                return;
            }
            var amount = parseInt(input.satoshis, 10);
            if (isNaN(amount)) {
                throw ERR_INVALID_AMOUNT;
            }
            var hash = Bitcoin.Util.bytesToBase64(Bitcoin.Util.hexToBytes(input.txid));
            var script = Bitcoin.Util.hexToBytes(input.scriptPubKey);
            var bcIn = new Bitcoin.TransactionIn({
                outpoint: {
                    hash: hash,
                    index: input.vout
                },
                script: script,
                sequence: 4294967295
            });
            this.tx.addInput(bcIn);
            // add some more info to the input object here
            this.inputs.push(input);
            this.totalIn += amount;
        };

        Transaction.prototype.replaceScripts = function(signedScripts) {
            if (!Array.isArray(signedScripts)) {
                throw ERR_BAD_SIGNED_SCRIPTS;
            }
            if (signedScripts.length !== this.inputs.length) {
                throw ERR_BAD_SIGNED_SCRIPTS;
            }
            var hex = this.unsignedHex;
            this.inputs.forEach(function(input, index) {
                hex = hex.replace('19' + input.script, signedScripts[index]);
            });
            this.signedHex = hex;
            return hex;
        };

        return Transaction;
    }

})(window, window.angular, window.Bitcoin);
<commit_msg>oooooh, i am dumb<commit_after><|endoftext|>


<commit_before>$(function () {
  'use strict';

  module('scrollspy plugin')

  test('should be defined on jquery object', function () {
    ok($(document.body).scrollspy, 'scrollspy method is defined')
  })

  module('scrollspy', {
    setup: function () {
      // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
      $.fn.bootstrapScrollspy = $.fn.scrollspy.noConflict()
    },
    teardown: function () {
      $.fn.scrollspy = $.fn.bootstrapScrollspy
      delete $.fn.bootstrapScrollspy
    }
  })

  test('should provide no conflict', function () {
    strictEqual($.fn.scrollspy, undefined, 'scrollspy was set back to undefined (org value)')
  })

  test('should return jquery collection containing the element', function () {
    var $el = $('
')
    var $scrollspy = $el.bootstrapScrollspy()
    ok($scrollspy instanceof $, 'returns jquery collection')
    strictEqual($scrollspy[0], $el[0], 'collection contains element')
  })

  // Does not work properly ATM, #13500 will fix this
  test('should switch "active" class on scroll', function () {
    var topbarHTML = '
'
        + '
'
        + '
'
        + '
Bootstrap
'
        + '
Overview
'
        + '
'
        + '
'
        + '
'
        + '
'
    var $topbar = $(topbarHTML).bootstrapScrollspy()

    ok($topbar.find('.active', true))
  })

  test('should only switch "active" class on current target', function () {
    stop()

    var sectionHTML = '
'
        + '
'
        + '
'
        + '
'
        + '
'
        + '
Overview
'
        + '
Detail
'
        + '
'
        + '
'
        + '
'
        + '
'
        + '
'
        + '
'
        + '
Overview
'
        + '
'
        + 'Ad leggings keytar, brunch id art party dolor labore.'
        + '
'
        + '
'
        + '
'
        + '
Detail
'
        + '
'
        + 'Veniam marfa mustache skateboard, adipisicing fugiat velit pitchfork beard.'
        + '
'
        + '
'
        + '
'
        + '
'
    var $section = $(sectionHTML).appendTo('#qunit-fixture')

    var $scrollspy = $section
        .show()
        .find('#scrollspy-example')
        .bootstrapScrollspy({ target: '#ss-target' })

    $scrollspy.on('scroll.bs.scrollspy', function () {
      ok($section.hasClass('active'), '"active" class still on root node')
      start()
    })

    $scrollspy.scrollTop(350)
  })

  test('middle navigation option correctly selected when large offset is used', function () {
    stop()

    var sectionHTML = '

'
        + ''
        + '
'
        + '
One
'
        + '
Two
'
        + '
Three
'
        + '
'
        + ''
        + '
'
        + '

'
        + '

'
        + '

'
        + '
'
    var $section = $(sectionHTML).appendTo('#qunit-fixture')
    var $scrollspy = $section
        .show()
        .filter('#content')

    $scrollspy.bootstrapScrollspy({ target: '#navigation', offset: $scrollspy.position().top })

    $scrollspy.on('scroll.bs.scrollspy', function () {
      ok(!$section.find('#one-link').parent().hasClass('active'), '"active" class removed from first section')
      ok($section.find('#two-link').parent().hasClass('active'), '"active" class on middle section')
      ok(!$section.find('#three-link').parent().hasClass('active'), '"active" class not on last section')
      start()
    })

    $scrollspy.scrollTop(550)
  })

  test('should add the active class to the correct element', function () {
    var navbarHtml =
        ''
      + '
'
      + '
div 1
'
      + '
div 2
'
      + '
'
      + ''
    var contentHtml =
        '
'
      + '
div 1
'
      + '
div 2
'
      + '
'

    $(navbarHtml).appendTo('#qunit-fixture')
    var $content = $(contentHtml)
      .appendTo('#qunit-fixture')
      .bootstrapScrollspy({ offset: 0, target: '.navbar' })

    var testElementIsActiveAfterScroll = function (element, target) {
      var deferred = $.Deferred()
      var scrollHeight = Math.ceil($content.scrollTop() + $(target).position().top)
      stop()
      $content.one('scroll', function () {
        ok($(element).hasClass('active'), 'target:' + target + ', element' + element)
        start()
        deferred.resolve()
      })
      $content.scrollTop(scrollHeight)
      return deferred.promise()
    }

    $.when(testElementIsActiveAfterScroll('#li-1', '#div-1'))
      .then(function () { return testElementIsActiveAfterScroll('#li-2', '#div-2') })
  })

})
<commit_msg>Small clean-up in scrollspy unit test<commit_after>$(function () {
  'use strict';

  module('scrollspy plugin')

  test('should be defined on jquery object', function () {
    ok($(document.body).scrollspy, 'scrollspy method is defined')
  })

  module('scrollspy', {
    setup: function () {
      // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
      $.fn.bootstrapScrollspy = $.fn.scrollspy.noConflict()
    },
    teardown: function () {
      $.fn.scrollspy = $.fn.bootstrapScrollspy
      delete $.fn.bootstrapScrollspy
    }
  })

  test('should provide no conflict', function () {
    strictEqual($.fn.scrollspy, undefined, 'scrollspy was set back to undefined (org value)')
  })

  test('should return jquery collection containing the element', function () {
    var $el = $('
')
    var $scrollspy = $el.bootstrapScrollspy()
    ok($scrollspy instanceof $, 'returns jquery collection')
    strictEqual($scrollspy[0], $el[0], 'collection contains element')
  })

  test('should only switch "active" class on current target', function () {
    stop()

    var sectionHTML = '
'
        + '
'
        + '
'
        + '
'
        + '
'
        + '
Overview
'
        + '
Detail
'
        + '
'
        + '
'
        + '
'
        + '
'
        + '
'
        + '
'
        + '
Overview
'
        + '
'
        + 'Ad leggings keytar, brunch id art party dolor labore.'
        + '
'
        + '
'
        + '
'
        + '
Detail
'
        + '
'
        + 'Veniam marfa mustache skateboard, adipisicing fugiat velit pitchfork beard.'
        + '
'
        + '
'
        + '
'
        + '
'
    var $section = $(sectionHTML).appendTo('#qunit-fixture')

    var $scrollspy = $section
      .show()
      .find('#scrollspy-example')
      .bootstrapScrollspy({ target: '#ss-target' })

    $scrollspy.on('scroll.bs.scrollspy', function () {
      ok($section.hasClass('active'), '"active" class still on root node')
      start()
    })

    $scrollspy.scrollTop(350)
  })

  test('middle navigation option correctly selected when large offset is used', function () {
    stop()

    var sectionHTML = '

'
        + ''
        + '
'
        + '
One
'
        + '
Two
'
        + '
Three
'
        + '
'
        + ''
        + '
'
        + '

'
        + '

'
        + '

'
        + '
'
    var $section = $(sectionHTML).appendTo('#qunit-fixture')
    var $scrollspy = $section
      .show()
      .filter('#content')

    $scrollspy.bootstrapScrollspy({ target: '#navigation', offset: $scrollspy.position().top })

    $scrollspy.on('scroll.bs.scrollspy', function () {
      ok(!$section.find('#one-link').parent().hasClass('active'), '"active" class removed from first section')
      ok($section.find('#two-link').parent().hasClass('active'), '"active" class on middle section')
      ok(!$section.find('#three-link').parent().hasClass('active'), '"active" class not on last section')
      start()
    })

    $scrollspy.scrollTop(550)
  })

  test('should add the active class to the correct element', function () {
    var navbarHtml =
        ''
      + '
'
      + '
div 1
'
      + '
div 2
'
      + '
'
      + ''
    var contentHtml =
        '
'
      + '
div 1
'
      + '
div 2
'
      + '
'

    $(navbarHtml).appendTo('#qunit-fixture')
    var $content = $(contentHtml)
      .appendTo('#qunit-fixture')
      .bootstrapScrollspy({ offset: 0, target: '.navbar' })

    var testElementIsActiveAfterScroll = function (element, target) {
      var deferred = $.Deferred()
      var scrollHeight = Math.ceil($content.scrollTop() + $(target).position().top)
      stop()
      $content.one('scroll', function () {
        ok($(element).hasClass('active'), 'target:' + target + ', element' + element)
        start()
        deferred.resolve()
      })
      $content.scrollTop(scrollHeight)
      return deferred.promise()
    }

    $.when(testElementIsActiveAfterScroll('#li-1', '#div-1'))
      .then(function () { return testElementIsActiveAfterScroll('#li-2', '#div-2') })
  })

})
<|endoftext|>


<commit_before>var swiper = require('swiper');
var dialog = require('dialog-component');
var extend = require('deep-extend');
var domify = require('domify');
var css = require('mucss/css');
var sliderHTML = require('./index.html');
var itemHTML = require('./item.html');
var q = require('queried');

function SwiperFullscreen(options) {

	if (!(this instanceof(SwiperFullscreen))) return new SwiperFullscreen(options);

	var self = this;

	extend(self, options);

	self.el = domify(sliderHTML);

	//create and append slides
	self.data.forEach(function(itemData) {
		var item = self.render(itemData);
		self.appendItem(item);
	});

	if (self.navigation && self.data.length > 1) {
		self.appendNavigation();
	}

	self.swiper = new Swiper(q('.swiper-container', self.el), self.swiper);

	//prepare and open dialog with swiper
	self.dialog = dialog(null, self.el)
	.effect('fade')
	.overlay()
	.fixed()
	.closable()
	.escapable()
	.addClass('dialog-slider-fullscreen')
	.on('show', function () {
		css(document.body, {
			'overflow': 'hidden'
		});
	})
	.on('close', closeDialog)
	.on('hide', closeDialog)
	.on('escape', closeDialog);

	function closeDialog () {
		css(document.body, {
			'overflow': null
		});
	}

}

extend(SwiperFullscreen.prototype, {

	data: [],
	navigation: true,

	swiper: {
		loop: true,
		effect: 'fade',
		speed: 200,
		lazyLoading: true,
		preloadImages: false,
		lazyLoadingOnTransitionStart: true,
		keyboardControl: true
	},

	show: function(slideIndex) {
		this.dialog.show();
		this.swiper.update();
		if (typeof slideIndex != 'undefined') this.swiper.slideTo(slideIndex, 0);
	},

	hide: function() {
		this.dialog.hide();
	},

	render: function(data) {
		data.title = data.title || '';
		return domify(
			itemHTML
				.replace("%src%", data.src)
				.replace("%title%", data.title)
		);
	},

	appendItem: function(element) {
		this.el.querySelector('.swiper-wrapper').appendChild(element);
	},

	appendNavigation: function() {
		var self = this;

		//create elements for nav buttons
		var prevArrow = document.createElement('div');
		prevArrow.className = 'swiper-button-prev';
		var nextArrow = document.createElement('div');
		nextArrow.className = 'swiper-button-next';

		//bind click events
		prevArrow.addEventListener('click', function() {
			self.swiper.slidePrev();
		});
		nextArrow.addEventListener('click', function() {
			self.swiper.slideNext();
		});

		//append the buttons
		var container = q('.swiper-container', this.el);
		container.appendChild(prevArrow);
		container.appendChild(nextArrow);
	}

});

module.exports = SwiperFullscreen;<commit_msg>Added doc blocks to functions<commit_after>var swiper = require('swiper');
var dialog = require('dialog-component');
var extend = require('deep-extend');
var domify = require('domify');
var css = require('mucss/css');
var sliderHTML = require('./index.html');
var itemHTML = require('./item.html');
var q = require('queried');

/**
 * Create an instance of fullscreen swiper
 * @constructor
 * @param {Object} options Initialization options
 */
function SwiperFullscreen(options) {

	if (!(this instanceof(SwiperFullscreen))) return new SwiperFullscreen(options);

	var self = this;

	extend(self, options);

	self.el = domify(sliderHTML);

	//create and append slides
	self.data.forEach(function(itemData) {
		var item = self.render(itemData);
		self.appendItem(item);
	});

	if (self.navigation && self.data.length > 1) {
		self.appendNavigation();
	}

	self.swiper = new Swiper(q('.swiper-container', self.el), self.swiper);

	//prepare and open dialog with swiper
	self.dialog = dialog(null, self.el)
	.effect('fade')
	.overlay()
	.fixed()
	.closable()
	.escapable()
	.addClass('dialog-slider-fullscreen')
	.on('show', function () {
		css(document.body, {
			'overflow': 'hidden'
		});
	})
	.on('close', closeDialog)
	.on('hide', closeDialog)
	.on('escape', closeDialog);

	function closeDialog () {
		css(document.body, {
			'overflow': null
		});
	}

}

extend(SwiperFullscreen.prototype, {

	data: [],
	navigation: true,

	swiper: {
		loop: true,
		effect: 'fade',
		speed: 200,
		lazyLoading: true,
		preloadImages: false,
		lazyLoadingOnTransitionStart: true,
		keyboardControl: true
	},

	/**
	 * show the dialog with instance slider
	 * @param  {Number} slideIndex Index of slide to show when opened
	 */
	show: function(slideIndex) {
		this.dialog.show();
		this.swiper.update();
		if (typeof slideIndex != 'undefined') this.swiper.slideTo(slideIndex, 0);
	},

	/**
	 * hide the instanse's dialog
	 */
	hide: function() {
		this.dialog.hide();
	},

	/**
	 * render slide item with data provided
	 * @param  {Object} data - data to be rendered
	 * @return {DomObject}      Slide DOM element
	 */
	render: function(data) {
		data.title = data.title || '';
		return domify(
			itemHTML
				.replace("%src%", data.src)
				.replace("%title%", data.title)
		);
	},

	/**
	 * append slide to the slider
	 * @param  {DomObject} element - slide element
	 */
	appendItem: function(element) {
		this.el.querySelector('.swiper-wrapper').appendChild(element);
	},

	appendNavigation: function() {
		var self = this;

		//create elements for nav buttons
		var prevArrow = document.createElement('div');
		prevArrow.className = 'swiper-button-prev';
		var nextArrow = document.createElement('div');
		nextArrow.className = 'swiper-button-next';

		//bind click events
		prevArrow.addEventListener('click', function() {
			self.swiper.slidePrev();
		});
		nextArrow.addEventListener('click', function() {
			self.swiper.slideNext();
		});

		//append the buttons
		var container = q('.swiper-container', this.el);
		container.appendChild(prevArrow);
		container.appendChild(nextArrow);
	}

});

module.exports = SwiperFullscreen;<|endoftext|>


<commit_before>import get from 'lodash/get';
import set from 'lodash/set';
import has from 'lodash/has';
import clone from 'lodash/clone';
import forOwn from 'lodash/forOwn';
import isString from 'lodash/isString';
import isNaN from 'lodash/isNaN';
import isNil from 'lodash/isNil';
import isPlainObject from 'lodash/isPlainObject';
import round from 'lodash/round';
import chunk from 'lodash/chunk';
import pad from 'lodash/pad';
import { compare, applyPatch } from 'fast-json-patch';

/**
 * Determine if a component is a layout component or not.
 *
 * @param {Object} component
 *   The component to check.
 *
 * @returns {Boolean}
 *   Whether or not the component is a layout component.
 */
export function isLayoutComponent(component) {
  return Boolean(
    (component.columns && Array.isArray(component.columns)) ||
    (component.rows && Array.isArray(component.rows)) ||
    (component.components && Array.isArray(component.components))
  );
}

/**
 * Iterate through each component within a form.
 *
 * @param {Object} components
 *   The components to iterate.
 * @param {Function} fn
 *   The iteration function to invoke for each component.
 * @param {Boolean} includeAll
 *   Whether or not to include layout components.
 * @param {String} path
 *   The current data path of the element. Example: data.user.firstName
 * @param {Object} parent
 *   The parent object.
 */
export function eachComponent(components, fn, includeAll, path, parent) {
  if (!components) return;
  path = path || '';
  components.forEach((component) => {
    if (!component) {
      return;
    }
    const hasColumns = component.columns && Array.isArray(component.columns);
    const hasRows = component.rows && Array.isArray(component.rows);
    const hasComps = component.components && Array.isArray(component.components);
    let noRecurse = false;
    const newPath = component.key ? (path ? (`${path}.${component.key}`) : component.key) : '';

    // Keep track of parent references.
    if (parent) {
      // Ensure we don't create infinite JSON structures.
      component.parent = clone(parent);
      delete component.parent.components;
      delete component.parent.componentMap;
      delete component.parent.columns;
      delete component.parent.rows;
    }

    if (includeAll || component.tree || (!hasColumns && !hasRows && !hasComps)) {
      noRecurse = fn(component, newPath);
    }

    const subPath = () => {
      if (
        component.key &&
        !['panel', 'table', 'well', 'columns', 'fieldset', 'tabs', 'form'].includes(component.type) &&
        (
          ['datagrid', 'container', 'editgrid'].includes(component.type) ||
          component.tree
        )
      ) {
        return newPath;
      }
      else if (
        component.key &&
        component.type === 'form'
      ) {
        return `${newPath}.data`;
      }
      return path;
    };

    if (!noRecurse) {
      if (hasColumns) {
        component.columns.forEach((column) =>
          eachComponent(column.components, fn, includeAll, subPath(), parent ? component : null));
      }

      else if (hasRows) {
        component.rows.forEach((row) => {
          if (Array.isArray(row)) {
            row.forEach((column) =>
              eachComponent(column.components, fn, includeAll, subPath(), parent ? component : null));
          }
        });
      }

      else if (hasComps) {
        eachComponent(component.components, fn, includeAll, subPath(), parent ? component : null);
      }
    }
  });
}

/**
 * Matches if a component matches the query.
 *
 * @param component
 * @param query
 * @return {boolean}
 */
export function matchComponent(component, query) {
  if (isString(query)) {
    return component.key === query;
  }
  else {
    let matches = false;
    forOwn(query, (value, key) => {
      matches = (get(component, key) === value);
      if (!matches) {
        return false;
      }
    });
    return matches;
  }
}

/**
 * Get a component by its key
 *
 * @param {Object} components
 *   The components to iterate.
 * @param {String|Object} key
 *   The key of the component to get, or a query of the component to search.
 *
 * @returns {Object}
 *   The component that matches the given key, or undefined if not found.
 */
export function getComponent(components, key, includeAll) {
  let result;
  eachComponent(components, (component, path) => {
    if (path === key) {
      component.path = path;
      result = component;
      return true;
    }
  }, includeAll);
  return result;
}

/**
 * Finds a component provided a query of properties of that component.
 *
 * @param components
 * @param query
 * @return {*}
 */
export function searchComponents(components, query) {
  const results = [];
  eachComponent(components, (component, path) => {
    if (matchComponent(component, query)) {
      component.path = path;
      results.push(component);
    }
  }, true);
  return results;
}

/**
 * Deprecated version of findComponents. Renamed to searchComponents.
 *
 * @param components
 * @param query
 * @returns {*}
 */
export function findComponents(components, query) {
  console.warn('formio.js/utils findComponents is deprecated. Use searchComponents instead.');
  return searchComponents(components, query);
}

/**
 * This function will find a component in a form and return the component AND THE PATH to the component in the form.
 *
 * @param components
 * @param key
 * @param fn
 * @param path
 * @returns {*}
 */
export function findComponent(components, key, path, fn) {
  if (!components) return;
  path = path || [];

  if (!key) {
    return fn(components);
  }

  components.forEach(function(component, index) {
    var newPath = path.slice();
    newPath.push(index);
    if (!component) return;

    if (component.hasOwnProperty('columns') && Array.isArray(component.columns)) {
      newPath.push('columns');
      component.columns.forEach(function(column, index) {
        var colPath = newPath.slice();
        colPath.push(index);
        colPath.push('components');
        findComponent(column.components, key, colPath, fn);
      });
    }

    if (component.hasOwnProperty('rows') && Array.isArray(component.rows)) {
      newPath.push('rows');
      component.rows.forEach(function(row, index) {
        var rowPath = newPath.slice();
        rowPath.push(index);
        row.forEach(function(column, index) {
          var colPath = rowPath.slice();
          colPath.push(index);
          colPath.push('components');
          findComponent(column.components, key, colPath, fn);
        });
      });
    }

    if (component.hasOwnProperty('components') && Array.isArray(component.components)) {
      newPath.push('components');
      findComponent(component.components, key, newPath, fn);
    }

    if (component.key === key) {
      fn(component, newPath);
    }
  });
}

/**
 * Remove a component by path.
 *
 * @param components
 * @param path
 */
export function removeComponent(components, path) {
  // Using _.unset() leave a null value. Use Array splice instead.
  var index = path.pop();
  if (path.length !== 0) {
    components = get(components, path);
  }
  components.splice(index, 1);
}

export function generateFormChange(type, data) {
  let change;
  switch (type) {
    case 'add':
      change = {
        op: 'add',
        key: data.component.key,
        container: data.parent.key, // Parent component
        path: data.path, // Path to container within parent component.
        index: data.index, // Index of component in parent container.
        component: data.component
      };
      break;
    case 'edit':
      change = {
        op: 'edit',
        key: data.originalComponent.key,
        patches: compare(data.originalComponent, data.component)
      };

      // Don't save if nothing changed.
      if (!change.patches.length) {
        change = null;
      }
      break;
    case 'remove':
      change = {
        op: 'remove',
        key: data.component.key,
      };
      break;
  }

  return change;
}

export function applyFormChanges(form, changes) {
  const failed = [];
  changes.forEach(function(change) {
    var found = false;
    switch (change.op) {
      case 'add':
        var newComponent = change.component;

        // Find the container to set the component in.
        findComponent(form.components, change.container, null, function(parent) {
          if (!change.container) {
            parent = form;
          }

          // A move will first run an add so remove any existing components with matching key before inserting.
          findComponent(form.components, change.key, null, function(component, path) {
            // If found, use the existing component. (If someone else edited it, the changes would be here)
            newComponent = component;
            removeComponent(form.components, path);
          });

          found = true;
          var container = get(parent, change.path);
          container.splice(change.index, 0, newComponent);
        });
        break;
      case 'remove':
        findComponent(form.components, change.key, null, function(component, path) {
          found = true;
          removeComponent(form.components, path);
        });
        break;
      case 'edit':
        findComponent(form.components, change.key, null, function(component, path) {
          found = true;
          try {
            set(form.components, path, applyPatch(component, change.patches).newDocument);
          }
          catch (err) {
            failed.push(change);
          }
        });
        break;
      case 'move':
        break;
    }
    if (!found) {
      failed.push(change);
    }
  });

  return {
    form,
    failed
  };
}

/**
 * Flatten the form components for data manipulation.
 *
 * @param {Object} components
 *   The components to iterate.
 * @param {Boolean} includeAll
 *   Whether or not to include layout components.
 *
 * @returns {Object}
 *   The flattened components map.
 */
export function flattenComponents(components, includeAll) {
  const flattened = {};
  eachComponent(components, (component, path) => {
    flattened[path] = component;
  }, includeAll);
  return flattened;
}

/**
 * Returns if this component has a conditional statement.
 *
 * @param component - The component JSON schema.
 *
 * @returns {boolean} - TRUE - This component has a conditional, FALSE - No conditional provided.
 */
export function hasCondition(component) {
  return Boolean(
    (component.customConditional) ||
    (component.conditional && component.conditional.when) ||
    (component.conditional && component.conditional.json)
  );
}

/**
 * Extension of standard #parseFloat(value) function, that also clears input string.
 *
 * @param {any} value
 *   The value to parse.
 *
 * @returns {Number}
 *   Parsed value.
 */
export function parseFloatExt(value) {
  return parseFloat(isString(value)
    ? value.replace(/[^\de.+-]/gi, '')
    : value);
}

/**
 * Formats provided value in way how Currency component uses it.
 *
 * @param {any} value
 *   The value to format.
 *
 * @returns {String}
 *   Value formatted for Currency component.
 */
export function formatAsCurrency(value) {
  const parsedValue = parseFloatExt(value);

  if (isNaN(parsedValue)) {
    return '';
  }

  const parts = round(parsedValue, 2)
    .toString()
    .split('.');
  parts[0] = chunk(Array.from(parts[0]).reverse(), 3)
    .reverse()
    .map((part) => part
      .reverse()
      .join(''))
    .join(',');
  parts[1] = pad(parts[1], 2, '0');
  return parts.join('.');
}

/**
 * Escapes RegEx characters in provided String value.
 *
 * @param {String} value
 *   String for escaping RegEx characters.
 * @returns {string}
 *   String with escaped RegEx characters.
 */
export function escapeRegExCharacters(value) {
  return value.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
}

/**
 * Get the value for a component key, in the given submission.
 *
 * @param {Object} submission
 *   A submission object to search.
 * @param {String} key
 *   A for components API key to search for.
 */
export function getValue(submission, key) {
  const search = (data) => {
    if (isPlainObject(data)) {
      if (has(data, key)) {
        return data[key];
      }

      let value = null;

      forOwn(data, (prop) => {
        const result = search(prop);
        if (!isNil(result)) {
          value = result;
          return false;
        }
      });

      return value;
    }
    else {
      return null;
    }
  };

  return search(submission.data);
}

/**
 * Iterate over all components in a form and get string values for translation.
 * @param form
 */
export function getStrings(form) {
  const properties = ['label', 'title', 'legend', 'tooltip', 'description', 'placeholder', 'prefix', 'suffix', 'errorLabel', 'content', 'html'];
  const strings = [];
  eachComponent(form.components, component => {
    properties.forEach(property => {
      if (component.hasOwnProperty(property) && component[property]) {
        strings.push({
          key: component.key,
          type: component.type,
          property,
          string: component[property]
        });
      }
    });
    if ((!component.dataSrc || component.dataSrc === 'values') && component.hasOwnProperty('values') && Array.isArray(component.values) && component.values.length) {
      component.values.forEach((value, index) => {
        strings.push({
          key: component.key,
          property: `value[${index}].label`,
          string: component.values[index].label
        });
      });
    }

    // Hard coded values from Day component
    if (component.type === 'day') {
      [
        'day',
        'month',
        'year',
        'Day',
        'Month',
        'Year',
        'january',
        'february',
        'march',
        'april',
        'may',
        'june',
        'july',
        'august',
        'september',
        'october',
        'november',
        'december'
      ].forEach(string => {
        strings.push({
          key: component.key,
          property: 'day',
          string,
        });
      });

      if (component.fields.day.placeholder) {
        strings.push({
          key: component.key,
          property: 'fields.day.placeholder',
          string: component.fields.day.placeholder,
        });
      }

      if (component.fields.month.placeholder) {
        strings.push({
          key: component.key,
          property: 'fields.month.placeholder',
          string: component.fields.month.placeholder,
        });
      }

      if (component.fields.year.placeholder) {
        strings.push({
          key: component.key,
          property: 'fields.year.placeholder',
          string: component.fields.year.placeholder,
        });
      }
    }

    if (component.type === 'editgrid') {
      const string = this.component.addAnother || 'Add Another';
      if (component.addAnother) {
        strings.push({
          key: component.key,
          property: 'addAnother',
          string,
        });
      }
    }

    if (component.type === 'select') {
      [
        'loading...',
        'Type to search'
      ].forEach(string => {
        strings.push({
          key: component.key,
          property: 'select',
          string,
        });
      });
    }
  }, true);

  return strings;
}
<commit_msg>fixed typo in getStrings method<commit_after>import get from 'lodash/get';
import set from 'lodash/set';
import has from 'lodash/has';
import clone from 'lodash/clone';
import forOwn from 'lodash/forOwn';
import isString from 'lodash/isString';
import isNaN from 'lodash/isNaN';
import isNil from 'lodash/isNil';
import isPlainObject from 'lodash/isPlainObject';
import round from 'lodash/round';
import chunk from 'lodash/chunk';
import pad from 'lodash/pad';
import { compare, applyPatch } from 'fast-json-patch';

/**
 * Determine if a component is a layout component or not.
 *
 * @param {Object} component
 *   The component to check.
 *
 * @returns {Boolean}
 *   Whether or not the component is a layout component.
 */
export function isLayoutComponent(component) {
  return Boolean(
    (component.columns && Array.isArray(component.columns)) ||
    (component.rows && Array.isArray(component.rows)) ||
    (component.components && Array.isArray(component.components))
  );
}

/**
 * Iterate through each component within a form.
 *
 * @param {Object} components
 *   The components to iterate.
 * @param {Function} fn
 *   The iteration function to invoke for each component.
 * @param {Boolean} includeAll
 *   Whether or not to include layout components.
 * @param {String} path
 *   The current data path of the element. Example: data.user.firstName
 * @param {Object} parent
 *   The parent object.
 */
export function eachComponent(components, fn, includeAll, path, parent) {
  if (!components) return;
  path = path || '';
  components.forEach((component) => {
    if (!component) {
      return;
    }
    const hasColumns = component.columns && Array.isArray(component.columns);
    const hasRows = component.rows && Array.isArray(component.rows);
    const hasComps = component.components && Array.isArray(component.components);
    let noRecurse = false;
    const newPath = component.key ? (path ? (`${path}.${component.key}`) : component.key) : '';

    // Keep track of parent references.
    if (parent) {
      // Ensure we don't create infinite JSON structures.
      component.parent = clone(parent);
      delete component.parent.components;
      delete component.parent.componentMap;
      delete component.parent.columns;
      delete component.parent.rows;
    }

    if (includeAll || component.tree || (!hasColumns && !hasRows && !hasComps)) {
      noRecurse = fn(component, newPath);
    }

    const subPath = () => {
      if (
        component.key &&
        !['panel', 'table', 'well', 'columns', 'fieldset', 'tabs', 'form'].includes(component.type) &&
        (
          ['datagrid', 'container', 'editgrid'].includes(component.type) ||
          component.tree
        )
      ) {
        return newPath;
      }
      else if (
        component.key &&
        component.type === 'form'
      ) {
        return `${newPath}.data`;
      }
      return path;
    };

    if (!noRecurse) {
      if (hasColumns) {
        component.columns.forEach((column) =>
          eachComponent(column.components, fn, includeAll, subPath(), parent ? component : null));
      }

      else if (hasRows) {
        component.rows.forEach((row) => {
          if (Array.isArray(row)) {
            row.forEach((column) =>
              eachComponent(column.components, fn, includeAll, subPath(), parent ? component : null));
          }
        });
      }

      else if (hasComps) {
        eachComponent(component.components, fn, includeAll, subPath(), parent ? component : null);
      }
    }
  });
}

/**
 * Matches if a component matches the query.
 *
 * @param component
 * @param query
 * @return {boolean}
 */
export function matchComponent(component, query) {
  if (isString(query)) {
    return component.key === query;
  }
  else {
    let matches = false;
    forOwn(query, (value, key) => {
      matches = (get(component, key) === value);
      if (!matches) {
        return false;
      }
    });
    return matches;
  }
}

/**
 * Get a component by its key
 *
 * @param {Object} components
 *   The components to iterate.
 * @param {String|Object} key
 *   The key of the component to get, or a query of the component to search.
 *
 * @returns {Object}
 *   The component that matches the given key, or undefined if not found.
 */
export function getComponent(components, key, includeAll) {
  let result;
  eachComponent(components, (component, path) => {
    if (path === key) {
      component.path = path;
      result = component;
      return true;
    }
  }, includeAll);
  return result;
}

/**
 * Finds a component provided a query of properties of that component.
 *
 * @param components
 * @param query
 * @return {*}
 */
export function searchComponents(components, query) {
  const results = [];
  eachComponent(components, (component, path) => {
    if (matchComponent(component, query)) {
      component.path = path;
      results.push(component);
    }
  }, true);
  return results;
}

/**
 * Deprecated version of findComponents. Renamed to searchComponents.
 *
 * @param components
 * @param query
 * @returns {*}
 */
export function findComponents(components, query) {
  console.warn('formio.js/utils findComponents is deprecated. Use searchComponents instead.');
  return searchComponents(components, query);
}

/**
 * This function will find a component in a form and return the component AND THE PATH to the component in the form.
 *
 * @param components
 * @param key
 * @param fn
 * @param path
 * @returns {*}
 */
export function findComponent(components, key, path, fn) {
  if (!components) return;
  path = path || [];

  if (!key) {
    return fn(components);
  }

  components.forEach(function(component, index) {
    var newPath = path.slice();
    newPath.push(index);
    if (!component) return;

    if (component.hasOwnProperty('columns') && Array.isArray(component.columns)) {
      newPath.push('columns');
      component.columns.forEach(function(column, index) {
        var colPath = newPath.slice();
        colPath.push(index);
        colPath.push('components');
        findComponent(column.components, key, colPath, fn);
      });
    }

    if (component.hasOwnProperty('rows') && Array.isArray(component.rows)) {
      newPath.push('rows');
      component.rows.forEach(function(row, index) {
        var rowPath = newPath.slice();
        rowPath.push(index);
        row.forEach(function(column, index) {
          var colPath = rowPath.slice();
          colPath.push(index);
          colPath.push('components');
          findComponent(column.components, key, colPath, fn);
        });
      });
    }

    if (component.hasOwnProperty('components') && Array.isArray(component.components)) {
      newPath.push('components');
      findComponent(component.components, key, newPath, fn);
    }

    if (component.key === key) {
      fn(component, newPath);
    }
  });
}

/**
 * Remove a component by path.
 *
 * @param components
 * @param path
 */
export function removeComponent(components, path) {
  // Using _.unset() leave a null value. Use Array splice instead.
  var index = path.pop();
  if (path.length !== 0) {
    components = get(components, path);
  }
  components.splice(index, 1);
}

export function generateFormChange(type, data) {
  let change;
  switch (type) {
    case 'add':
      change = {
        op: 'add',
        key: data.component.key,
        container: data.parent.key, // Parent component
        path: data.path, // Path to container within parent component.
        index: data.index, // Index of component in parent container.
        component: data.component
      };
      break;
    case 'edit':
      change = {
        op: 'edit',
        key: data.originalComponent.key,
        patches: compare(data.originalComponent, data.component)
      };

      // Don't save if nothing changed.
      if (!change.patches.length) {
        change = null;
      }
      break;
    case 'remove':
      change = {
        op: 'remove',
        key: data.component.key,
      };
      break;
  }

  return change;
}

export function applyFormChanges(form, changes) {
  const failed = [];
  changes.forEach(function(change) {
    var found = false;
    switch (change.op) {
      case 'add':
        var newComponent = change.component;

        // Find the container to set the component in.
        findComponent(form.components, change.container, null, function(parent) {
          if (!change.container) {
            parent = form;
          }

          // A move will first run an add so remove any existing components with matching key before inserting.
          findComponent(form.components, change.key, null, function(component, path) {
            // If found, use the existing component. (If someone else edited it, the changes would be here)
            newComponent = component;
            removeComponent(form.components, path);
          });

          found = true;
          var container = get(parent, change.path);
          container.splice(change.index, 0, newComponent);
        });
        break;
      case 'remove':
        findComponent(form.components, change.key, null, function(component, path) {
          found = true;
          removeComponent(form.components, path);
        });
        break;
      case 'edit':
        findComponent(form.components, change.key, null, function(component, path) {
          found = true;
          try {
            set(form.components, path, applyPatch(component, change.patches).newDocument);
          }
          catch (err) {
            failed.push(change);
          }
        });
        break;
      case 'move':
        break;
    }
    if (!found) {
      failed.push(change);
    }
  });

  return {
    form,
    failed
  };
}

/**
 * Flatten the form components for data manipulation.
 *
 * @param {Object} components
 *   The components to iterate.
 * @param {Boolean} includeAll
 *   Whether or not to include layout components.
 *
 * @returns {Object}
 *   The flattened components map.
 */
export function flattenComponents(components, includeAll) {
  const flattened = {};
  eachComponent(components, (component, path) => {
    flattened[path] = component;
  }, includeAll);
  return flattened;
}

/**
 * Returns if this component has a conditional statement.
 *
 * @param component - The component JSON schema.
 *
 * @returns {boolean} - TRUE - This component has a conditional, FALSE - No conditional provided.
 */
export function hasCondition(component) {
  return Boolean(
    (component.customConditional) ||
    (component.conditional && component.conditional.when) ||
    (component.conditional && component.conditional.json)
  );
}

/**
 * Extension of standard #parseFloat(value) function, that also clears input string.
 *
 * @param {any} value
 *   The value to parse.
 *
 * @returns {Number}
 *   Parsed value.
 */
export function parseFloatExt(value) {
  return parseFloat(isString(value)
    ? value.replace(/[^\de.+-]/gi, '')
    : value);
}

/**
 * Formats provided value in way how Currency component uses it.
 *
 * @param {any} value
 *   The value to format.
 *
 * @returns {String}
 *   Value formatted for Currency component.
 */
export function formatAsCurrency(value) {
  const parsedValue = parseFloatExt(value);

  if (isNaN(parsedValue)) {
    return '';
  }

  const parts = round(parsedValue, 2)
    .toString()
    .split('.');
  parts[0] = chunk(Array.from(parts[0]).reverse(), 3)
    .reverse()
    .map((part) => part
      .reverse()
      .join(''))
    .join(',');
  parts[1] = pad(parts[1], 2, '0');
  return parts.join('.');
}

/**
 * Escapes RegEx characters in provided String value.
 *
 * @param {String} value
 *   String for escaping RegEx characters.
 * @returns {string}
 *   String with escaped RegEx characters.
 */
export function escapeRegExCharacters(value) {
  return value.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
}

/**
 * Get the value for a component key, in the given submission.
 *
 * @param {Object} submission
 *   A submission object to search.
 * @param {String} key
 *   A for components API key to search for.
 */
export function getValue(submission, key) {
  const search = (data) => {
    if (isPlainObject(data)) {
      if (has(data, key)) {
        return data[key];
      }

      let value = null;

      forOwn(data, (prop) => {
        const result = search(prop);
        if (!isNil(result)) {
          value = result;
          return false;
        }
      });

      return value;
    }
    else {
      return null;
    }
  };

  return search(submission.data);
}

/**
 * Iterate over all components in a form and get string values for translation.
 * @param form
 */
export function getStrings(form) {
  const properties = ['label', 'title', 'legend', 'tooltip', 'description', 'placeholder', 'prefix', 'suffix', 'errorLabel', 'content', 'html'];
  const strings = [];
  eachComponent(form.components, component => {
    properties.forEach(property => {
      if (component.hasOwnProperty(property) && component[property]) {
        strings.push({
          key: component.key,
          type: component.type,
          property,
          string: component[property]
        });
      }
    });
    if ((!component.dataSrc || component.dataSrc === 'values') && component.hasOwnProperty('values') && Array.isArray(component.values) && component.values.length) {
      component.values.forEach((value, index) => {
        strings.push({
          key: component.key,
          property: `value[${index}].label`,
          string: component.values[index].label
        });
      });
    }

    // Hard coded values from Day component
    if (component.type === 'day') {
      [
        'day',
        'month',
        'year',
        'Day',
        'Month',
        'Year',
        'january',
        'february',
        'march',
        'april',
        'may',
        'june',
        'july',
        'august',
        'september',
        'october',
        'november',
        'december'
      ].forEach(string => {
        strings.push({
          key: component.key,
          property: 'day',
          string,
        });
      });

      if (component.fields.day.placeholder) {
        strings.push({
          key: component.key,
          property: 'fields.day.placeholder',
          string: component.fields.day.placeholder,
        });
      }

      if (component.fields.month.placeholder) {
        strings.push({
          key: component.key,
          property: 'fields.month.placeholder',
          string: component.fields.month.placeholder,
        });
      }

      if (component.fields.year.placeholder) {
        strings.push({
          key: component.key,
          property: 'fields.year.placeholder',
          string: component.fields.year.placeholder,
        });
      }
    }

    if (component.type === 'editgrid') {
      const string = component.addAnother || 'Add Another';
      if (component.addAnother) {
        strings.push({
          key: component.key,
          property: 'addAnother',
          string,
        });
      }
    }

    if (component.type === 'select') {
      [
        'loading...',
        'Type to search'
      ].forEach(string => {
        strings.push({
          key: component.key,
          property: 'select',
          string,
        });
      });
    }
  }, true);

  return strings;
}
<|endoftext|>


<commit_before>'use strict'

module.exports = builder

// ## Usage
// ```js
// builder(options)
// .on('warn', function () {
// })
// .parse(filename, callback)
// ```
function builder(entry, options, callback) {
  make_sure(options, 'pkg')
  make_sure(options, 'cwd')
  return new Builder(options).parse(entry, callback)
}

function make_sure (options, key) {
  if (key in options) {
    return
  }

  throw new Error('`options.' + key + '` must be defined')
}

builder.Builder = Builder

var fs = require('fs')
var node_path = require('path')
var util = require('util')
var async = require('async')
var _ = require('underscore')
var EE = require('events').EventEmitter
var walker = require('commonjs-walker')
var make_array = require('make-array')
var mix = require('mix2')

function Builder(options) {
  var self = this
  this._uuid = 0
  this.options = options
  this.cwd = node_path.resolve(options.cwd)
  this.pkg = options.pkg
  this.locals = {}
  this.global_map = {}
}

util.inherits(Builder, EE)

Builder.prototype.parse = function(filename, callback) {
  var self = this
  var resolved = {}
  var pkg = this.pkg
  var locals = this.locals

  async.waterfall([
    function(done) {
      self._get_dependency_tree(filename, done)
    },
    function(nodes, done) {
      self._collect_modules(nodes, done)
    },
    function(codes, done) {
      self._generate_code(codes, done)
    }
  ], callback)
}

// Gets the dependency tree from the entry file
// @param {String} filename
// @param {function(err, nodes)} callback
Builder.prototype._get_dependency_tree = function(filename, callback) {
  var self = this
  walker({
    allow_cyclic: true,
    check_require_length: true,
    allow_absolute_path: false,
    extensions: ['.js', '.json'],
    require_resolve: true,
    require_async: true
  })
  .on('warn', function(message) {
    self.emit('warn', message)
  })
  .register(this.options.compilers)
  .walk(filename)
  .done(function(err, nodes) {
    if (err) {
      return callback(err)
    }
console.log(nodes)
    self.nodes = nodes
    callback(null, nodes)
  })
}

// Collect all modules which should be bundled into one file
// @param {function(err, codes)} callback
// - codes `Object` the `{<path>: <parsed-module>}` map
Builder.prototype._collect_modules = function(nodes, callback) {
  var codes = {}
  var errmsg = ''
  var id
  var mod
  for (id in nodes) {
    mod = nodes[id]
    if (mod.foreign) {
      continue
    }

    try {
      mod.resolved = this._resolve_module_dependencies(id, mod)
    } catch (e) {
      if (e.code == 'ENOTINSTALLED') {
        errmsg = 'Explicit version of dependency <%= deps.map(function(dep){return dep}).join(", ") %> <%= deps.length > 1 ? "are" : "is" %> not defined.\n file: <%= file %>'
      } else if (e.code == 'EOUTENTRY') {
        errmsg = 'Relative dependency "<%= deps[0] %>" out of main entry\'s directory. file: <%= file %>'
      } else {
        errmsg = e.message
      }
      e.file = id
      return callback(new Error(_.template(errmsg)(e)))
    }

    codes[id] = mod
  }

  callback(null, codes)
}

// @param {String} id Path(file entry) or package name(foreign package)
Builder.prototype._resolve_module_dependencies = function(id, mod) {
  var self = this
  var pkg = this.pkg
  var cwd = this.cwd
  var deps = mod.dependencies
  var resolved = {}

  ;['require', 'resolve', 'async'].forEach(function (key) {
    this._resolve_dependencies(id, mod, mod[key], resolved)
  }, this)

  return resolved
}

// @param {*Object} resolved
Builder.prototype._resolve_dependencies = function(id, mod, deps, resolved) {
  var module_name
  var r
  var real
  var not_installed = []

  for (module_name in deps) {
    real = deps[module_name]

    if (this._is_foreign(real)) {
      // check dependency versions and apply
      // 'jquery' -> 'jquery@^1.9.2'
      r = this._apply_dependency_version(real)

      if (!r) {
        not_installed.push(real)
      }

    } else {
      if (this._out_of_dir(module_name, id)) {
        throw {
          code: 'EOUTENTRY',
          deps: [module_name]
        }
      }
      r = this._generate_module_id(real)
    }

    resolved[module_name] = r
    this._add_to_global_map(module_name, r)
    this._add_locals(r)
  }

  if (not_installed.length) {
    throw {
      code: 'ENOTINSTALLED',
      deps: not_installed
    }
  }
}

Builder.prototype._add_to_global_map = function(key, value) {
  this.global_map[key] = value
}

Builder.prototype._generate_code = function(codes, callback) {
  var self = this
  this._wrap_all(codes, function (err, code) {
    if (err) {
      return callback(err)
    }

    callback(null, self._combile_statements(code))
  })
}

var CODE_TEMPLATE = [
  '(function(){'         ,
  ''                      ,
  'function mix(a, b){'   ,
  '  for(var k in b) {'   ,
  '    a[k] = b[k]'      ,
  '  }'                   ,
  '  return a'           ,
  '}'                     ,
  '<%= variables %>'      ,
  '<%= code %>'           ,
  ''                      ,
  '})()'

].join('\n')

Builder.prototype._combile_statements = function(code) {
  var locals = this.locals

  var statements = []
  function declare_varible(name, value, raw) {
    var statement = 'var ' + name + ' = ' + (raw ? value : JSON.stringify(value)) + ''
    if (value) {
      statements.push(statement)
    }
  }

  _.keys(locals).forEach(function(v) {
    declare_varible(locals[v], v)
  })

  declare_varible('global_map', this._stringify(this.global_map), true)

  return _.template(CODE_TEMPLATE)({
    variables: statements.join('\n'),
    code: code
  })
}

Builder.prototype._wrap_all = function(codes, callback) {
  var self = this
  var tasks = _.keys(codes).map(function (id) {
    return function (done) {
      self._wrap(id, codes[id], done)
    }
  })

  async.parallel(tasks, function (err, content_array) {
    if (err) {
      return callback(err)
    }

    callback(null, content_array.join('\n\n'))
  })
}

var WRAPPING_TEMPLATE =
    'define(<%= id %>, <%= deps %>, function(require, exports, module, __filename, __dirname) {\n'
  +   '<%= code %>\n'
  + '}<%= module_options ? ", " + module_options : "" %>)'

// Wrap a commonjs module with wrappings so that it could run in browsers
Builder.prototype._wrap = function(filename, mod, callback) {
  // id
  var module_id = this._generate_module_id(filename)

  // dependencies
  var resolved_dependencies = _.keys(mod.require).map(function (dep) {
    return mod.resolved[dep] || dep
  })

  // options
  var module_options = this._generate_module_options(filename, mod)

  var pairs = []
  if (module_options.main) {
    pairs.push('main: true')
  }

  var different
  var map
  if (module_options.map) {
    different = get_difference(module_options.map, this.global_map)
    map = _.keys(different).length
      ? 'mix(' + this._stringify(different) + ', global_map)'
      : 'global_map'

    pairs.push('map: ' + map)
  }

  module_options = pairs.length
    ? '{\n'
      + '  ' + pairs.join(',\n  ')
      + '\n}'
    : ''

  var result = _.template(WRAPPING_TEMPLATE)({
    id: this._stringify(module_id),
    deps: this._stringify(resolved_dependencies),
    code: mod.code,
    module_options: module_options
  })

  callback(null, result)
}

function get_difference (object, relative) {
  var parsed = {}
  var key
  for(key in object){
    if (relative[key] !== object[key]) {
      parsed[key] = object[key]
    }
  }
  return parsed
}

// filename: '/path/to/a.js'
// cwd: '/path'
// -> 'module@0.0.1/to/a.js'
Builder.prototype._generate_module_id = function(filename, relative) {
  // the exact identifier
  var cwd = this.cwd
  var pkg = this.pkg
  var main_id = [pkg.name, pkg.version].join('@')

  var relative_path = relative
    ? filename
    : node_path.relative(cwd, filename)

  // -> 'module@0.0.1/folder/foo'
  var id = node_path.join(main_id, relative_path)

  // fixes windows paths
  id = id
    .replace(new RegExp('\\' + node_path.sep, 'g'), '/')
    .toLowerCase()

  this._add_locals(id)
  return id
}

Builder.prototype._is_foreign = function(str) {
  var isWindowsAbsolute = str.match(/^\w+:\\/)
  var isRelative = ['../', './'].some(function(prefix) {
    return str.indexOf(prefix) === 0
  })
  var isUnixAbsolute = str.indexOf('/') == 0
  return !isRelative && !isUnixAbsolute && !isWindowsAbsolute
}

Builder.prototype._out_of_dir = function(dep, file) {
  var mod_path = node_path.resolve(node_path.join(node_path.dirname(file), dep))
  return mod_path.indexOf(this.cwd) == -1
}

// Returns `Object`
// - main: `Boolean`
// - map: `Object`
Builder.prototype._generate_module_options = function(id, mod) {
  var pkg = this.pkg
  var cwd = this.cwd
  var module_options = {}

  if (
    pkg.main &&
    node_path.resolve(id) === node_path.resolve(cwd, pkg.main)
  ) {
    module_options.main = true
  }

  if (_.keys(mod.resolved).length) {
    module_options.map = mod.resolved
  }

  return module_options
}

Builder.prototype._apply_dependency_version = function(module_name) {
  var pkg = this.pkg

  var module_id
  ['dependencies', 'asyncDependencies', 'devDependencies'].some(function (key) {
    var dependencies = pkg[key]
    if (!dependencies) {
      return
    }
    if (module_name in dependencies) {
      module_id = module_name + '@' + dependencies[module_name]
      return true
    }
  })

  return module_id
    ? module_id

    // If allow implicit dependencies
    : this.options.allow_implicit_dependencies
      ? module_name + '@*'
      : module_id
}

// {
//   '/path/to/a.js': '_0',
//   '/path/to/b.js': '_1'
// }
Builder.prototype._add_locals = function(val) {
  var locals = this.locals
  if (!locals[val]) {
    locals[val] = '_' + this._uuid ++
  }
}

function just_return (subject) {
  return subject
}

// Stringify subject and apply local variables
Builder.prototype._stringify = function(subject) {
  var locals = this.locals

  function to_locals(item) {
    return locals[item]
  }

  if (_.isString(subject)) {
    return to_locals(subject)
  }

  if (_.isArray(subject)) {
    return '[' + subject.map(to_locals).filter(just_return).join(', ') + ']'
  }

  if (_.isObject(subject)) {
    return '{\n'
    + _.keys(subject).map(function(k) {
      var value = to_locals(subject[k])
      return value
        ? '\'' + k + '\'' + ':' + value
        : null

    }).filter(just_return).join(',\n')
    + '\n}'
  }
}
<commit_msg>removes console.log<commit_after>'use strict'

module.exports = builder

// ## Usage
// ```js
// builder(options)
// .on('warn', function () {
// })
// .parse(filename, callback)
// ```
function builder(entry, options, callback) {
  make_sure(options, 'pkg')
  make_sure(options, 'cwd')
  return new Builder(options).parse(entry, callback)
}

function make_sure (options, key) {
  if (key in options) {
    return
  }

  throw new Error('`options.' + key + '` must be defined')
}

builder.Builder = Builder

var fs = require('fs')
var node_path = require('path')
var util = require('util')
var async = require('async')
var _ = require('underscore')
var EE = require('events').EventEmitter
var walker = require('commonjs-walker')
var make_array = require('make-array')
var mix = require('mix2')

function Builder(options) {
  var self = this
  this._uuid = 0
  this.options = options
  this.cwd = node_path.resolve(options.cwd)
  this.pkg = options.pkg
  this.locals = {}
  this.global_map = {}
}

util.inherits(Builder, EE)

Builder.prototype.parse = function(filename, callback) {
  var self = this
  var resolved = {}
  var pkg = this.pkg
  var locals = this.locals

  async.waterfall([
    function(done) {
      self._get_dependency_tree(filename, done)
    },
    function(nodes, done) {
      self._collect_modules(nodes, done)
    },
    function(codes, done) {
      self._generate_code(codes, done)
    }
  ], callback)
}

// Gets the dependency tree from the entry file
// @param {String} filename
// @param {function(err, nodes)} callback
Builder.prototype._get_dependency_tree = function(filename, callback) {
  var self = this
  walker({
    allow_cyclic: true,
    check_require_length: true,
    allow_absolute_path: false,
    extensions: ['.js', '.json'],
    require_resolve: true,
    require_async: true
  })
  .on('warn', function(message) {
    self.emit('warn', message)
  })
  .register(this.options.compilers)
  .walk(filename)
  .done(function(err, nodes) {
    if (err) {
      return callback(err)
    }

    self.nodes = nodes
    callback(null, nodes)
  })
}

// Collect all modules which should be bundled into one file
// @param {function(err, codes)} callback
// - codes `Object` the `{<path>: <parsed-module>}` map
Builder.prototype._collect_modules = function(nodes, callback) {
  var codes = {}
  var errmsg = ''
  var id
  var mod
  for (id in nodes) {
    mod = nodes[id]
    if (mod.foreign) {
      continue
    }

    try {
      mod.resolved = this._resolve_module_dependencies(id, mod)
    } catch (e) {
      if (e.code == 'ENOTINSTALLED') {
        errmsg = 'Explicit version of dependency <%= deps.map(function(dep){return dep}).join(", ") %> <%= deps.length > 1 ? "are" : "is" %> not defined.\n file: <%= file %>'
      } else if (e.code == 'EOUTENTRY') {
        errmsg = 'Relative dependency "<%= deps[0] %>" out of main entry\'s directory. file: <%= file %>'
      } else {
        errmsg = e.message
      }
      e.file = id
      return callback(new Error(_.template(errmsg)(e)))
    }

    codes[id] = mod
  }

  callback(null, codes)
}

// @param {String} id Path(file entry) or package name(foreign package)
Builder.prototype._resolve_module_dependencies = function(id, mod) {
  var self = this
  var pkg = this.pkg
  var cwd = this.cwd
  var deps = mod.dependencies
  var resolved = {}

  ;['require', 'resolve', 'async'].forEach(function (key) {
    this._resolve_dependencies(id, mod, mod[key], resolved)
  }, this)

  return resolved
}

// @param {*Object} resolved
Builder.prototype._resolve_dependencies = function(id, mod, deps, resolved) {
  var module_name
  var r
  var real
  var not_installed = []

  for (module_name in deps) {
    real = deps[module_name]

    if (this._is_foreign(real)) {
      // check dependency versions and apply
      // 'jquery' -> 'jquery@^1.9.2'
      r = this._apply_dependency_version(real)

      if (!r) {
        not_installed.push(real)
      }

    } else {
      if (this._out_of_dir(module_name, id)) {
        throw {
          code: 'EOUTENTRY',
          deps: [module_name]
        }
      }
      r = this._generate_module_id(real)
    }

    resolved[module_name] = r
    this._add_to_global_map(module_name, r)
    this._add_locals(r)
  }

  if (not_installed.length) {
    throw {
      code: 'ENOTINSTALLED',
      deps: not_installed
    }
  }
}

Builder.prototype._add_to_global_map = function(key, value) {
  this.global_map[key] = value
}

Builder.prototype._generate_code = function(codes, callback) {
  var self = this
  this._wrap_all(codes, function (err, code) {
    if (err) {
      return callback(err)
    }

    callback(null, self._combile_statements(code))
  })
}

var CODE_TEMPLATE = [
  '(function(){'         ,
  ''                      ,
  'function mix(a, b){'   ,
  '  for(var k in b) {'   ,
  '    a[k] = b[k]'      ,
  '  }'                   ,
  '  return a'           ,
  '}'                     ,
  '<%= variables %>'      ,
  '<%= code %>'           ,
  ''                      ,
  '})()'

].join('\n')

Builder.prototype._combile_statements = function(code) {
  var locals = this.locals

  var statements = []
  function declare_varible(name, value, raw) {
    var statement = 'var ' + name + ' = ' + (raw ? value : JSON.stringify(value)) + ''
    if (value) {
      statements.push(statement)
    }
  }

  _.keys(locals).forEach(function(v) {
    declare_varible(locals[v], v)
  })

  declare_varible('global_map', this._stringify(this.global_map), true)

  return _.template(CODE_TEMPLATE)({
    variables: statements.join('\n'),
    code: code
  })
}

Builder.prototype._wrap_all = function(codes, callback) {
  var self = this
  var tasks = _.keys(codes).map(function (id) {
    return function (done) {
      self._wrap(id, codes[id], done)
    }
  })

  async.parallel(tasks, function (err, content_array) {
    if (err) {
      return callback(err)
    }

    callback(null, content_array.join('\n\n'))
  })
}

var WRAPPING_TEMPLATE =
    'define(<%= id %>, <%= deps %>, function(require, exports, module, __filename, __dirname) {\n'
  +   '<%= code %>\n'
  + '}<%= module_options ? ", " + module_options : "" %>)'

// Wrap a commonjs module with wrappings so that it could run in browsers
Builder.prototype._wrap = function(filename, mod, callback) {
  // id
  var module_id = this._generate_module_id(filename)

  // dependencies
  var resolved_dependencies = _.keys(mod.require).map(function (dep) {
    return mod.resolved[dep] || dep
  })

  // options
  var module_options = this._generate_module_options(filename, mod)

  var pairs = []
  if (module_options.main) {
    pairs.push('main: true')
  }

  var different
  var map
  if (module_options.map) {
    different = get_difference(module_options.map, this.global_map)
    map = _.keys(different).length
      ? 'mix(' + this._stringify(different) + ', global_map)'
      : 'global_map'

    pairs.push('map: ' + map)
  }

  module_options = pairs.length
    ? '{\n'
      + '  ' + pairs.join(',\n  ')
      + '\n}'
    : ''

  var result = _.template(WRAPPING_TEMPLATE)({
    id: this._stringify(module_id),
    deps: this._stringify(resolved_dependencies),
    code: mod.code,
    module_options: module_options
  })

  callback(null, result)
}

function get_difference (object, relative) {
  var parsed = {}
  var key
  for(key in object){
    if (relative[key] !== object[key]) {
      parsed[key] = object[key]
    }
  }
  return parsed
}

// filename: '/path/to/a.js'
// cwd: '/path'
// -> 'module@0.0.1/to/a.js'
Builder.prototype._generate_module_id = function(filename, relative) {
  // the exact identifier
  var cwd = this.cwd
  var pkg = this.pkg
  var main_id = [pkg.name, pkg.version].join('@')

  var relative_path = relative
    ? filename
    : node_path.relative(cwd, filename)

  // -> 'module@0.0.1/folder/foo'
  var id = node_path.join(main_id, relative_path)

  // fixes windows paths
  id = id
    .replace(new RegExp('\\' + node_path.sep, 'g'), '/')
    .toLowerCase()

  this._add_locals(id)
  return id
}

Builder.prototype._is_foreign = function(str) {
  var isWindowsAbsolute = str.match(/^\w+:\\/)
  var isRelative = ['../', './'].some(function(prefix) {
    return str.indexOf(prefix) === 0
  })
  var isUnixAbsolute = str.indexOf('/') == 0
  return !isRelative && !isUnixAbsolute && !isWindowsAbsolute
}

Builder.prototype._out_of_dir = function(dep, file) {
  var mod_path = node_path.resolve(node_path.join(node_path.dirname(file), dep))
  return mod_path.indexOf(this.cwd) == -1
}

// Returns `Object`
// - main: `Boolean`
// - map: `Object`
Builder.prototype._generate_module_options = function(id, mod) {
  var pkg = this.pkg
  var cwd = this.cwd
  var module_options = {}

  if (
    pkg.main &&
    node_path.resolve(id) === node_path.resolve(cwd, pkg.main)
  ) {
    module_options.main = true
  }

  if (_.keys(mod.resolved).length) {
    module_options.map = mod.resolved
  }

  return module_options
}

Builder.prototype._apply_dependency_version = function(module_name) {
  var pkg = this.pkg

  var module_id
  ['dependencies', 'asyncDependencies', 'devDependencies'].some(function (key) {
    var dependencies = pkg[key]
    if (!dependencies) {
      return
    }
    if (module_name in dependencies) {
      module_id = module_name + '@' + dependencies[module_name]
      return true
    }
  })

  return module_id
    ? module_id

    // If allow implicit dependencies
    : this.options.allow_implicit_dependencies
      ? module_name + '@*'
      : module_id
}

// {
//   '/path/to/a.js': '_0',
//   '/path/to/b.js': '_1'
// }
Builder.prototype._add_locals = function(val) {
  var locals = this.locals
  if (!locals[val]) {
    locals[val] = '_' + this._uuid ++
  }
}

function just_return (subject) {
  return subject
}

// Stringify subject and apply local variables
Builder.prototype._stringify = function(subject) {
  var locals = this.locals

  function to_locals(item) {
    return locals[item]
  }

  if (_.isString(subject)) {
    return to_locals(subject)
  }

  if (_.isArray(subject)) {
    return '[' + subject.map(to_locals).filter(just_return).join(', ') + ']'
  }

  if (_.isObject(subject)) {
    return '{\n'
    + _.keys(subject).map(function(k) {
      var value = to_locals(subject[k])
      return value
        ? '\'' + k + '\'' + ':' + value
        : null

    }).filter(just_return).join(',\n')
    + '\n}'
  }
}
<|endoftext|>