<commit_before>// dependencies
//
import React from 'react';
import update from 'react-addons-update';
import classnames from 'classnames';
import uniqueId from 'lodash/uniqueId';
import isRegExp from 'lodash/isRegExp';
import isFunction from 'lodash/isFunction';

// @TODO add different validation error messages for failing different rules
// @TODO horizontal form - label & input element widths
// @TODO permitted characters regex
// @TODO CurrencyInput - must clear non-numeric characters when reporting value
// @TODO DateInput - must ensure date is formatted as M/D/YYYY when reporting value

/**
 * The TextInput component
 *
 */
class TextInput extends React.Component {
    /**
     * Construct the component instance
     * @param  {Object} props The component props
     */
    constructor(props) {
        super(props);

        // format the value if we have a format method
        //
        const value = props.format ? props.format(props.value) : props.value;

        // initialize the state for the component
        //
        this.state = {
            value,
            isValid:   true,
            isEditing: false,
        };

        // generate a unique ID for this component instance if an ID prop has
        // not been provided
        //
        this.id = this.props.id || uniqueId('form-textinput-');

        // intialize the validation message for the component
        //
        this.validationMessage = props.validationMessage
            || `${this.props.description} is required`;

        // bind `this` to the component event handlers
        //
        this.onBlur = this.onBlur.bind(this);
        this.onFocus = this.onFocus.bind(this);
        this.onChange = this.onChange.bind(this);
    }

    /**
     * Handle the "component is about to mount" event
     */
    componentWillMount() {
        // determine if it's valid
        //
        const isValid = this.validate(this.state.value);

        // call the `onChildValidationEvent` handler once with
        // `hasValidated`=false, just to ensure that the parent knows about this
        // child
        //
        if (this.context.onChildValidationEvent) {
            this.context.onChildValidationEvent(
                this.id,
                false,
                isValid ? null : this.validationMessage
            );
        }
    }

    /**
     * Handle new props received from parent components
     * @param  {Object} newProps The new properties for the component
     */
    componentWillReceiveProps(newProps) {
        // get the value from the event object
        //
        const value = newProps.value;

        // update the component state
        //
        this.setState((state) => update(state, { value: { $set: value } }));
    }

    /**
     * Handle the blur event for the input element
     * @param  {Object} event The event object
     */
    onBlur() {
        // get the value
        //
        const value = this.state.value;

        // determine if it's valid
        //
        const isValid = this.validate(value);

        // set the `isValid` state
        //
        this.setState(() => ({ value, isValid, isEditing: false }));

        // call the `onChildValidationEvent` handler
        //
        if (this.context.onChildValidationEvent) {
            this.context.onChildValidationEvent(
                this.id,
                true,
                isValid ? null : this.validationMessage
            );
        }

        // call the `onChange` handler
        //
        if (this.props.onChange) {
            this.props.onChange(this.props.format ? this.props.format(value) : value);
        }
    }

    /**
     * Handle the `onFocus` event
     */
    onFocus() {
        // do we have a parse prop? is the component NOT read only?
        //
        if (this.props.parse && !this.props.readOnly) {
            // yes! parse the value before editing begins
            //
            this.setState((state) => update(state, {
                value:     { $set: this.props.parse(this.state.value) },
                isEditing: { $set: true },
            }));
        }
    }

    /**
     * Handle the change event for the input element
     * @param  {Object} event The event object
     */
    onChange(event) {
        // get the value from the event object
        //
        const value = event.target.value;
        // update the component state
        //
        this.setState((state) => update(state, {
            value:     { $set: value },
            isEditing: { $set: true },
        }));

        // do we have an `onChange` handler? if so call it with the new value
        //
        if (this.props.onChange) {
            this.props.onChange(value);
        }
    }

    /**
     * Validate a value
     * @param  {String} value The value to validate
     * @return {Boolean}      True if the value is valid, false otherwise
     */
    validate(value) {
        // declare a variable to hold the result
        //
        let isValid = true;

        // do we have a value?
        //
        if (!value) {
            // we do not have a value - in this case, whether it's valid or not
            // is determined solely by whether a valid is required or not
            //
            isValid = !this.props.required;
        } else {
            // we do have a value. Do we have a pattern prop?
            //
            if (this.props.pattern) {
                // yes, we have a pattern prop. is the pattern a regex or is it
                // a function?
                //
                if (isRegExp(this.props.pattern)) {
                    // the pattern is a regex. Test the value against it
                    //
                    isValid = this.props.pattern.test(`${value}`);
                } else if (isFunction(this.props.pattern)) {
                    // the pattern is a function. Pass the value to the function
                    //
                    isValid = this.props.pattern(value);
                }
            } else {
                // we don't have a pattern prop. That means if we get here that
                // we have a value and it doesn't matter whether it's required
                // or not because we have a value
                //
                isValid = true;
            }
        }

        // return the results of the validation
        //
        return isValid;
    }

    /**
     * Render the component
     * @return {React.Element} The React element describing the component
     */
    render() {
        // is the component hidden? if so, return null
        //
        if (this.props.hidden) {
            return null;
        }

        const label = this.props.label
            ? <label
                htmlFor={this.id}
                className={classnames('control-label', {
                    [`col-xs-${this.context.labelColumns}`]: this.context.labelColumns,
                })}
            >
                {this.props.label}

            : null;
        // determine the value to display, formatting it if necessary
        //
        const value = (this.props.format && !this.state.isEditing)
            ? this.props.format(this.state.value)
            : this.state.value;

        // return the rendered component
        //
        return (

                {label}
                <input
                    type="text"
                    readOnly={!!this.props.readOnly}
                    id={this.id}
                    value={value}
                    placeholder={this.props.placeholder}
                    className="form-control"
                    onBlur={this.onBlur}
                    onFocus={this.onFocus}
                    onChange={this.onChange}
                />
                {!this.state.isValid
                    ? {this.validationMessage}
                    : null
                }

        );
    }
}

// set the property types for the component
//
TextInput.propTypes = {
    required:          React.PropTypes.bool,
    readOnly:          React.PropTypes.bool,
    hidden:            React.PropTypes.bool,
    id:                React.PropTypes.string,
    value:             React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    label:             React.PropTypes.string,
    placeholder:       React.PropTypes.string,
    description:       React.PropTypes.string,
    validationMessage: React.PropTypes.string,
    pattern:           (props, propName, componentName) => {
        if (props.pattern && !isRegExp(props.pattern) && !isFunction(props.pattern)) {
            return new Error(
                `Invalid prop ${propName} supplied to ${componentName}` +
                ' - should be a regular expression'
            );
        }
        return null;
    },
    format:            React.PropTypes.func,
    parse:             React.PropTypes.func,
    onChange:          React.PropTypes.func,
    validationKey:     React.PropTypes.string,
};

// set the context types for values received from higher up the food chain
//
TextInput.contextTypes = {
    onChildValidationEvent: React.PropTypes.func,
    labelColumns:           React.PropTypes.number,
};

// export the component
//
export default TextInput;
<commit_msg>code cleanp<commit_after>// dependencies
//
import React from 'react';
import update from 'react-addons-update';
import classnames from 'classnames';
import uniqueId from 'lodash/uniqueId';
import isRegExp from 'lodash/isRegExp';
import isFunction from 'lodash/isFunction';

// @TODO add different validation error messages for failing different rules
// @TODO horizontal form - label & input element widths
// @TODO permitted characters regex
// @TODO CurrencyInput - must clear non-numeric characters when reporting value
// @TODO DateInput - must ensure date is formatted as M/D/YYYY when reporting value

/**
 * The TextInput component
 *
 */
class TextInput extends React.Component {
    /**
     * Construct the component instance
     * @param  {Object} props The component props
     */
    constructor(props) {
        super(props);

        // format the value if we have a format method
        //
        const value = props.format ? props.format(props.value) : props.value;

        // initialize the state for the component
        //
        this.state = {
            value,
            isValid:   true,
            isEditing: false,
        };

        // generate a unique ID for this component instance if an ID prop has
        // not been provided
        //
        this.id = this.props.id || uniqueId('form-textinput-');

        // intialize the validation message for the component
        //
        this.validationMessage = props.validationMessage
            || `${this.props.description} is required`;

        // bind `this` to the component event handlers
        //
        this.onBlur = this.onBlur.bind(this);
        this.onFocus = this.onFocus.bind(this);
        this.onChange = this.onChange.bind(this);
    }

    /**
     * Handle the "component is about to mount" event
     */
    componentWillMount() {
        // determine if it's valid
        //
        const isValid = this.validate(this.state.value);

        // call the `onChildValidationEvent` handler once with
        // `hasValidated`=false, just to ensure that the parent knows about this
        // child
        //
        if (this.context.onChildValidationEvent) {
            this.context.onChildValidationEvent(
                this.id,
                false,
                isValid ? null : this.validationMessage
            );
        }
    }

    /**
     * Handle new props received from parent components
     * @param  {Object} newProps The new properties for the component
     */
    componentWillReceiveProps(newProps) {
        // get the value from the event object
        //
        const value = newProps.value;

        // update the component state
        //
        this.setState((state) => update(state, { value: { $set: value } }));
    }

    /**
     * Handle the blur event for the input element
     * @param  {Object} event The event object
     */
    onBlur() {
        // get the value
        //
        const value = this.state.value;

        // determine if it's valid
        //
        const isValid = this.validate(value);

        // set the `isValid` state
        //
        this.setState(() => ({ value, isValid, isEditing: false }));

        // call the `onChildValidationEvent` handler
        //
        if (this.context.onChildValidationEvent) {
            this.context.onChildValidationEvent(
                this.id,
                true,
                isValid ? null : this.validationMessage
            );
        }

        // call the `onChange` handler
        //
        if (this.props.onChange) {
            this.props.onChange(this.props.format ? this.props.format(value) : value);
        }
    }

    /**
     * Handle the `onFocus` event
     */
    onFocus() {
        // do we have a parse prop? is the component NOT read only?
        //
        if (this.props.parse && !this.props.readOnly) {
            // yes! parse the value before editing begins
            //
            this.setState((state) => update(state, {
                value:     { $set: this.props.parse(this.state.value) },
                isEditing: { $set: true },
            }));
        }
    }

    /**
     * Handle the change event for the input element
     * @param  {Object} event The event object
     */
    onChange(event) {
        // get the value from the event object
        //
        const value = event.target.value;
        // update the component state
        //
        this.setState((state) => update(state, {
            value:     { $set: value },
            isEditing: { $set: true },
        }));

        // do we have an `onChange` handler? if so call it with the new value
        //
        if (this.props.onChange) {
            this.props.onChange(value);
        }
    }

    /**
     * Validate a value
     * @param  {String} value The value to validate
     * @return {Boolean}      True if the value is valid, false otherwise
     */
    validate(value) {
        // declare a variable to hold the result
        //
        let isValid = true;

        // do we have a value?
        //
        if (!value) {
            // we do not have a value - in this case, whether it's valid or not
            // is determined solely by whether a valid is required or not
            //
            isValid = !this.props.required;
        } else {
            // we do have a value. Do we have a pattern prop?
            //
            if (this.props.pattern) {
                // yes, we have a pattern prop. is the pattern a regex or is it
                // a function?
                //
                if (isRegExp(this.props.pattern)) {
                    // the pattern is a regex. Test the value against it
                    //
                    isValid = this.props.pattern.test(`${value}`);
                } else if (isFunction(this.props.pattern)) {
                    // the pattern is a function. Pass the value to the function
                    //
                    isValid = this.props.pattern(value);
                }
            } else {
                // we don't have a pattern prop. That means if we get here that
                // we have a value and it doesn't matter whether it's required
                // or not because we have a value
                //
                isValid = true;
            }
        }

        // return the results of the validation
        //
        return isValid;
    }

    /**
     * Render the component
     * @return {React.Element} The React element describing the component
     */
    render() {
        // is the component hidden? if so, return null
        //
        if (this.props.hidden) {
            return null;
        }

        const label = this.props.label
            ? <label
                htmlFor={this.id}
                className={classnames('control-label', {
                    [`col-xs-${this.context.labelColumns}`]: this.context.labelColumns,
                })}
            >
                {this.props.label}

            : null;

        // determine the value to display, formatting it if necessary
        //
        const value = (this.props.format && !this.state.isEditing)
            ? this.props.format(this.state.value)
            : this.state.value;

        // return the rendered component
        //
        return (

                {label}
                <input
                    type="text"
                    readOnly={!!this.props.readOnly}
                    id={this.id}
                    value={value}
                    placeholder={this.props.placeholder}
                    className="form-control"
                    onBlur={this.onBlur}
                    onFocus={this.onFocus}
                    onChange={this.onChange}
                />
                {!this.state.isValid
                    ? {this.validationMessage}
                    : null
                }

        );
    }
}

// set the property types for the component
//
TextInput.propTypes = {
    required:          React.PropTypes.bool,
    readOnly:          React.PropTypes.bool,
    hidden:            React.PropTypes.bool,
    id:                React.PropTypes.string,
    value:             React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    label:             React.PropTypes.string,
    placeholder:       React.PropTypes.string,
    description:       React.PropTypes.string,
    validationMessage: React.PropTypes.string,
    pattern:           (props, propName, componentName) => {
        if (props.pattern && !isRegExp(props.pattern) && !isFunction(props.pattern)) {
            return new Error(
                `Invalid prop ${propName} supplied to ${componentName}` +
                ' - should be a regular expression'
            );
        }
        return null;
    },
    format:            React.PropTypes.func,
    parse:             React.PropTypes.func,
    onChange:          React.PropTypes.func,
    validationKey:     React.PropTypes.string,
};

// set the context types for values received from higher up the food chain
//
TextInput.contextTypes = {
    onChildValidationEvent: React.PropTypes.func,
    labelColumns:           React.PropTypes.number,
};

// export the component
//
export default TextInput;
<|endoftext|>


<commit_before>import _findIndex from "lodash/findIndex";
import _findLastIndex from "lodash/findLastIndex";
import _max from "lodash/max";
import { line, curveBasis } from "d3-shape";
import { easeLinear } from "d3-ease";
import { demeCountMultiplier, demeCountMinimum } from "../../util/globals";

/* util */

export const pathStringGenerator = line()
  .x((d) => { return d.x; })
  .y((d) => { return d.y; })
  .curve(curveBasis);

const extractLineSegmentForAnimationEffect = (
  numDateMin,
  numDateMax,
  originCoords,
  destinationCoords,
  originNumDate,
  destinationNumDate,
  visible,
  bezierCurve,
  bezierDates
) => {

  if (visible === "hidden") {
    return [];
  }

  // want to slice out all points that lie between numDateMin and numDateMax
  // and append interpolated start and end points
  // initial data
  // bezierDates = [ 2015.1    2015.2    2015.3    2015.4    2015.5 ]
  // bezierCurve = [ x0,y0     x1,y1     x2,y2     x3,y3     x4,y4  ]
  //
  // scenario A: numDateMin = 2015.25, numDateMax = 2015.45
  // bezierDates = [ 2015.25  2015.3    2015.4  2015.45 ]
  // bezierCurve = [ x12,y12  x2,y2     x3,y3   x34,y34 ]
  // startIndex is 2 in scenario A
  // endIndex is 3 in scenario A
  //
  // scenario B: numDateMin = 2014.5, numDateMax = 2015.45
  // bezierDates = [ 2015.1    2015.2    2015.3    2015.4  2015.45 ]
  // bezierCurve = [ x0,y0     x1,y1     x2,y2     x3,y3   x34,y34 ]
  // startIndex is 0 in scenario B
  // endIndex is 3 in scenario B
  //
  // scenario C: numDateMin = 2015.25, numDateMax = 2015.7
  // bezierDates = [ 2015.25  2015.3    2015.4    2015.5 ]
  // bezierCurve = [ x12,y12  x2,y2     x3,y3     x4,y4  ]
  // startIndex is 2 in scenario C
  // endIndex is 4 in scenario C
  //
  // scenario D: numDateMin = 2015.6, numDateMax = 2015.9
  // bezierDates = [ ]
  // bezierCurve = [ ]
  // startIndex is -1 in scenario D
  // endIndex is 4 in scenario D

  // find start walking forwards from left of array
  const startIndex = _findIndex(bezierDates, (d) => { return d > numDateMin; });

  // find end walking backwards from right of array
  const endIndex = _findLastIndex(bezierDates, (d) => { return d < numDateMax; });

  // startIndex and endIndex is -1 if not found
  // this indicates a slice of time that lies outside the bounds of BCurve
  // return empty array
  if (startIndex === -1 || endIndex === -1) {
    return [];
  }

  // get curve
  // slice takes index at begin
  // slice extracts up to but not including end
  const curve = bezierCurve.slice(startIndex, endIndex + 1);

  // if possible construct and prepend interpolated start
  let newStart;
  if (startIndex > 0) {
    // determine weighting of positions at startIndex and startIndex-1
    const dateDiff = bezierDates[startIndex] - bezierDates[startIndex - 1];
    const weightRight = (numDateMin - bezierDates[startIndex - 1]) / dateDiff;
    const weightLeft = (bezierDates[startIndex] - numDateMin) / dateDiff;
    // construct interpolated new start
    newStart = {
      x: (weightLeft * bezierCurve[startIndex - 1].x) + (weightRight * bezierCurve[startIndex].x),
      y: (weightLeft * bezierCurve[startIndex - 1].y) + (weightRight * bezierCurve[startIndex].y)
    };
    // will break indexing, so wait to prepend
  }

  // if possible construct and prepend interpolated start
  let newEnd;
  if (endIndex < bezierCurve.length - 1) {
    // determine weighting of positions at startIndex and startIndex-1
    const dateDiff = bezierDates[endIndex + 1] - bezierDates[endIndex];
    const weightRight = (numDateMax - bezierDates[endIndex]) / dateDiff;
    const weightLeft = (bezierDates[endIndex + 1] - numDateMax) / dateDiff;
    // construct interpolated new end
    newEnd = {
      x: (weightLeft * bezierCurve[endIndex].x) + (weightRight * bezierCurve[endIndex + 1].x),
      y: (weightLeft * bezierCurve[endIndex].y) + (weightRight * bezierCurve[endIndex + 1].y)
    };
    // will break indexing, so wait to append
  }

  // prepend / append interpolated points if they exist
  if (newStart) {
    curve.unshift(newStart);
  }
  if (newEnd) {
    curve.push(newEnd);
  }
  return curve;
};

export const drawDemesAndTransmissions = (
  demeData,
  transmissionData,
  g,
  map,
  nodes,
  numDateMin,
  numDateMax
) => {

  // add transmission lines
  const transmissions = g.selectAll("transmissions")
    .data(transmissionData)
    .enter()
    .append("path") /* instead of appending a geodesic path from the leaflet plugin data, we now draw a line directly between two points */
    .attr("d", (d) => {
      return pathStringGenerator(
        extractLineSegmentForAnimationEffect(
          numDateMin,
          numDateMax,
          d.originCoords,
          d.destinationCoords,
          d.originNumDate,
          d.destinationNumDate,
          d.visible,
          d.bezierCurve,
          d.bezierDates
        )
      );
    })
    .attr("fill", "none")
    .attr("stroke-opacity", 0.6)
    .attr("stroke-linecap", "round")
    .attr("stroke", (d) => { return d.color; })
    .attr("stroke-width", 1);

  // add demes
  const demeMultiplier = demeCountMultiplier / Math.sqrt(_max([nodes.length, demeCountMinimum]));
  const demes = g.selectAll("demes")
    .data(demeData)
    .enter().append("circle")
    .style("stroke", "none")
    .style("fill-opacity", 0.65)
    .style("fill", (d) => { return d.color; })
    .attr("r", (d) => { return demeMultiplier * Math.sqrt(d.count); })
    .attr("transform", (d) => {
      return "translate(" + d.coords.x + "," + d.coords.y + ")";
    });

  return {
    demes,
    transmissions
  };

};

export const updateOnMoveEnd = (demeData, transmissionData, d3elems, numDateMin, numDateMax) => {
  /* map has moved or rescaled, make demes and transmissions line up */
  if (d3elems) {
    d3elems.demes
      .data(demeData)
      .attr("transform", (d) => {
        return "translate(" + d.coords.x + "," + d.coords.y + ")";
      });

    d3elems.transmissions
      .data(transmissionData)
      .attr("d", (d) => {
        return pathStringGenerator(
          extractLineSegmentForAnimationEffect(
            numDateMin,
            numDateMax,
            d.originCoords,
            d.destinationCoords,
            d.originNumDate,
            d.destinationNumDate,
            d.visible,
            d.bezierCurve,
            d.bezierDates
          )
        );
      }); // other attrs remain the same as they were

  }
};

export const updateVisibility = (
  demeData,
  transmissionData,
  d3elems,
  map,
  nodes,
  numDateMin,
  numDateMax
) => {

  const demeMultiplier = demeCountMultiplier / Math.sqrt(_max([nodes.length, demeCountMinimum]));
  d3elems.demes
    .data(demeData)
    .transition()
    .duration(200)
    .ease(easeLinear)
    .style("fill", (d) => { return d.count > 0 ? d.color : "white"; })
    .attr("r", (d) => { return demeMultiplier * Math.sqrt(d.count); });

  d3elems.transmissions
    .data(transmissionData)
    .attr("d", (d) => {
      return pathStringGenerator(
        extractLineSegmentForAnimationEffect(
          numDateMin,
          numDateMax,
          d.originCoords,
          d.destinationCoords,
          d.originNumDate,
          d.destinationNumDate,
          d.visible,
          d.bezierCurve,
          d.bezierDates
        )
      );
    }) /* with the interpolation in the function above pathStringGenerator */
    .attr("stroke", (d) => { return d.color; });
};

/* template for an update helper */
export const updateFoo = (d3elems, latLongs) => {
  d3elems.demes
    .data(latLongs.demes);

  d3elems.transmissions
    .data(latLongs.transmissions);
};

// const missiles = transmissionPaths.map((transmissionPath) => {
//
//   // console.log(transmissionPath)
//
//   const missile = g.append("circle")
//     .attr("r", 0)
//     .attr("fill", (d) => { return colorScale(transmissionPath.transmission.to) })
//     .attr("transform", `translate(
//       ${transmissionPath.partialTransmission[0].x},
//       ${transmissionPath.partialTransmission[0].y}
//     )`) /* begin the missile on the start of the line */
//     // .transition()
//     // .duration(5000)
//     // .attrTween("transform", translateAlong(transmissionPath.elem.node()));
//
//   return missile;
// })

// const setTipCoords = () => {
//   demes.attr("transform", (d) => {
//     return "translate(" + d.coords.x + "," + d.coords.y + ")";
//   });
// };

// const animateTransmissions = () => {
//   /* point along path interpolation https://bl.ocks.org/mbostock/1705868 */
//
// }

// setTipCoords();
// map.on("viewreset", setTipCoords); /* search: -Note (A) for an idea as to why this might not be working properly */
// animateTransmissions();

/*
  http://gis.stackexchange.com/questions/49114/d3-geo-path-to-draw-a-path-from-gis-coordinates
  https://bl.ocks.org/mbostock/3916621  // Compute point-interpolators at each distance.
  http://bl.ocks.org/mbostock/5851933 // draw line on map
  https://gist.github.com/mikeatlas/0b69b354a8d713989147 // polyline split if we don't use leaflet
  http://bl.ocks.org/mbostock/5928813
  http://bl.ocks.org/duopixel/4063326 // animate path in
  https://bl.ocks.org/mbostock/1705868 // point along path interpolation
  https://bl.ocks.org/mbostock/1313857 // point along path interpolation
  https://github.com/d3/d3-shape/blob/master/README.md#curves
  https://github.com/d3/d3-shape/blob/master/README.md#lines
*/

// since we're now using d3 we'll probably do something like http://stackoverflow.com/questions/11808860/arrow-triangles-on-my-svg-line/11809868#11809868
// decorator docs: https://github.com/bbecquet/Leaflet.PolylineDecorator
<commit_msg>Add gentle borders to deme circles<commit_after>import _findIndex from "lodash/findIndex";
import _findLastIndex from "lodash/findLastIndex";
import _max from "lodash/max";
import { line, curveBasis } from "d3-shape";
import { easeLinear } from "d3-ease";
import { demeCountMultiplier, demeCountMinimum } from "../../util/globals";

/* util */

export const pathStringGenerator = line()
  .x((d) => { return d.x; })
  .y((d) => { return d.y; })
  .curve(curveBasis);

const extractLineSegmentForAnimationEffect = (
  numDateMin,
  numDateMax,
  originCoords,
  destinationCoords,
  originNumDate,
  destinationNumDate,
  visible,
  bezierCurve,
  bezierDates
) => {

  if (visible === "hidden") {
    return [];
  }

  // want to slice out all points that lie between numDateMin and numDateMax
  // and append interpolated start and end points
  // initial data
  // bezierDates = [ 2015.1    2015.2    2015.3    2015.4    2015.5 ]
  // bezierCurve = [ x0,y0     x1,y1     x2,y2     x3,y3     x4,y4  ]
  //
  // scenario A: numDateMin = 2015.25, numDateMax = 2015.45
  // bezierDates = [ 2015.25  2015.3    2015.4  2015.45 ]
  // bezierCurve = [ x12,y12  x2,y2     x3,y3   x34,y34 ]
  // startIndex is 2 in scenario A
  // endIndex is 3 in scenario A
  //
  // scenario B: numDateMin = 2014.5, numDateMax = 2015.45
  // bezierDates = [ 2015.1    2015.2    2015.3    2015.4  2015.45 ]
  // bezierCurve = [ x0,y0     x1,y1     x2,y2     x3,y3   x34,y34 ]
  // startIndex is 0 in scenario B
  // endIndex is 3 in scenario B
  //
  // scenario C: numDateMin = 2015.25, numDateMax = 2015.7
  // bezierDates = [ 2015.25  2015.3    2015.4    2015.5 ]
  // bezierCurve = [ x12,y12  x2,y2     x3,y3     x4,y4  ]
  // startIndex is 2 in scenario C
  // endIndex is 4 in scenario C
  //
  // scenario D: numDateMin = 2015.6, numDateMax = 2015.9
  // bezierDates = [ ]
  // bezierCurve = [ ]
  // startIndex is -1 in scenario D
  // endIndex is 4 in scenario D

  // find start walking forwards from left of array
  const startIndex = _findIndex(bezierDates, (d) => { return d > numDateMin; });

  // find end walking backwards from right of array
  const endIndex = _findLastIndex(bezierDates, (d) => { return d < numDateMax; });

  // startIndex and endIndex is -1 if not found
  // this indicates a slice of time that lies outside the bounds of BCurve
  // return empty array
  if (startIndex === -1 || endIndex === -1) {
    return [];
  }

  // get curve
  // slice takes index at begin
  // slice extracts up to but not including end
  const curve = bezierCurve.slice(startIndex, endIndex + 1);

  // if possible construct and prepend interpolated start
  let newStart;
  if (startIndex > 0) {
    // determine weighting of positions at startIndex and startIndex-1
    const dateDiff = bezierDates[startIndex] - bezierDates[startIndex - 1];
    const weightRight = (numDateMin - bezierDates[startIndex - 1]) / dateDiff;
    const weightLeft = (bezierDates[startIndex] - numDateMin) / dateDiff;
    // construct interpolated new start
    newStart = {
      x: (weightLeft * bezierCurve[startIndex - 1].x) + (weightRight * bezierCurve[startIndex].x),
      y: (weightLeft * bezierCurve[startIndex - 1].y) + (weightRight * bezierCurve[startIndex].y)
    };
    // will break indexing, so wait to prepend
  }

  // if possible construct and prepend interpolated start
  let newEnd;
  if (endIndex < bezierCurve.length - 1) {
    // determine weighting of positions at startIndex and startIndex-1
    const dateDiff = bezierDates[endIndex + 1] - bezierDates[endIndex];
    const weightRight = (numDateMax - bezierDates[endIndex]) / dateDiff;
    const weightLeft = (bezierDates[endIndex + 1] - numDateMax) / dateDiff;
    // construct interpolated new end
    newEnd = {
      x: (weightLeft * bezierCurve[endIndex].x) + (weightRight * bezierCurve[endIndex + 1].x),
      y: (weightLeft * bezierCurve[endIndex].y) + (weightRight * bezierCurve[endIndex + 1].y)
    };
    // will break indexing, so wait to append
  }

  // prepend / append interpolated points if they exist
  if (newStart) {
    curve.unshift(newStart);
  }
  if (newEnd) {
    curve.push(newEnd);
  }
  return curve;
};

export const drawDemesAndTransmissions = (
  demeData,
  transmissionData,
  g,
  map,
  nodes,
  numDateMin,
  numDateMax
) => {

  // add transmission lines
  const transmissions = g.selectAll("transmissions")
    .data(transmissionData)
    .enter()
    .append("path") /* instead of appending a geodesic path from the leaflet plugin data, we now draw a line directly between two points */
    .attr("d", (d) => {
      return pathStringGenerator(
        extractLineSegmentForAnimationEffect(
          numDateMin,
          numDateMax,
          d.originCoords,
          d.destinationCoords,
          d.originNumDate,
          d.destinationNumDate,
          d.visible,
          d.bezierCurve,
          d.bezierDates
        )
      );
    })
    .attr("fill", "none")
    .attr("stroke-opacity", 0.6)
    .attr("stroke-linecap", "round")
    .attr("stroke", (d) => { return d.color; })
    .attr("stroke-width", 1);

  // add demes
  const demeMultiplier = demeCountMultiplier / Math.sqrt(_max([nodes.length, demeCountMinimum]));
  const demes = g.selectAll("demes")
    .data(demeData)
    .enter().append("circle")
    .style("stroke", "none")
    .style("fill-opacity", 0.65)
    .style("fill", (d) => { return d.color; })
    .style("stroke-opacity", 0.85)
    .style("stroke", (d) => { return d.color; })
    .attr("r", (d) => { return demeMultiplier * Math.sqrt(d.count); })
    .attr("transform", (d) => {
      return "translate(" + d.coords.x + "," + d.coords.y + ")";
    });

  return {
    demes,
    transmissions
  };

};

export const updateOnMoveEnd = (demeData, transmissionData, d3elems, numDateMin, numDateMax) => {
  /* map has moved or rescaled, make demes and transmissions line up */
  if (d3elems) {
    d3elems.demes
      .data(demeData)
      .attr("transform", (d) => {
        return "translate(" + d.coords.x + "," + d.coords.y + ")";
      });

    d3elems.transmissions
      .data(transmissionData)
      .attr("d", (d) => {
        return pathStringGenerator(
          extractLineSegmentForAnimationEffect(
            numDateMin,
            numDateMax,
            d.originCoords,
            d.destinationCoords,
            d.originNumDate,
            d.destinationNumDate,
            d.visible,
            d.bezierCurve,
            d.bezierDates
          )
        );
      }); // other attrs remain the same as they were

  }
};

export const updateVisibility = (
  demeData,
  transmissionData,
  d3elems,
  map,
  nodes,
  numDateMin,
  numDateMax
) => {

  const demeMultiplier = demeCountMultiplier / Math.sqrt(_max([nodes.length, demeCountMinimum]));
  d3elems.demes
    .data(demeData)
    .transition()
    .duration(200)
    .ease(easeLinear)
    .style("fill", (d) => { return d.count > 0 ? d.color : "white"; })
    .attr("r", (d) => { return demeMultiplier * Math.sqrt(d.count); });

  d3elems.transmissions
    .data(transmissionData)
    .attr("d", (d) => {
      return pathStringGenerator(
        extractLineSegmentForAnimationEffect(
          numDateMin,
          numDateMax,
          d.originCoords,
          d.destinationCoords,
          d.originNumDate,
          d.destinationNumDate,
          d.visible,
          d.bezierCurve,
          d.bezierDates
        )
      );
    }) /* with the interpolation in the function above pathStringGenerator */
    .attr("stroke", (d) => { return d.color; });
};

/* template for an update helper */
export const updateFoo = (d3elems, latLongs) => {
  d3elems.demes
    .data(latLongs.demes);

  d3elems.transmissions
    .data(latLongs.transmissions);
};

// const missiles = transmissionPaths.map((transmissionPath) => {
//
//   // console.log(transmissionPath)
//
//   const missile = g.append("circle")
//     .attr("r", 0)
//     .attr("fill", (d) => { return colorScale(transmissionPath.transmission.to) })
//     .attr("transform", `translate(
//       ${transmissionPath.partialTransmission[0].x},
//       ${transmissionPath.partialTransmission[0].y}
//     )`) /* begin the missile on the start of the line */
//     // .transition()
//     // .duration(5000)
//     // .attrTween("transform", translateAlong(transmissionPath.elem.node()));
//
//   return missile;
// })

// const setTipCoords = () => {
//   demes.attr("transform", (d) => {
//     return "translate(" + d.coords.x + "," + d.coords.y + ")";
//   });
// };

// const animateTransmissions = () => {
//   /* point along path interpolation https://bl.ocks.org/mbostock/1705868 */
//
// }

// setTipCoords();
// map.on("viewreset", setTipCoords); /* search: -Note (A) for an idea as to why this might not be working properly */
// animateTransmissions();

/*
  http://gis.stackexchange.com/questions/49114/d3-geo-path-to-draw-a-path-from-gis-coordinates
  https://bl.ocks.org/mbostock/3916621  // Compute point-interpolators at each distance.
  http://bl.ocks.org/mbostock/5851933 // draw line on map
  https://gist.github.com/mikeatlas/0b69b354a8d713989147 // polyline split if we don't use leaflet
  http://bl.ocks.org/mbostock/5928813
  http://bl.ocks.org/duopixel/4063326 // animate path in
  https://bl.ocks.org/mbostock/1705868 // point along path interpolation
  https://bl.ocks.org/mbostock/1313857 // point along path interpolation
  https://github.com/d3/d3-shape/blob/master/README.md#curves
  https://github.com/d3/d3-shape/blob/master/README.md#lines
*/

// since we're now using d3 we'll probably do something like http://stackoverflow.com/questions/11808860/arrow-triangles-on-my-svg-line/11809868#11809868
// decorator docs: https://github.com/bbecquet/Leaflet.PolylineDecorator
<|endoftext|>


<commit_before>const statsd = require('./statsd')
const githubQueue = require('./github-queue')
const _ = require('lodash')

const { getNewLockfile } = require('../lib/lockfile')
const { getLockfilePath } = require('../utils/utils')
const { getMessage } = require('../lib/get-message')
const { getGithubFile } = require('../lib/get-files')

const Log = require('gk-log')
const dbs = require('../lib/dbs')

global.Promise = require('bluebird')

module.exports = async (
  {
    installationId,
    newBranch,
    branch,
    owner,
    repoName,
    repoDoc,
    message,
    transforms,
    path,
    transform,
    processLockfiles,
    commitMessageTemplates
  }
) => {
  if (!transforms) transforms = [{ transform, path, message }]
  const ghqueue = githubQueue(installationId)
  let contents = {}

  const logs = dbs.getLogsDb()
  const log = Log({
    logsDb: logs,
    accountId: repoDoc ? repoDoc.accountId : '',
    repoSlug: repoDoc ? repoDoc.fullName : '',
    context: 'create-branch' })

  const commits = (await Promise.mapSeries(transforms, async (
    { path, transform, message, create },
    index
  ) => {
    let blob = {}
    try {
      if (contents[path]) {
        blob.content = contents[path]
      } else {
        if (path === 'README.md') {
          blob = await ghqueue.read(github => github.repos.getReadme({ owner, repo: repoName, ref: branch }))
          path = blob.path
        } else {
          blob = await getGithubFile(ghqueue, { path, owner, repo: repoName, ref: branch }, log)
        }
      }
    } catch (e) {
      if (e.status !== 404) throw e
      if (!create) return
    }
    let oldContent
    if (contents[path]) {
      oldContent = contents[path]
    } else {
      oldContent = blob.content ? Buffer.from(blob.content, 'base64').toString() : ''
    }

    contents[path] = await transform(oldContent, path)
    if (!contents[path] || contents[path] === oldContent) return
    return { path, content: contents[path], message, index }
  })).filter(c => c)

  if (commits.length === 0) return

  /*
  After processing all the transforms and checking whether they generated any commits,
  we check each commit whether it affected a `package.json`, and generate its lockfile,
  if applicable.

  Note that there are no transforms for these commits. They are added on to the end of
  the commits array and receive an index value, but that doesn’t correspond to an index
  of the transforms array.

  Transforms array:
  ['readme', 'travis', 'package.json', 'yay/package.json']
  Commit array with lockfiles (lockfiles are in reverse order):
  ['readme', 'travis', 'package.json', 'yay/package.json', 'yay/package-lock.json', 'package-lock.json']

  */
  if (processLockfiles && repoDoc && repoDoc.files) {
    // we need to iterate over every changed package file, not every package file commit
    // we reverse because we want the most recent commit with the all the changes to the file (the last one)
    // we clone because we don’t actually want to do the commits backwards
    const dedupedCommits = _.uniqBy(_.clone(commits).reverse(), commit => commit.path)
    for (const commit of dedupedCommits) {
      // continue skips the current iteration but continues with the for loop as a whole
      if (!commit.path.includes('package.json')) continue
      const lockfilePath = getLockfilePath(repoDoc.files, commit.path)

      if (!lockfilePath) continue
      const versions = transforms.map(transform => {
        return {
          dependency: transform.dependency,
          version: transform.version,
          oldVersion: transform.oldVersion
        }
      })
      log.info('starting lockfile update', { lockfilePath, versions })

      const oldLockfile = await getGithubFile(ghqueue, { path: lockfilePath, owner, repo: repoName, sha: branch }, log)
      const oldLockfileContent = Buffer.from(oldLockfile.content, 'base64').toString()

      const isNpm = lockfilePath.includes('package-lock.json')
      try {
        const { tokens, 'token-audits': tokenAudits } = await dbs() // eslint-disable-line

        /*
        This is the structure of the tokens 'model'
        _id: `${accountId}
          tokens: {
            ${repoId}: {
            npm: ${token},
            github: ${token}
          }
        }
        */
        let execTokens = ''
        let repositoryTokens = ''
        try {
          repositoryTokens = await tokens.get(repoDoc.accountId)
        } catch (error) {
          log.error(`Unable to get repository token`, { lockfilePath, error })
        }

        if (repositoryTokens) {
          execTokens = JSON.stringify(repositoryTokens.tokens[repoDoc._id])
          const datetime = new Date().toISOString().substr(0, 19).replace(/[^0-9]/g, '')

          // write audit log entry to 'token-audits' db
          // log entry type: 'read'
          try {
            await tokenAudits.put({
              _id: `${installationId}:${repoDoc._id}:${datetime}:read`,
              keys: Object.keys(repositoryTokens.tokens[repoDoc._id])
            })
          } catch (error) {
            log.error(`Unable to store token audit log`, { lockfilePath, error })
          }
        }

        const { ok, contents, error } = await getNewLockfile({ packageJson: commit.content, lock: oldLockfileContent, isNpm, repositoryTokens: execTokens })
        if (ok) {
          // !ok means the old and new lockfile are the same, so we don’t make a commit
          log.info(`new lockfile contents for ${lockfilePath} received`)
          statsd.increment('lockfiles')

          const lockfileCommitMessage = getMessage(commitMessageTemplates, 'lockfileUpdate', { lockfilePath: lockfilePath })

          commits.push({
            path: lockfilePath,
            content: contents,
            message: lockfileCommitMessage,
            index: commits.length
          })
          log.info(`created lockfile commit for ${lockfilePath}`, { lockfileCommitMessage })
        } else { // ok: false
          log.info(`error building lockfile for ${lockfilePath}`, { error })
        }
      } catch (e) {
        log.error('error fetching updated lockfile from exec server', { e: e.error || e })
      }
    }
  }

  const head = await ghqueue.read(github => github.gitdata.getRef({
    owner,
    repo: repoName,
    ref: `heads/${branch}`
  }))

  const createCommits = async (sha, { path, content, message, index }) => {
    const newTree = await ghqueue.write(github => github.gitdata.createTree({
      owner,
      repo: repoName,
      base_tree: sha,
      tree: [{ path, content, mode: '100644', type: 'blob' }]
    }))

    const commit = await ghqueue.write(github => github.gitdata.createCommit({
      owner,
      repo: repoName,
      message,
      tree: newTree.sha,
      parents: [sha]
    }))
    /*
      .created is written back into the original transform which is still used
      after create-branch is called from wherever, create-initial-branch for example. So after
      create-branch returns its SHA to create-initial-branch, the latter can check whether, for
      example, travis.yml or readme.md were modified. This is then passed into create-pr or
      whatever else sends messages to humans, where we can then notify them which files were
      MODIFIED (so the key is actually a misnomer).

      ⚠ Lockfiles only have commits, not transforms, so when they try to write back to their
      transform, they can’t, because there is none. That’s why we check whether there’s something at
      every index we want to update.
    */
    if (transforms[index]) {
      transforms[index].created = true
    }

    return commit.sha
  }

  const sha = await Promise.reduce(commits, createCommits, head.object.sha)

  try {
    await ghqueue.write(github => github.gitdata.createRef({
      owner,
      repo: repoName,
      sha,
      ref: 'refs/heads/' + newBranch
    }))
  } catch (err) {
    if (!err.message.includes('already exists')) throw err

    const branch = await ghqueue.read(github => github.repos.getBranch({
      owner,
      repo: repoName,
      branch: newBranch
    }))

    if (branch.commit.committer.type !== 'Bot') throw err

    return branch.commit.sha
  }

  statsd.increment('branches')

  return sha
}
<commit_msg>fix(createBranch): change logging types<commit_after>const statsd = require('./statsd')
const githubQueue = require('./github-queue')
const _ = require('lodash')

const { getNewLockfile } = require('../lib/lockfile')
const { getLockfilePath } = require('../utils/utils')
const { getMessage } = require('../lib/get-message')
const { getGithubFile } = require('../lib/get-files')

const Log = require('gk-log')
const dbs = require('../lib/dbs')

global.Promise = require('bluebird')

module.exports = async (
  {
    installationId,
    newBranch,
    branch,
    owner,
    repoName,
    repoDoc,
    message,
    transforms,
    path,
    transform,
    processLockfiles,
    commitMessageTemplates
  }
) => {
  if (!transforms) transforms = [{ transform, path, message }]
  const ghqueue = githubQueue(installationId)
  let contents = {}

  const logs = dbs.getLogsDb()
  const log = Log({
    logsDb: logs,
    accountId: repoDoc ? repoDoc.accountId : '',
    repoSlug: repoDoc ? repoDoc.fullName : '',
    context: 'create-branch' })

  const commits = (await Promise.mapSeries(transforms, async (
    { path, transform, message, create },
    index
  ) => {
    let blob = {}
    try {
      if (contents[path]) {
        blob.content = contents[path]
      } else {
        if (path === 'README.md') {
          blob = await ghqueue.read(github => github.repos.getReadme({ owner, repo: repoName, ref: branch }))
          path = blob.path
        } else {
          blob = await getGithubFile(ghqueue, { path, owner, repo: repoName, ref: branch }, log)
        }
      }
    } catch (e) {
      if (e.status !== 404) throw e
      if (!create) return
    }
    let oldContent
    if (contents[path]) {
      oldContent = contents[path]
    } else {
      oldContent = blob.content ? Buffer.from(blob.content, 'base64').toString() : ''
    }

    contents[path] = await transform(oldContent, path)
    if (!contents[path] || contents[path] === oldContent) return
    return { path, content: contents[path], message, index }
  })).filter(c => c)

  if (commits.length === 0) return

  /*
  After processing all the transforms and checking whether they generated any commits,
  we check each commit whether it affected a `package.json`, and generate its lockfile,
  if applicable.

  Note that there are no transforms for these commits. They are added on to the end of
  the commits array and receive an index value, but that doesn’t correspond to an index
  of the transforms array.

  Transforms array:
  ['readme', 'travis', 'package.json', 'yay/package.json']
  Commit array with lockfiles (lockfiles are in reverse order):
  ['readme', 'travis', 'package.json', 'yay/package.json', 'yay/package-lock.json', 'package-lock.json']

  */
  if (processLockfiles && repoDoc && repoDoc.files) {
    // we need to iterate over every changed package file, not every package file commit
    // we reverse because we want the most recent commit with the all the changes to the file (the last one)
    // we clone because we don’t actually want to do the commits backwards
    const dedupedCommits = _.uniqBy(_.clone(commits).reverse(), commit => commit.path)
    for (const commit of dedupedCommits) {
      // continue skips the current iteration but continues with the for loop as a whole
      if (!commit.path.includes('package.json')) continue
      const lockfilePath = getLockfilePath(repoDoc.files, commit.path)

      if (!lockfilePath) continue
      const versions = transforms.map(transform => {
        return {
          dependency: transform.dependency,
          version: transform.version,
          oldVersion: transform.oldVersion
        }
      })
      log.info('starting lockfile update', { lockfilePath, versions })

      const oldLockfile = await getGithubFile(ghqueue, { path: lockfilePath, owner, repo: repoName, sha: branch }, log)
      const oldLockfileContent = Buffer.from(oldLockfile.content, 'base64').toString()

      const isNpm = lockfilePath.includes('package-lock.json')
      try {
        const { tokens, 'token-audits': tokenAudits } = await dbs() // eslint-disable-line

        /*
        This is the structure of the tokens 'model'
        _id: `${accountId}
          tokens: {
            ${repoId}: {
            npm: ${token},
            github: ${token}
          }
        }
        */
        let execTokens = ''
        let repositoryTokens = ''
        try {
          repositoryTokens = await tokens.get(repoDoc.accountId)
        } catch (error) {
          log.error(`Unable to get repository token`, { lockfilePath, error })
        }

        if (repositoryTokens) {
          execTokens = JSON.stringify(repositoryTokens.tokens[repoDoc._id])
          const datetime = new Date().toISOString().substr(0, 19).replace(/[^0-9]/g, '')

          // write audit log entry to 'token-audits' db
          // log entry type: 'read'
          try {
            await tokenAudits.put({
              _id: `${installationId}:${repoDoc._id}:${datetime}:read`,
              keys: Object.keys(repositoryTokens.tokens[repoDoc._id])
            })
          } catch (error) {
            log.error(`Unable to store token audit log`, { lockfilePath, error })
          }
        }

        const { ok, contents, error } = await getNewLockfile({ packageJson: commit.content, lock: oldLockfileContent, isNpm, repositoryTokens: execTokens })
        if (ok) {
          // !ok means the old and new lockfile are the same, so we don’t make a commit
          log.info(`new lockfile contents for ${lockfilePath} received`)
          statsd.increment('lockfiles')

          const lockfileCommitMessage = getMessage(commitMessageTemplates, 'lockfileUpdate', { lockfilePath: lockfilePath })

          commits.push({
            path: lockfilePath,
            content: contents,
            message: lockfileCommitMessage,
            index: commits.length
          })
          log.info(`created lockfile commit for ${lockfilePath}`, { lockfileCommitMessage })
        } else { // ok: false
          log.error(`error building lockfile for ${lockfilePath}`, { error })
        }
      } catch (e) {
        log.error('error fetching updated lockfile from exec server', { e: e.error || e })
      }
    }
  }

  const head = await ghqueue.read(github => github.gitdata.getRef({
    owner,
    repo: repoName,
    ref: `heads/${branch}`
  }))

  const createCommits = async (sha, { path, content, message, index }) => {
    const newTree = await ghqueue.write(github => github.gitdata.createTree({
      owner,
      repo: repoName,
      base_tree: sha,
      tree: [{ path, content, mode: '100644', type: 'blob' }]
    }))

    const commit = await ghqueue.write(github => github.gitdata.createCommit({
      owner,
      repo: repoName,
      message,
      tree: newTree.sha,
      parents: [sha]
    }))
    /*
      .created is written back into the original transform which is still used
      after create-branch is called from wherever, create-initial-branch for example. So after
      create-branch returns its SHA to create-initial-branch, the latter can check whether, for
      example, travis.yml or readme.md were modified. This is then passed into create-pr or
      whatever else sends messages to humans, where we can then notify them which files were
      MODIFIED (so the key is actually a misnomer).

      ⚠ Lockfiles only have commits, not transforms, so when they try to write back to their
      transform, they can’t, because there is none. That’s why we check whether there’s something at
      every index we want to update.
    */
    if (transforms[index]) {
      transforms[index].created = true
    }

    return commit.sha
  }

  const sha = await Promise.reduce(commits, createCommits, head.object.sha)

  try {
    await ghqueue.write(github => github.gitdata.createRef({
      owner,
      repo: repoName,
      sha,
      ref: 'refs/heads/' + newBranch
    }))
  } catch (err) {
    if (!err.message.includes('already exists')) throw err

    const branch = await ghqueue.read(github => github.repos.getBranch({
      owner,
      repo: repoName,
      branch: newBranch
    }))

    if (branch.commit.committer.type !== 'Bot') throw err

    return branch.commit.sha
  }

  statsd.increment('branches')

  return sha
}
<|endoftext|>


<commit_before>var Chalk = require('chalk');
var Logs = require('../lib/logs');
var WebtaskCreator = require('../lib/webtaskCreator');
var Url = require('url');
var _ = require('lodash');

module.exports = createWebtask;

function createWebtask(args, options) {
    if (!options) options = {};
    if (!options.action) options.action = 'created';

    var profile = args.profile;
    var createWebtask = WebtaskCreator(args, {
        onGeneration: onGeneration,
        onError: onError,
    });
    var logger = args.watch
        ?   Logs.createLogStream(profile)
        :   console;
    var log = args.watch
        ?   _.bindKey(logger, 'info')
        :   _.bindKey(logger, 'log');
    var logError = _.bindKey(logger, 'error');

    return createWebtask(profile);

    function onError(build) {
        formatError(build);
    }

    function onGeneration(build) {
        var parsedUrl = Url.parse(build.webtask.url, true);

        if (!args.prod) {
            parsedUrl.query.webtask_no_cache = 1;
        }

        var url = Url.format(parsedUrl);

        formatOutput(build, url);
    }

    function formatError(build, url) {
        var output;

        if (args.watch) {
            output = { generation: build.generation };

            _.forEach(build.stats.errors, function (error) {
                logError(output, 'Bundling failed: %s', error);
            });
        } else if (args.output === 'json') {
            output = { url: url, name: build.webtask.claims.jtn, container: build.webtas.container };

            if (args.showToken) {
                output.token = build.webtask.token;
            }

            logError(JSON.stringify(build.stats.errors, null, 2));
        } else {
            logError(Chalk.red('Bundling failed failed'));
            build.stats.errors.forEach(logError);
        }
    }

    function formatOutput(build, url) {
        var output;

        if (args.watch) {
            output = { generation: build.generation, container: build.webtask.container };

            if (args.showToken) {
                output.token = build.webtask.token;
            }

            log(output, 'Webtask %s: %s', options.action, url);
        } else if (args.output === 'json') {
            output = { url: url, name: build.webtask.claims.jtn, container: build.webtask.container };

            if (args.showToken) {
                output.token = build.webtask.token;
            }

            log(JSON.stringify(output, null, 2));
        } else if (args.showToken) {
            log(Chalk.green('Webtask token %s') + '\n\n%s\n\nYou can access your webtask at the following url:\n\n%s', options.action, Chalk.gray(build.webtask.token), Chalk.bold(url));
        } else {
            log(Chalk.green('Webtask %s') + '\n\nYou can access your webtask at the following url:\n\n%s', options.action, Chalk.bold(url));
        }
    }
}<commit_msg>Improve output on bundling errors<commit_after>var Chalk = require('chalk');
var Logs = require('../lib/logs');
var WebtaskCreator = require('../lib/webtaskCreator');
var Url = require('url');
var _ = require('lodash');

module.exports = createWebtask;

function createWebtask(args, options) {
    if (!options) options = {};
    if (!options.action) options.action = 'created';

    var profile = args.profile;
    var createWebtask = WebtaskCreator(args, {
        onGeneration: onGeneration,
        onError: onError,
    });
    var logger = args.watch
        ?   Logs.createLogStream(profile)
        :   console;
    var log = args.watch
        ?   _.bindKey(logger, 'info')
        :   _.bindKey(logger, 'log');
    var logError = _.bindKey(logger, 'error');

    return createWebtask(profile);

    function onError(build) {
        formatError(build);
    }

    function onGeneration(build) {
        var parsedUrl = Url.parse(build.webtask.url, true);

        if (!args.prod) {
            parsedUrl.query.webtask_no_cache = 1;
        }

        var url = Url.format(parsedUrl);

        formatOutput(build, url);
    }

    function formatError(build, url) {
        build.stats.errors = build.stats.errors.map(err => err.split('|').slice(0, -1).join('|'));

        if (args.watch) {
            var output = { generation: build.generation };

            _.forEach(build.stats.errors, function (error) {
                logError(output, 'Bundling failed: %s', error);
            });
        } else if (args.output === 'json') {
            var json = {
                name: args.name,
                container: args.profile.container,
                errors: build.stats.errors,
            };

            logError(JSON.stringify(json, null, 2));
        } else {
            logError(Chalk.red('Bundling failed'));
            build.stats.errors.forEach(err => logError(err));
        }
    }

    function formatOutput(build, url) {
        var output;

        if (args.watch) {
            output = { generation: build.generation, container: build.webtask.container };

            if (args.showToken) {
                output.token = build.webtask.token;
            }

            log(output, 'Webtask %s: %s', options.action, url);
        } else if (args.output === 'json') {
            output = { url: url, name: build.webtask.claims.jtn, container: build.webtask.container };

            if (args.showToken) {
                output.token = build.webtask.token;
            }

            log(JSON.stringify(output, null, 2));
        } else if (args.showToken) {
            log(Chalk.green('Webtask token %s') + '\n\n%s\n\nYou can access your webtask at the following url:\n\n%s', options.action, Chalk.gray(build.webtask.token), Chalk.bold(url));
        } else {
            log(Chalk.green('Webtask %s') + '\n\nYou can access your webtask at the following url:\n\n%s', options.action, Chalk.bold(url));
        }
    }
}<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchTrinomial } from '../actions';

class TrinomialShow extends Component {
  componentDidMount() {
    this.props.fetchTrinomial();
  }

  render() {
    console.log(this.props.trinomial);
    const trinomial = this.props.trinomial.trinomial;
    // console.log(trinomial.trinomial);
    // const promise = this.props.trinomial.trinomial;
    // const { trinomial } = this.props;
    // const data = trinomial.data;
    // console.log(data);
    // const trinomial = this.props.trinomial;
    // console.log(trinomial);
    if (!trinomial) {
      return (

Loading...

      );
    }

    return (

problem goes here

You need to know what pattern you want to render the correct problem

{`x^2 + ${trinomial.b}x + ${trinomial.c}`}

    );
  }
}

function mapStateToProps(state) {
  return { trinomial: state.trinomial };
}

export default connect(mapStateToProps, { fetchTrinomial })(TrinomialShow);
<commit_msg>problem component is showing all information given in api response<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchTrinomial } from '../actions';

class TrinomialShow extends Component {
  componentDidMount() {
    this.props.fetchTrinomial();
  }

  render() {
    // console.log(this.props.data);
    const trinomial = this.props.data.trinomial;

    // just like the course said - this conditional is important ...
    if (!trinomial) {
      return (

Loading...

      );
    }

    return (

problem goes here

You need to know what pattern you want to render the correct problem

 Now getting pattern and string with api call

Pattern: { trinomial.pattern }

{ trinomial.general_form }

a: { trinomial.a }

b: { trinomial.b }

c: { trinomial.c }

    );
  }
}

function mapStateToProps(state) {
  return { data: state.trinomial };
}

export default connect(mapStateToProps, { fetchTrinomial })(TrinomialShow);
<|endoftext|>


<commit_before>/*
 * package.js: Titanium iOS CLI package hook
 *
 * Copyright (c) 2012-2017, Appcelerator, Inc.  All Rights Reserved.
 * See the LICENSE file for more information.
 */

'use strict';

const appc = require('node-appc'),
	__ = appc.i18n(__dirname).__,
	afs = appc.fs,
	fs = require('fs'),
	path = require('path'),
	wrench = require('wrench'),
	exec = require('child_process').exec; // eslint-disable-line security/detect-child-process

exports.cliVersion = '>=3.2';

exports.init = function (logger, config, cli) {
	cli.on('build.ios.xcodebuild', {
		pre: function (data, finished) {
			if (this.target !== 'dist-appstore' && this.target !== 'dist-adhoc') {
				return finished();
			}

			const stagingArchiveDir = path.join(this.buildDir, this.tiapp.name + '.xcarchive');
			fs.existsSync(stagingArchiveDir) && wrench.rmdirSyncRecursive(stagingArchiveDir);

			// inject the temporary archive path into the xcodebuild args
			const args = data.args[1];
			const p = args.indexOf('-archivePath');
			if (p === -1) {
				args.push('-archivePath', stagingArchiveDir);
			} else {
				args[p + 1] = stagingArchiveDir;
			}

			finished();
		}
	});

	cli.on('build.post.compile', {
		priority: 8000,
		post: function (builder, finished) {
			const target = cli.argv.target;

			if (target !== 'dist-appstore' && target !== 'dist-adhoc') {
				return finished();
			}

			const name = builder.tiapp.name;
			const stagingArchiveDir = path.join(builder.buildDir, name + '.xcarchive');
			if (!fs.existsSync(stagingArchiveDir)) {
				return finished(new Error(__('Staging archive directory does not exist')));
			}

			const now = new Date();
			const destInfoPlist = path.join(stagingArchiveDir, 'Info.plist');
			if (!fs.existsSync(destInfoPlist)) {
				const origPlist = new appc.plist(path.join(builder.buildDir, 'Info.plist'));
				const newPlist = new appc.plist();
				const appBundle = 'Applications/' + name + '.app';

				appc.util.mix(newPlist, {
					ApplicationProperties: {
						ApplicationPath: appBundle,
						CFBundleIdentifier: origPlist.CFBundleIdentifier || builder.tiapp.id,
						CFBundleShortVersionString: origPlist.CFBundleShortVersionString || '1.0',
						CFBundleVersion: origPlist.CFBundleVersion || '1.0',
						SigningIdentity: 'iPhone Distribution: ' + builder.certDistributionName,
						IconPaths: [
							appBundle + '/' + builder.tiapp.icon
						]
					},
					ArchiveVersion: newPlist.type('integer', 2),
					CreationDate: now,
					Name: name,
					SchemeName: name
				}).save(destInfoPlist);
			}

			switch (target) {
				case 'dist-appstore':
					logger.info(__('Preparing xcarchive'));

					const productsDir = path.join(builder.buildDir, 'build', 'Products');
					if (!fs.existsSync(productsDir)) {
						return finished(new Error(__('Products directory does not exist')));
					}

					// copy symbols
					const archiveDsymDir = path.join(stagingArchiveDir, 'dSYMs');
					fs.existsSync(archiveDsymDir) || wrench.mkdirSyncRecursive(archiveDsymDir);
					const bcSymbolMapsDir = path.join(stagingArchiveDir, 'BCSymbolMaps');
					fs.existsSync(bcSymbolMapsDir) || wrench.mkdirSyncRecursive(bcSymbolMapsDir);
					const dsymRegExp = /\.dSYM$/;
					const bcSymbolMapsRegExp = /\.bcsymbolmap$/;
					fs.readdirSync(productsDir).forEach(function (name) {
						var subdir = path.join(productsDir, name);
						if (fs.existsSync(subdir) && fs.statSync(subdir).isDirectory()) {
							fs.readdirSync(subdir).forEach(function (name) {
								var file = path.join(subdir, name);
								if (dsymRegExp.test(name) && fs.existsSync(file) && fs.statSync(file).isDirectory()) {
									logger.info(__('Archiving debug symbols: %s', file.cyan));
									wrench.copyDirSyncRecursive(file, path.join(archiveDsymDir, name), { forceDelete: false });
								} else if (bcSymbolMapsRegExp.test(name) && fs.existsSync(file) && fs.statSync(file).isFile()) {
									const dest = path.join(bcSymbolMapsDir, name);
									logger.info(__('Archiving Bitcode Symbol Map: %s', file.cyan));
									fs.writeFileSync(dest, fs.readFileSync(file));
								}
							});
						}
					});

					// if output-dir don't move the archive, instead export it into an IPA
					if (cli.argv['output-dir']) {
						exportIPA(builder, target, stagingArchiveDir, cli.argv['output-dir'], finished);
						return;
					}

					const month = now.getMonth() + 1;
					const day = now.getDate();
					const hours = now.getHours();
					const minutes = now.getMinutes();
					const seconds = now.getSeconds();
					const date = now.getFullYear() + '-' + (month >= 10 ? month : '0' + month) + '-' + (day >= 10 ? day : '0' + day);
					const time = (hours >= 10 ? hours : '0' + hours) + '-' + (minutes >= 10 ? minutes : '0' + minutes) + '-' + (seconds >= 10 ? seconds : '0' + seconds);

					const archivesDir = afs.resolvePath('~/Library/Developer/Xcode/Archives', date);
					const dest = path.join(archivesDir, name + ' ' + date + ' ' + time + '.xcarchive');

					// move the finished archive directory into the correct location
					fs.existsSync(archivesDir) || wrench.mkdirSyncRecursive(archivesDir);
					appc.fs.copyDirSyncRecursive(stagingArchiveDir, dest, {
						logger: logger.debug
					});

					// if not build-only open xcode + organizer after packaging, otherwise finish
					if (!cli.argv['build-only']) {
						logger.info(__('Launching Xcode: %s', builder.xcodeEnv.xcodeapp.cyan));
						exec('open -a "' + builder.xcodeEnv.xcodeapp + '"', function () {
							process.env.TI_ENV_NAME = process.env.STUDIO_NAME || 'Terminal.app';
							exec('osascript "' + path.join(builder.platformPath, 'xcode_organizer.scpt') + '"', { env: process.env }, function () {
								logger.info(__('Packaging complete'));
								finished();
							});
						});
					} else {
						logger.info(__('Packaging complete'));
						finished();
					}
					return;

				case 'dist-adhoc':
					logger.info(__('Packaging for Ad Hoc distribution'));
					exportIPA(builder, target, stagingArchiveDir, cli.argv['output-dir'], finished);
					return;
			}

			finished();
		}
	});

	/**
	 * Centralized function to export build into an IPA
	 * @param  {object}   builder           builder object
	 * @param  {string}   target            target store/consumer
	 * @param  {string}   stagingArchiveDir path to staging dir
	 * @param  {string}   outputDirArg      path to ultimate output dir
	 * @param  {Function} callback          callback function
	 * @return {undefined}
	 */
	function exportIPA(builder, target, stagingArchiveDir, outputDirArg, callback) {
		logger.debug(__('Packaging IPA for target %s', target.cyan));

		const outputDir = outputDirArg && afs.resolvePath(outputDirArg);
		if (!outputDir) {
			logger.warn(__('Invalid output directory %s, skipping packaging', '--output-dir'.cyan));
			return callback();
		}

		// make sure the output directory is good to go
		if (!fs.existsSync(outputDir)) {
			wrench.mkdirSyncRecursive(outputDir);
		}

		const ipaFile = path.join(outputDir, builder.tiapp.name + '.ipa');
		if (fs.existsSync(ipaFile)) {
			logger.debug(__('Deleting old .ipa file'));
			fs.unlinkSync(ipaFile);
		}

		const exportsOptionsPlistFile = path.join(builder.buildDir, 'export_options.plist');
		const exportsOptions = new appc.plist();
		const pp = builder.provisioningProfile;

		// Build the options plist file
		if (target === 'dist-appstore') {
			exportsOptions.method = 'app-store';
		} else {
			exportsOptions.method = 'ad-hoc';

			if (pp.type === 'enterprise') {
				exportsOptions.method = 'enterprise';
			}

			if (pp.appPrefix) {
				exportsOptions.teamId = pp.appPrefix;
			}
		}

		const keychains = builder.iosInfo.certs.keychains;
		Object.keys(keychains).some(function (keychain) {
			return (keychains[keychain].distribution || []).some(function (d) {
				if (!d.invalid && d.name === builder.certDistributionName) {
					exportsOptions.signingCertificate = d.fullname;
					return true;
				}
				return false;
			}, this);
		}, this);

		exportsOptions.provisioningProfiles = {};
		exportsOptions.provisioningProfiles[builder.tiapp.id] = pp.uuid;

		// check if the app is using CloudKit
		const entitlementsFile = path.join(builder.buildDir, builder.tiapp.name + '.entitlements');
		if (fs.existsSync(entitlementsFile)) {
			const plist = new appc.plist(entitlementsFile);
			if (Object.keys(plist).some(function (key) { return key === 'com.apple.developer.icloud-container-identifiers'; })) {
				exportsOptions.iCloudContainerEnvironment = 'Production';
			}
		}

		fs.writeFileSync(exportsOptionsPlistFile, exportsOptions.toString('xml'));

		// construct the command
		const cmd = [
			builder.xcodeEnv.executables.xcodebuild,
			'-exportArchive',
			'-archivePath', '"' + stagingArchiveDir + '"',
			'-exportPath', '"' + outputDir + '"',
			'-exportOptionsPlist', '"' + exportsOptionsPlistFile + '"'
		].join(' ');

		// execute!
		logger.debug(__('Running: %s', cmd.cyan));
		exec(cmd, function (err, stdout, stderr) {
			if (err) {
				const output = stderr.trim();
				output.split('\n').forEach(logger.trace);
				logger.error(__('Failed to export archive to ipa'));

				const targetName = target === 'dist-appstore' ? 'Distribution' : 'Ad Hoc';

				if (pp) {
					if (pp.type === 'distribution' && target === 'dist-adhoc') {
						logger.error(__('The selected provisioning profile "%s (%s)" appears to be a Distribution provisioning profile and not an Ad Hoc provisioning profile.', pp.name, pp.uuid));
					} else if (pp.type === 'adhoc' && target === 'dist-appstore') {
						logger.error(__('The selected provisioning profile "%s (%s)" appears to be an Ad Hoc provisioning profile and not a Distribution provisioning profile.', pp.name, pp.uuid));
					} else {
						logger.error(__('The selected provisioning profile "%s (%s)" is most likely not a valid %s provisioning profile.', pp.name, pp.uuid, targetName));
					}
				} else {
					logger.error(__('The selected provisioning profile doesn\'t appear to be a %s provisioning profile or match the signing identity.', targetName));
				}
				logger.error(__('Please ensure you are using a valid %s provisioning that is linked to the signing identity, then try again.', targetName));
			} else {
				logger.info(__('Packaging complete'));
				logger.info(__('Package location: %s', ipaFile.cyan));
			}
			callback();
		});
	}
};
<commit_msg>[TIMOB-25319] Cleaned up code to be more sensible and pass lint rules.<commit_after>/*
 * package.js: Titanium iOS CLI package hook
 *
 * Copyright (c) 2012-2017, Appcelerator, Inc.  All Rights Reserved.
 * See the LICENSE file for more information.
 */

'use strict';

const appc = require('node-appc'),
	__ = appc.i18n(__dirname).__,
	afs = appc.fs,
	fs = require('fs'),
	path = require('path'),
	wrench = require('wrench'),
	exec = require('child_process').exec; // eslint-disable-line security/detect-child-process

exports.cliVersion = '>=3.2';

exports.init = function (logger, config, cli) {
	cli.on('build.ios.xcodebuild', {
		pre: function (data, finished) {
			if (this.target !== 'dist-appstore' && this.target !== 'dist-adhoc') {
				return finished();
			}

			const stagingArchiveDir = path.join(this.buildDir, this.tiapp.name + '.xcarchive');
			fs.existsSync(stagingArchiveDir) && wrench.rmdirSyncRecursive(stagingArchiveDir);

			// inject the temporary archive path into the xcodebuild args
			const args = data.args[1];
			const p = args.indexOf('-archivePath');
			if (p === -1) {
				args.push('-archivePath', stagingArchiveDir);
			} else {
				args[p + 1] = stagingArchiveDir;
			}

			finished();
		}
	});

	cli.on('build.post.compile', {
		priority: 8000,
		post: function (builder, finished) {
			const target = cli.argv.target;

			if (target !== 'dist-appstore' && target !== 'dist-adhoc') {
				return finished();
			}

			const name = builder.tiapp.name;
			const stagingArchiveDir = path.join(builder.buildDir, name + '.xcarchive');
			if (!fs.existsSync(stagingArchiveDir)) {
				return finished(new Error(__('Staging archive directory does not exist')));
			}

			const now = new Date();
			const destInfoPlist = path.join(stagingArchiveDir, 'Info.plist');
			if (!fs.existsSync(destInfoPlist)) {
				const origPlist = new appc.plist(path.join(builder.buildDir, 'Info.plist'));
				const newPlist = new appc.plist();
				const appBundle = 'Applications/' + name + '.app';

				appc.util.mix(newPlist, {
					ApplicationProperties: {
						ApplicationPath: appBundle,
						CFBundleIdentifier: origPlist.CFBundleIdentifier || builder.tiapp.id,
						CFBundleShortVersionString: origPlist.CFBundleShortVersionString || '1.0',
						CFBundleVersion: origPlist.CFBundleVersion || '1.0',
						SigningIdentity: 'iPhone Distribution: ' + builder.certDistributionName,
						IconPaths: [
							appBundle + '/' + builder.tiapp.icon
						]
					},
					ArchiveVersion: newPlist.type('integer', 2),
					CreationDate: now,
					Name: name,
					SchemeName: name
				}).save(destInfoPlist);
			}

			switch (target) {
				case 'dist-appstore':
					logger.info(__('Preparing xcarchive'));

					const productsDir = path.join(builder.buildDir, 'build', 'Products');
					if (!fs.existsSync(productsDir)) {
						return finished(new Error(__('Products directory does not exist')));
					}

					// copy symbols
					const archiveDsymDir = path.join(stagingArchiveDir, 'dSYMs');
					fs.existsSync(archiveDsymDir) || wrench.mkdirSyncRecursive(archiveDsymDir);
					const bcSymbolMapsDir = path.join(stagingArchiveDir, 'BCSymbolMaps');
					fs.existsSync(bcSymbolMapsDir) || wrench.mkdirSyncRecursive(bcSymbolMapsDir);
					const dsymRegExp = /\.dSYM$/;
					const bcSymbolMapsRegExp = /\.bcsymbolmap$/;
					fs.readdirSync(productsDir).forEach(function (name) {
						var subdir = path.join(productsDir, name);
						if (fs.existsSync(subdir) && fs.statSync(subdir).isDirectory()) {
							fs.readdirSync(subdir).forEach(function (name) {
								var file = path.join(subdir, name);
								if (dsymRegExp.test(name) && fs.existsSync(file) && fs.statSync(file).isDirectory()) {
									logger.info(__('Archiving debug symbols: %s', file.cyan));
									wrench.copyDirSyncRecursive(file, path.join(archiveDsymDir, name), { forceDelete: false });
								} else if (bcSymbolMapsRegExp.test(name) && fs.existsSync(file) && fs.statSync(file).isFile()) {
									const dest = path.join(bcSymbolMapsDir, name);
									logger.info(__('Archiving Bitcode Symbol Map: %s', file.cyan));
									fs.writeFileSync(dest, fs.readFileSync(file));
								}
							});
						}
					});

					// if output-dir don't move the archive, instead export it into an IPA
					if (cli.argv['output-dir']) {
						exportIPA(builder, target, stagingArchiveDir, cli.argv['output-dir'], finished);
						return;
					}

					const month = now.getMonth() + 1;
					const day = now.getDate();
					const hours = now.getHours();
					const minutes = now.getMinutes();
					const seconds = now.getSeconds();
					const date = now.getFullYear() + '-' + (month >= 10 ? month : '0' + month) + '-' + (day >= 10 ? day : '0' + day);
					const time = (hours >= 10 ? hours : '0' + hours) + '-' + (minutes >= 10 ? minutes : '0' + minutes) + '-' + (seconds >= 10 ? seconds : '0' + seconds);

					const archivesDir = afs.resolvePath('~/Library/Developer/Xcode/Archives', date);
					const dest = path.join(archivesDir, name + ' ' + date + ' ' + time + '.xcarchive');

					// move the finished archive directory into the correct location
					fs.existsSync(archivesDir) || wrench.mkdirSyncRecursive(archivesDir);
					appc.fs.copyDirSyncRecursive(stagingArchiveDir, dest, {
						logger: logger.debug
					});

					// if not build-only open xcode + organizer after packaging, otherwise finish
					if (!cli.argv['build-only']) {
						logger.info(__('Launching Xcode: %s', builder.xcodeEnv.xcodeapp.cyan));
						exec('open -a "' + builder.xcodeEnv.xcodeapp + '"', function () {
							process.env.TI_ENV_NAME = process.env.STUDIO_NAME || 'Terminal.app';
							exec('osascript "' + path.join(builder.platformPath, 'xcode_organizer.scpt') + '"', { env: process.env }, function () {
								logger.info(__('Packaging complete'));
								finished();
							});
						});
					} else {
						logger.info(__('Packaging complete'));
						finished();
					}
					return;

				case 'dist-adhoc':
					logger.info(__('Packaging for Ad Hoc distribution'));
					exportIPA(builder, target, stagingArchiveDir, cli.argv['output-dir'], finished);
					return;
			}

			finished();
		}
	});

	/**
	 * Centralized function to export build into an IPA
	 * @param  {object}   builder           builder object
	 * @param  {string}   target            target store/consumer
	 * @param  {string}   stagingArchiveDir path to staging dir
	 * @param  {string}   outputDirArg      path to ultimate output dir
	 * @param  {Function} callback          callback function
	 * @return {undefined}
	 */
	function exportIPA(builder, target, stagingArchiveDir, outputDirArg, callback) {
		logger.debug(__('Packaging IPA for target %s', target.cyan));

		const outputDir = outputDirArg && afs.resolvePath(outputDirArg);
		if (!outputDir) {
			logger.warn(__('Invalid output directory %s, skipping packaging', '--output-dir'.cyan));
			return callback();
		}

		// make sure the output directory is good to go
		if (!fs.existsSync(outputDir)) {
			wrench.mkdirSyncRecursive(outputDir);
		}

		const ipaFile = path.join(outputDir, builder.tiapp.name + '.ipa');
		if (fs.existsSync(ipaFile)) {
			logger.debug(__('Deleting old .ipa file'));
			fs.unlinkSync(ipaFile);
		}

		const exportsOptionsPlistFile = path.join(builder.buildDir, 'export_options.plist');
		const exportsOptions = new appc.plist();
		const pp = builder.provisioningProfile;

		// Build the options plist file
		if (target === 'dist-appstore') {
			exportsOptions.method = 'app-store';
		} else {
			exportsOptions.method = 'ad-hoc';

			if (pp.type === 'enterprise') {
				exportsOptions.method = 'enterprise';
			}

			if (pp.appPrefix) {
				exportsOptions.teamId = pp.appPrefix;
			}
		}

		const keychains = builder.iosInfo.certs.keychains;
		Object.keys(keychains).some(function (keychain) {
			return (keychains[keychain].distribution || []).some(function (d) {
				if (!d.invalid && d.name === builder.certDistributionName) {
					exportsOptions.signingCertificate = d.fullname;
					return true;
				}
				return false;
			}, this);
		}, this);

		exportsOptions.provisioningProfiles = {};
		exportsOptions.provisioningProfiles[builder.tiapp.id] = pp.uuid;

		// check if the app is using CloudKit
		const entitlementsFile = path.join(builder.buildDir, builder.tiapp.name + '.entitlements');
		if (fs.existsSync(entitlementsFile)) {
			const plist = new appc.plist(entitlementsFile);
			if (Object.keys(plist).indexOf('com.apple.developer.icloud-container-identifiers') !== -1) {
				exportsOptions.iCloudContainerEnvironment = 'Production';
			}
		}

		fs.writeFileSync(exportsOptionsPlistFile, exportsOptions.toString('xml'));

		// construct the command
		const cmd = [
			builder.xcodeEnv.executables.xcodebuild,
			'-exportArchive',
			'-archivePath', '"' + stagingArchiveDir + '"',
			'-exportPath', '"' + outputDir + '"',
			'-exportOptionsPlist', '"' + exportsOptionsPlistFile + '"'
		].join(' ');

		// execute!
		logger.debug(__('Running: %s', cmd.cyan));
		exec(cmd, function (err, stdout, stderr) {
			if (err) {
				const output = stderr.trim();
				output.split('\n').forEach(logger.trace);
				logger.error(__('Failed to export archive to ipa'));

				const targetName = target === 'dist-appstore' ? 'Distribution' : 'Ad Hoc';

				if (pp) {
					if (pp.type === 'distribution' && target === 'dist-adhoc') {
						logger.error(__('The selected provisioning profile "%s (%s)" appears to be a Distribution provisioning profile and not an Ad Hoc provisioning profile.', pp.name, pp.uuid));
					} else if (pp.type === 'adhoc' && target === 'dist-appstore') {
						logger.error(__('The selected provisioning profile "%s (%s)" appears to be an Ad Hoc provisioning profile and not a Distribution provisioning profile.', pp.name, pp.uuid));
					} else {
						logger.error(__('The selected provisioning profile "%s (%s)" is most likely not a valid %s provisioning profile.', pp.name, pp.uuid, targetName));
					}
				} else {
					logger.error(__('The selected provisioning profile doesn\'t appear to be a %s provisioning profile or match the signing identity.', targetName));
				}
				logger.error(__('Please ensure you are using a valid %s provisioning that is linked to the signing identity, then try again.', targetName));
			} else {
				logger.info(__('Packaging complete'));
				logger.info(__('Package location: %s', ipaFile.cyan));
			}
			callback();
		});
	}
};
<|endoftext|>


<commit_before>'use strict';
var DocumentDB = require('documentdb').DocumentClient;
var DoQmentDB  = require('..');
var _          = require('agile');
var sinon      = require('sinon');
var should     = require('should');
var Promise    = require('bluebird');

describe('DoqmentDB', function() {
  //...
});<commit_msg>test(DoQmentDB): dynamic creation<commit_after>'use strict';
var DocumentDB = require('documentdb').DocumentClient;
var DoQmentDB  = require('..');
var _          = require('agile');
var sinon      = require('sinon');
var should     = require('should');
var Promise    = require('bluebird');

var toArray = function(args) {
  return { toArray: function(fb) { fb.apply(null, args);} }
};

describe('DoqmentDB', function() {
  describe('DatabaseManager', function() {
    beforeEach(function() {

    });

    describe('creating `new` DatabaseManager', function() {
      it('should get a not DocumentDB instance(connection) and throw', function() {
        (function() {
          new DoQmentDB({});
        }).should.throw();
      });

      it('should get DocumentDB instance(connection) and return an instance', function() {
        (new DoQmentDB(new DocumentDB('name', {}), 'dbName'))
          .should.be.an.instanceOf(Object)
      });
    });

    // findOrCreate behavior
    describe('`using` dynamically', function() {
      var connection = new DocumentDB('host', { masterKey: 'key' });
      var dbManager  = new DoQmentDB(connection, '');

      beforeEach(function() {
        sinon.stub(DocumentDB.prototype, 'createDatabase', function(obj, fb) {fb()});
        var stub = sinon.stub(DocumentDB.prototype, 'queryDatabases');
        stub.onCall(0).returns(toArray([null, []]));
        stub.onCall(1).returns(toArray([null, [{}]]));
      });

      describe('working with non-existing(in Azure) database', function() {
        it('should call `createDatabase` with database name', function(done) {
          dbManager.manager.findOrCreate({ id: dbManager.database })
            .then(function(result) {
              DocumentDB.prototype.createDatabase.calledWith({ id: dbManager.database })
                .should.eql(true);
              done();
            });
        });
      });

      describe('working with existing(in Azure) database', function() {
        it('should return the db and not call `createDatabase`', function(done) {
          dbManager.manager.findOrCreate({ id: dbManager.database })
            .then(function(result) {
              DocumentDB.prototype.createDatabase.calledTwice.should.eql(false);
              done();
            });
        });
      });

      afterEach(function() {
        DocumentDB.prototype.createDatabase.restore();
        DocumentDB.prototype.queryDatabases.restore();
      });
    });

    // Public api, .find(), .create(), ...

  });
});<|endoftext|>


<commit_before>var test = require('tape');
var mapboxgl = require('mapbox-gl');
var GLDraw = require('../');
import { accessToken, createMap } from './utils';

mapboxgl.accessToken = accessToken;

var map = createMap();

map.on('load', () => {

  test('Draw class test', t => {
    var Draw = GLDraw();
    map.addControl(Draw);

    t.ok(Draw, 'Draw class exists');

    t.ok(Draw.options, 'Draw.options is defined');

    // check for control buttons in the DOM
    t.ok(
      document.getElementById('lineDrawBtn'),
      'line draw button is in the DOM'
    );
    t.ok(
      document.getElementById('polygonDrawBtn'),
      'polygon draw button is in the DOM'
    );
    t.ok(
      document.getElementById('squareDrawBtn'),
      'square draw button is in the DOM'
    );
    t.ok(
      document.getElementById('pointDrawBtn'),
      'point draw button is in the DOM'
    );

    // test selected mode
    // TO DO

    t.end();
  });

  test('Draw without handlers', t => {
    GLDraw({
      controls: {}
    });

    try {
      map.fire('drawing.end');
    } catch (e) {
      t.fail('calling drawing.end without handlers throws');
    }

    t.end();
  });

});
<commit_msg>Add failing test for #223<commit_after>var test = require('tape');
var mapboxgl = require('mapbox-gl');
var GLDraw = require('../');
import { accessToken, createMap } from './utils';

mapboxgl.accessToken = accessToken;

var map = createMap();

map.on('load', () => {

  var Draw;

  test('Draw class test', t => {
    Draw = GLDraw();
    map.addControl(Draw);

    t.ok(Draw, 'Draw class exists');

    t.ok(Draw.options, 'Draw.options is defined');

    // check for control buttons in the DOM
    t.ok(
      document.getElementById('lineDrawBtn'),
      'line draw button is in the DOM'
    );
    t.ok(
      document.getElementById('polygonDrawBtn'),
      'polygon draw button is in the DOM'
    );
    t.ok(
      document.getElementById('squareDrawBtn'),
      'square draw button is in the DOM'
    );
    t.ok(
      document.getElementById('pointDrawBtn'),
      'point draw button is in the DOM'
    );

    // test selected mode
    // TO DO

    t.end();
  });

  test('Draw without handlers', t => {
    GLDraw({
      controls: {}
    });

    try {
      map.fire('drawing.end');
    } catch (e) {
      t.fail('calling drawing.end without handlers throws');
    }

    t.end();
  });

  test('Draw without drawing', t => {
    Draw = GLDraw({
      drawing: false
    });

    t.doesNotThrow(Draw._hideDeleteButton.bind(Draw),
    'calling _hideDeleteButton with drawing disabled does not throw an error');

    t.end();
  });

});
<|endoftext|>


<commit_before>var chai = require('chai');
chai.use(require('chai-fs'));
var expect = chai.expect;
var echo = require('../src/echo-table-2-file');

describe("ConvertURL Test", function(){
  this.timeout(15000);
  const TIME_TO_GENERATE_JSON = 2000;

  beforeEach(function(done){
    echo.convertUrl('https://www.coolgithubprojects.com', 'dest','json');
    setTimeout(function(){
      done();
    }, TIME_TO_GENERATE_JSON);
  });

  it("Should generate valid json files", function(){
    expect('dest/days.json').to.be.a.file('Should be a json file').with.json;
    expect('dest/weeks.json').to.be.a.file('Should be a json file').with.json;
    expect('dest/months.json').to.be.a.file('Should be a json file').with.json;
  });
});
<commit_msg>Adding CSV to test<commit_after>var chai = require('chai');
chai.use(require('chai-fs'));
var expect = chai.expect;
var echo = require('../src/echo-table-2-file');

describe("ConvertURL Test", function(){
  this.timeout(15000);
  const TIME_TO_GENERATE_JSON = 2000;

  beforeEach(function(done){
    echo.convertUrl('https://www.coolgithubprojects.com', 'dest','json');
    echo.convertUrl('https://www.coolgithubprojects.com', 'dest','csv');
    setTimeout(function(){
      done();
    }, TIME_TO_GENERATE_JSON);
  });

  it("Should generate valid json files", function(){
    expect('dest/days.json').to.be.a.file('Should be a json file').with.json;
    expect('dest/weeks.json').to.be.a.file('Should be a json file').with.json;
    expect('dest/months.json').to.be.a.file('Should be a json file').with.json;
    expect('dest/days.csv').to.be.a.file('Should be a json file').with.csv;
    expect('dest/weeks.csv').to.be.a.file('Should be a json file').with.csv;
    expect('dest/months.csv').to.be.a.file('Should be a json file').with.csv;
  });
});
<|endoftext|>