<commit_before>import React from 'react';
import PropTypes from 'prop-types';

// Redux
import { connect } from 'react-redux';

// Services
import DatasetsService from 'services/DatasetsService';
import LayersService from 'services/LayersService';
import { toastr } from 'react-redux-toastr';

// Constants
import { STATE_DEFAULT, FORM_ELEMENTS } from 'components/admin/layers/form/constants';

import { setLayerInteractionError } from 'components/admin/layers/form/layer-preview/layer-preview-actions';

// Components
import Step1 from 'components/admin/layers/form/steps/Step1';
import Navigation from 'components/form/Navigation';
import Spinner from 'components/ui/Spinner';

import LayerManager from 'utils/layers/LayerManager';

class LayersForm extends React.Component {
  constructor(props) {
    super(props);

    const formObj = props.dataset ?
      Object.assign({}, STATE_DEFAULT.form,
        { dataset: props.dataset, application: props.application }) :
      Object.assign({}, STATE_DEFAULT.form, {
        application: props.application
      });

    this.state = Object.assign({}, STATE_DEFAULT, {
      id: props.id,
      dataset: props.dataset,
      datasets: [],
      form: formObj,
      loading: !!props.id
    });

    // Service
    this.datasetsService = new DatasetsService({
      authorization: props.authorization,
      language: props.locale
    });

    this.service = new LayersService({
      authorization: props.authorization
    });

    this.layerManager = new LayerManager(null, {
      layersUpdated: (valid, err) => {
        this.props.dispatch(setLayerInteractionError(valid ? false : err));
      }
    });

    // BINDINGS
    this.onSubmit = this.onSubmit.bind(this);
    this.onChange = this.onChange.bind(this);
    this.onChangeDataset = this.onChangeDataset.bind(this);
    this.onStepChange = this.onStepChange.bind(this);
  }

  componentDidMount() {
    const { id } = this.state;

    const promises = [
      this.datasetsService.fetchAllData({})
    ];

    // Add the dashboard promise if the id exists
    if (id) {
      promises.push(this.service.fetchData({ id }));
    }

    Promise.all(promises)
      .then((response) => {
        const datasets = response[0];
        const current = response[1];

        const formState = (id) ? this.setFormFromParams(current) : this.state.form;

        this.setState({
          // CURRENT LAYER
          form: formState,
          loading: false,
          // CURRENT DATASET
          dataset: formState.dataset,
          // OPTIONS
          datasets: datasets.map(d => ({ label: d.name, value: d.id }))
        });
      })
      .catch((err) => {
        toastr.error('Error', err);
      });
  }

  /**
   * UI EVENTS
   * - onSubmit
   * - onChange
   * - onChangeDataset
  */
  onSubmit(event) {
    if (event) event.preventDefault();

    // Validate the form
    FORM_ELEMENTS.validate(this.state.step);

    // Set a timeout due to the setState function of react
    setTimeout(() => {
      // Validate all the inputs on the current step
      const valid = FORM_ELEMENTS.isValid(this.state.step);
      const { interactions } = this.props;

      // Grab all the interactions from the redux store
      const interactionConfig = Object.assign(
        {},
        this.state.form.interactionConfig,
        { output: interactions.added }
      );

      const form = Object.assign({}, this.state.form, { interactionConfig });

      // Verify that layers are valid, otherwise render error
      const { adminLayerPreview } = this.props;
      const { layerGroups } = adminLayerPreview;
      const cartoLayer = layerGroups.length && 'layers' in layerGroups[0] ?
        layerGroups[0].layers.filter(layer => layer.provider === 'cartodb') : [];

      if (valid) {
        // Start the submitting
        this.setState({ submitting: true });
        this.props.dispatch(setLayerInteractionError(false));

        if (cartoLayer.length) {
          // If we have carto layers, make sure they work
          this.layerManager.verifyCartoLayer(Object.assign(
            {},
            cartoLayer[0],
            { layerConfig: form.layerConfig }
          ), (cartoLayerValid) => {
            if (cartoLayerValid) {
              this.saveLayer(form);
            } else {
              toastr.error('Error', 'Layer config contains errors');
              this.setState({ submitting: false });
            }
          });
          return;
        }

        this.saveLayer(form);
      } else {
        toastr.error('Error', 'Fill all the required fields or correct the invalid values');
      }
    }, 0);
  }

  onChange(obj) {
    const form = Object.assign({}, this.state.form, obj);
    this.setState({ form });
  }

  onChangeDataset(dataset) {
    this.setState({ dataset });
  }

  onStepChange(step) {
    this.setState({ step });
  }

  // HELPERS
  setFormFromParams(params) {
    const newForm = {};

    Object.keys(params).forEach((f) => {
      switch (f) {
        default: {
          if ((typeof params[f] !== 'undefined' || params[f] !== null) ||
              (typeof this.state.form[f] !== 'undefined' || this.state.form[f] !== null)) {
            newForm[f] = params[f] || this.state.form[f];
          }
        }
      }
    });

    return newForm;
  }

  /**
   * Set the layer interaction of the store
   * @export
   * @param {Layer{}} layer
   */
  setLayerInteraction(layer) {
    return (dispatch) => {
      dispatch({
        type: SET_LAYERS_INTERACTION,
        payload: layer
      });
    };
  }

  setLayerInteractionSelected(id) {
    return (dispatch) => {
      dispatch({
        type: SET_LAYER_INTERACTION_SELECTED,
        payload: id
      });
    };
  }

  setLayerInteractionLatLng(latlng) {
    return (dispatch) => {
      dispatch({
        type: SET_LAYER_INTERACTION_LATLNG,
        payload: latlng
      });
    };
  }

  verifyLayerConfig() {
    const { adminLayerPreview } = this.props;
    const { layerGroups } = adminLayerPreview;

    const { form } = this.state;

    const cartoLayer = layerGroups.length && 'layers' in layerGroups[0] ?
      layerGroups[0].layers.filter(layer => layer.provider === 'cartodb') : [];

    if (cartoLayer.length) {
      // If we have carto layers, make sure they work
      this.layerManager.verifyCartoLayer(Object.assign(
        {},
        cartoLayer[0],
        { layerConfig: form.layerConfig }
      ));
    }
  }

  saveLayer(form) {
    const { id, dataset } = this.state;
    this.service.saveData({
      dataset,
      id: id || '',
      type: (id) ? 'PATCH' : 'POST',
      body: form
    }).then((data) => {
      toastr.success('Success', `The layer "${data.id}" - "${data.name}" has been uploaded correctly`);
      if (this.props.onSubmit) this.props.onSubmit();
      this.setState({ submitting: false, form: data });
    }).catch((errors) => {
      this.setState({ submitting: false });
      try {
        errors.forEach(er => toastr.error('Error', er.detail));
      } catch (e) {
        toastr.error('Error', 'Oops! There was an error, try again.');
      }
    });
  }

  render() {
    return (
      <form className="c-form c-layers-form" onSubmit={this.onSubmit} noValidate>
        <Spinner isLoading={this.state.loading} className="-light" />

        {(this.state.step === 1 && !this.state.loading) &&
          <Step1
            ref={(c) => { this.step = c; }}
            form={this.state.form}
            id={this.state.id}
            layerPreview={this.props.adminLayerPreview}
            dataset={this.state.dataset}
            datasets={this.state.datasets}
            onChange={value => this.onChange(value)}
            onChangeDataset={value => this.onChangeDataset(value)}
            setLayerInteraction={this.setLayerInteraction}
            setLayerInteractionSelected={this.setLayerInteractionSelected}
            setLayerInteractionLatLng={this.setLayerInteractionLatLng}
            verifyLayerConfig={() => this.verifyLayerConfig()}
          />
        }

        {!this.state.loading &&
          <Navigation
            step={this.state.step}
            stepLength={this.state.stepLength}
            submitting={this.state.submitting}
            onStepChange={this.onStepChange}
          />
        }
      </form>
    );
  }
}

LayersForm.propTypes = {
  id: PropTypes.string,
  dataset: PropTypes.string,
  authorization: PropTypes.string,
  application: PropTypes.array,
  onSubmit: PropTypes.func,
  locale: PropTypes.string.isRequired,
  interactions: PropTypes.object.isRequired,
  adminLayerPreview: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  locale: state.common.locale,
  interactions: state.interactions,
  adminLayerPreview: state.adminLayerPreview
});

export default connect(mapStateToProps, null)(LayersForm);
<commit_msg>Unexpected behavior on save fixed<commit_after>import React from 'react';
import PropTypes from 'prop-types';

// Redux
import { connect } from 'react-redux';

// Services
import DatasetsService from 'services/DatasetsService';
import LayersService from 'services/LayersService';
import { toastr } from 'react-redux-toastr';

// Constants
import { STATE_DEFAULT, FORM_ELEMENTS } from 'components/admin/layers/form/constants';

import { setLayerInteractionError } from 'components/admin/layers/form/layer-preview/layer-preview-actions';

// Components
import Step1 from 'components/admin/layers/form/steps/Step1';
import Navigation from 'components/form/Navigation';
import Spinner from 'components/ui/Spinner';

import LayerManager from 'utils/layers/LayerManager';

class LayersForm extends React.Component {
  constructor(props) {
    super(props);

    const formObj = props.dataset ?
      Object.assign({}, STATE_DEFAULT.form,
        { dataset: props.dataset, application: props.application }) :
      Object.assign({}, STATE_DEFAULT.form, {
        application: props.application
      });

    this.state = Object.assign({}, STATE_DEFAULT, {
      id: props.id,
      dataset: props.dataset,
      datasets: [],
      form: formObj,
      loading: !!props.id
    });

    // Service
    this.datasetsService = new DatasetsService({
      authorization: props.authorization,
      language: props.locale
    });

    this.service = new LayersService({
      authorization: props.authorization
    });

    this.layerManager = new LayerManager(null, {
      layersUpdated: (valid, err) => {
        this.props.dispatch(setLayerInteractionError(valid ? false : err));
      }
    });

    // BINDINGS
    this.onSubmit = this.onSubmit.bind(this);
    this.onChange = this.onChange.bind(this);
    this.onChangeDataset = this.onChangeDataset.bind(this);
    this.onStepChange = this.onStepChange.bind(this);
  }

  componentDidMount() {
    const { id } = this.state;

    const promises = [
      this.datasetsService.fetchAllData({})
    ];

    // Add the dashboard promise if the id exists
    if (id) {
      promises.push(this.service.fetchData({ id }));
    }

    Promise.all(promises)
      .then((response) => {
        const datasets = response[0];
        const current = response[1];

        const formState = (id) ? this.setFormFromParams(current) : this.state.form;

        this.setState({
          // CURRENT LAYER
          form: formState,
          loading: false,
          // CURRENT DATASET
          dataset: formState.dataset,
          // OPTIONS
          datasets: datasets.map(d => ({ label: d.name, value: d.id }))
        });
      })
      .catch((err) => {
        toastr.error('Error', err);
      });
  }

  /**
   * UI EVENTS
   * - onSubmit
   * - onChange
   * - onChangeDataset
  */
  onSubmit(event) {
    if (event) event.preventDefault();

    // Validate the form
    FORM_ELEMENTS.validate(this.state.step);

    // Set a timeout due to the setState function of react
    setTimeout(() => {
      // Validate all the inputs on the current step
      const valid = FORM_ELEMENTS.isValid(this.state.step);
      const { interactions } = this.props;

      let interactionConfig = this.state.form.interactionConfig;
      // Grab all the interactions from the redux store
      if (this.state.form.provider !== 'gee') {
        interactionConfig = Object.assign(
          {},
          this.state.form.interactionConfig,
          { output: interactions.added }
        );
      }

      const form = Object.assign({}, this.state.form, { interactionConfig });

      // Verify that layers are valid, otherwise render error
      const { adminLayerPreview } = this.props;
      const { layerGroups } = adminLayerPreview;
      const cartoLayer = layerGroups.length && 'layers' in layerGroups[0] ?
        layerGroups[0].layers.filter(layer => layer.provider === 'cartodb') : [];

      if (valid) {
        // Start the submitting
        this.setState({ submitting: true });
        this.props.dispatch(setLayerInteractionError(false));

        if (cartoLayer.length) {
          // If we have carto layers, make sure they work
          this.layerManager.verifyCartoLayer(Object.assign(
            {},
            cartoLayer[0],
            { layerConfig: form.layerConfig }
          ), (cartoLayerValid) => {
            if (cartoLayerValid) {
              this.saveLayer(form);
            } else {
              toastr.error('Error', 'Layer config contains errors');
              this.setState({ submitting: false });
            }
          });
          return;
        }

        this.saveLayer(form);
      } else {
        toastr.error('Error', 'Fill all the required fields or correct the invalid values');
      }
    }, 0);
  }

  onChange(obj) {
    const form = Object.assign({}, this.state.form, obj);
    this.setState({ form });
  }

  onChangeDataset(dataset) {
    this.setState({ dataset });
  }

  onStepChange(step) {
    this.setState({ step });
  }

  // HELPERS
  setFormFromParams(params) {
    const newForm = {};

    Object.keys(params).forEach((f) => {
      switch (f) {
        default: {
          if ((typeof params[f] !== 'undefined' || params[f] !== null) ||
              (typeof this.state.form[f] !== 'undefined' || this.state.form[f] !== null)) {
            newForm[f] = params[f] || this.state.form[f];
          }
        }
      }
    });

    return newForm;
  }

  /**
   * Set the layer interaction of the store
   * @export
   * @param {Layer{}} layer
   */
  setLayerInteraction(layer) {
    return (dispatch) => {
      dispatch({
        type: SET_LAYERS_INTERACTION,
        payload: layer
      });
    };
  }

  setLayerInteractionSelected(id) {
    return (dispatch) => {
      dispatch({
        type: SET_LAYER_INTERACTION_SELECTED,
        payload: id
      });
    };
  }

  setLayerInteractionLatLng(latlng) {
    return (dispatch) => {
      dispatch({
        type: SET_LAYER_INTERACTION_LATLNG,
        payload: latlng
      });
    };
  }

  verifyLayerConfig() {
    const { adminLayerPreview } = this.props;
    const { layerGroups } = adminLayerPreview;

    const { form } = this.state;

    const cartoLayer = layerGroups.length && 'layers' in layerGroups[0] ?
      layerGroups[0].layers.filter(layer => layer.provider === 'cartodb') : [];

    if (cartoLayer.length) {
      // If we have carto layers, make sure they work
      this.layerManager.verifyCartoLayer(Object.assign(
        {},
        cartoLayer[0],
        { layerConfig: form.layerConfig }
      ));
    }
  }

  saveLayer(form) {
    const { id, dataset } = this.state;
    this.service.saveData({
      dataset,
      id: id || '',
      type: (id) ? 'PATCH' : 'POST',
      body: form
    }).then((data) => {
      toastr.success('Success', `The layer "${data.id}" - "${data.name}" has been uploaded correctly`);
      if (this.props.onSubmit) this.props.onSubmit();
      this.setState({ submitting: false, form: data });
    }).catch((errors) => {
      this.setState({ submitting: false });
      try {
        errors.forEach(er => toastr.error('Error', er.detail));
      } catch (e) {
        toastr.error('Error', 'Oops! There was an error, try again.');
      }
    });
  }

  render() {
    return (
      <form className="c-form c-layers-form" onSubmit={this.onSubmit} noValidate>
        <Spinner isLoading={this.state.loading} className="-light" />

        {(this.state.step === 1 && !this.state.loading) &&
          <Step1
            ref={(c) => { this.step = c; }}
            form={this.state.form}
            id={this.state.id}
            layerPreview={this.props.adminLayerPreview}
            dataset={this.state.dataset}
            datasets={this.state.datasets}
            onChange={value => this.onChange(value)}
            onChangeDataset={value => this.onChangeDataset(value)}
            setLayerInteraction={this.setLayerInteraction}
            setLayerInteractionSelected={this.setLayerInteractionSelected}
            setLayerInteractionLatLng={this.setLayerInteractionLatLng}
            verifyLayerConfig={() => this.verifyLayerConfig()}
          />
        }

        {!this.state.loading &&
          <Navigation
            step={this.state.step}
            stepLength={this.state.stepLength}
            submitting={this.state.submitting}
            onStepChange={this.onStepChange}
          />
        }
      </form>
    );
  }
}

LayersForm.propTypes = {
  id: PropTypes.string,
  dataset: PropTypes.string,
  authorization: PropTypes.string,
  application: PropTypes.array,
  onSubmit: PropTypes.func,
  locale: PropTypes.string.isRequired,
  interactions: PropTypes.object.isRequired,
  adminLayerPreview: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  locale: state.common.locale,
  interactions: state.interactions,
  adminLayerPreview: state.adminLayerPreview
});

export default connect(mapStateToProps, null)(LayersForm);
<|endoftext|>


<commit_before>/* The number of fake symbols we've served up */
let count = 0;

/**
 * @param {any} description
 * @returns {string}
 */
function uniqueString(description) {
  return `_${description}${count++}`;
}

/**
 * A helper function for simulating instances of the `Symbol` class in older
 * browsers, notably Microsoft Internet Explorer 11.
 *
 * Mixins and component classes often want to associate private data with an
 * element instance, but JavaScript does not have direct support for true
 * private properties. Elix uses `Symbol` instances as property keys to set and
 * retrieve data on an element. This prevents accidental name collisions. While
 * it does not make the properties completely private, it does make them
 * somewhat harder to access, and hopefully discourages outside code from
 * directly manipulating the properties.
 *
 * In modern browsers that support `Symbol`, the Elix `Symbol` helper function
 * simply returns a real `Symbol` instance. In browsers like IE that do not have
 * support for `Symbol`, the Elix `Symbol` helper function returns a different
 * string each time it is called.
 *
 * Usage:
 *
 *     const fooKey = Symbol('foo');
 *
 *     class MyElement extends HTMLElement {
 *       get foo() {
 *         return this[fooKey];
 *       }
 *       set foo(value) {
 *         this[fooKey] = value;
 *       }
 *     }
 *
 * In IE 11, this sample will "hide" data behind an instance property that looks
 * like `this._foo0`, `this._foo1`, etc. The underscore is meant to reduce (not
 * eliminate) potential accidental access, and the unique number at the end is
 * mean to avoid (not eliminate) naming conflicts.
 *
 * @function Symbol
 * @param {any} description - A string to identify the symbol when debugging
 * @returns {symbol|string} — A Symbol (in ES6 browsers) or unique string ID (in
 * ES5).
 */
export default function(description) {
  return typeof Symbol === 'function' ?
    Symbol(description) :
    uniqueString(description);
}
<commit_msg>Fix trivial jsDoc syntax error.<commit_after>/* The number of fake symbols we've served up */
let count = 0;

/**
 * @param {any} description
 * @returns {string}
 */
function uniqueString(description) {
  return `_${description}${count++}`;
}

/**
 * A helper function for simulating instances of the `Symbol` class in older
 * browsers, notably Microsoft Internet Explorer 11.
 *
 * Mixins and component classes often want to associate private data with an
 * element instance, but JavaScript does not have direct support for true
 * private properties. Elix uses `Symbol` instances as property keys to set and
 * retrieve data on an element. This prevents accidental name collisions. While
 * it does not make the properties completely private, it does make them
 * somewhat harder to access, and hopefully discourages outside code from
 * directly manipulating the properties.
 *
 * In modern browsers that support `Symbol`, the Elix `Symbol` helper function
 * simply returns a real `Symbol` instance. In browsers like IE that do not have
 * support for `Symbol`, the Elix `Symbol` helper function returns a different
 * string each time it is called.
 *
 * Usage:
 *
 *     const fooKey = Symbol('foo');
 *
 *     class MyElement extends HTMLElement {
 *       get foo() {
 *         return this[fooKey];
 *       }
 *       set foo(value) {
 *         this[fooKey] = value;
 *       }
 *     }
 *
 * In IE 11, this sample will "hide" data behind an instance property that looks
 * like `this._foo0`, `this._foo1`, etc. The underscore is meant to reduce (not
 * eliminate) potential accidental access, and the unique number at the end is
 * mean to avoid (not eliminate) naming conflicts.
 *
 * @function Symbol
 * @param {any} description - A string to identify the symbol when debugging
 * @returns {symbol|string} - A Symbol (in ES6 browsers) or unique string ID (in
 * ES5).
 */
export default function(description) {
  return typeof Symbol === 'function' ?
    Symbol(description) :
    uniqueString(description);
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import 'isomorphic-fetch';
import { Autobind } from 'es-decorators';

// Components
import Title from 'components/ui/Title';
import TextChart from 'components/widgets/TextChart';
import VegaChart from 'components/widgets/VegaChart';
import Map from 'components/vis/Map';
import Legend from 'components/ui/Legend';
import Spinner from 'components/ui/Spinner';
import Icon from 'components/ui/Icon';

// Redux
import { connect } from 'react-redux';

// Utils
import getChartTheme from 'utils/widgets/theme';
import LayerManager from 'utils/layers/LayerManager';

// Services
import UserService from 'services/UserService';

class DashboardCard extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      error: null, // Error message
      loading: false,
      name: null, // Name of the widget
      widgetConfig: null, // Vega config of the widget
      layers: [], // Map's layers
      isFavourite: props.isFavourite
    };

    // Services
    this.userService = new UserService({ apiURL: process.env.CONTROL_TOWER_URL });
  }

  componentDidMount() {
    if (this.props.widgetId) {
      this.getData();
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.isFavourite !== this.state.isFavourite) {
      this.setState({
        isFavourite: nextProps.isFavourite
      });
    }
  }

  /**
   * Fetch the widget's data and set a few properties in the
   * state once done
   */
  getData() {
    this.setState({ loading: true });

    fetch(`${process.env.WRI_API_URL}/widget/${this.props.widgetId}`)
      .then((res) => {
        if (res.ok) return res.json();
        throw new Error(res.statusText);
      })
      .then(({ data }) => {
        this.setState({
          name: data.attributes.name,
          widgetConfig: data.attributes.widgetConfig
        }, () => {
          // If the widget is a map, we also fetch its layer
          if (data.attributes.widgetConfig.type && data.attributes.widgetConfig.type === 'map') {
            this.getLayer();
          }
        });
      })
      .catch(err => this.setState({ error: err.message }));
      // TODO error message
  }

  /**
   * Fetch the map's layer if the widget is a map and store it
   * in the state
   * NOTE: you should only call this method if you're sure the
   * widget is a map and its config has been loaded
   */
  getLayer() {
    // At this point, loading is still true
    const widgetConfig = this.getWidgetConfig();

    fetch(`${process.env.WRI_API_URL}/layer/${widgetConfig.layer_id}`)
      .then((res) => {
        if (res.ok) return res.json();
        throw new Error(res.statusText);
      })
      .then(({ data }) => {
        this.setState({
          layers: [{
            dataset: data.attributes.dataset,
            visible: true,
            layers: [{
              id: data.id,
              active: true,
              ...data.attributes
            }]
          }]
        });
      })
      .catch(err => this.setState({ error: err.message }))
      // We remove the loader because the map will render
      // right away
      .then(() => this.setState({ loading: false }));
  }

  /**
   * Return the widget config
   * @returns {object}
   */
  getWidgetConfig() {
    return (this.props.data && this.props.data.attributes.widgetConfig)
      || this.state.widgetConfig;
  }

  /**
   * Return the type of widget
   * @returns {'vega'|'map'|'text'}
   */
  getWidgetType() {
    const widgetConfig = this.getWidgetConfig();
    return (widgetConfig && widgetConfig.type) || 'vega';
  }

  @Autobind
  handleFavouriteClick() {
    const { isFavourite, widgetId, user } = this.props;
    this.setState({
      loading: true
    });
    if (isFavourite) {
      this.userService.deleteFavourite(isFavourite.id, user.token)
        .then(() => {
          this.setState({
            isFavourite: false,
            loading: false
          });
        }
      ).catch(err => console.error(err));
    } else {
      this.userService.createFavouriteWidget(widgetId, user.token)
        .then(() => {
          this.setState({
            isFavourite: true,
            loading: false
          });
        }
      ).catch(err => console.error(err));
    }
  }

  render() {
    const { isFavourite } = this.state;
    const widgetConfig = this.getWidgetConfig();

    // Type of the widget: "vega", "text" or "map"
    const widgetType = (widgetConfig && widgetConfig.type) || 'vega';

    const iconName = (isFavourite && isFavourite.id) ? 'star-full' : 'star-empty';

    return (

            <Title className="-default">{this.state.name || this.props.name || '–'}</Title>
            <button
              onClick={this.handleFavouriteClick}
            >
              <Icon name={`icon-${iconName}`} className="c-icon -small" />
            </button>

            {this.props.categories.map(category =>
{category}
)}

          <Spinner isLoading={this.state.loading} className="-light -small" />
          { !this.state.error && widgetType === 'text'
            && <TextChart
              widgetConfig={widgetConfig}
              toggleLoading={loading => this.setState({ loading })}
            />
          }
          { !this.state.error && widgetConfig && widgetType === 'vega'
            && <VegaChart
              data={widgetConfig}
              theme={getChartTheme()}
              toggleLoading={loading => this.setState({ loading })}
              reloadOnResize
            />
          }
          {
            !this.state.error && widgetConfig && widgetType === 'map' && this.state.layers
              && (

                  <Map
                    LayerManager={LayerManager}
                    mapConfig={{}}
                    layerGroups={this.state.layers}
                  />
                  <Legend
                    layerGroups={this.state.layers}
                    className={{ color: '-dark' }}
                    setLayerGroupsOrder={() => {}}
                    setLayerGroupActiveLayer={() => {}}
                    expanded={false}
                    readonly
                  />

              )
          }
          { !this.state.error && !this.props.data && !this.props.widgetId
            &&

No data

          }
          { this.state.error
            &&

Unable to load the widget {this.state.error}

          }

    );
  }

}

DashboardCard.propTypes = {
  widgetId: PropTypes.string.isRequired,
  categories: PropTypes.arrayOf(PropTypes.string).isRequired,
  isFavourite: PropTypes.bool.isRequired,
  // Redux
  user: PropTypes.object.isRequired,
  // NOTE:
  // The following props will be deprecated once the dashboards
  // have all of their widgets in the API
  name: PropTypes.string,
  data: PropTypes.object // Raw data from the server: { data: { attributes: { ... } } }
};

const mapStateToProps = state => ({
  user: state.user
});

const mapDispatchToProps = () => ({});

export default connect(mapStateToProps, mapDispatchToProps)(DashboardCard);
<commit_msg>Update DashboardCard bcse Legend's props changed<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import 'isomorphic-fetch';
import { Autobind } from 'es-decorators';

// Components
import Title from 'components/ui/Title';
import TextChart from 'components/widgets/TextChart';
import VegaChart from 'components/widgets/VegaChart';
import Map from 'components/vis/Map';
import Legend from 'components/ui/Legend';
import Spinner from 'components/ui/Spinner';
import Icon from 'components/ui/Icon';

// Redux
import { connect } from 'react-redux';

// Utils
import getChartTheme from 'utils/widgets/theme';
import LayerManager from 'utils/layers/LayerManager';

// Services
import UserService from 'services/UserService';

class DashboardCard extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      error: null, // Error message
      loading: false,
      name: null, // Name of the widget
      widgetConfig: null, // Vega config of the widget
      layers: [], // Map's layers
      isFavourite: props.isFavourite
    };

    // Services
    this.userService = new UserService({ apiURL: process.env.CONTROL_TOWER_URL });
  }

  componentDidMount() {
    if (this.props.widgetId) {
      this.getData();
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.isFavourite !== this.state.isFavourite) {
      this.setState({
        isFavourite: nextProps.isFavourite
      });
    }
  }

  /**
   * Event handler executed when the user toggles the
   * visibility of a layer group
   * @param {LayerGroup} layerGroup - Layer group to toggle
   */
  onToggleLayerGroupVisibility(layerGroup) {
    const layerGroups = this.state.layers.map((l) => {
      if (l.dataset !== layerGroup.dataset) return l;
      return Object.assign({}, l, { visible: !layerGroup.visible });
    });

    this.setState({ layers: [...layerGroups] });
  }

  /**
   * Fetch the widget's data and set a few properties in the
   * state once done
   */
  getData() {
    this.setState({ loading: true });

    fetch(`${process.env.WRI_API_URL}/widget/${this.props.widgetId}`)
      .then((res) => {
        if (res.ok) return res.json();
        throw new Error(res.statusText);
      })
      .then(({ data }) => {
        this.setState({
          name: data.attributes.name,
          widgetConfig: data.attributes.widgetConfig
        }, () => {
          // If the widget is a map, we also fetch its layer
          if (data.attributes.widgetConfig.type && data.attributes.widgetConfig.type === 'map') {
            this.getLayer();
          }
        });
      })
      .catch(err => this.setState({ error: err.message }));
      // TODO error message
  }

  /**
   * Fetch the map's layer if the widget is a map and store it
   * in the state
   * NOTE: you should only call this method if you're sure the
   * widget is a map and its config has been loaded
   */
  getLayer() {
    // At this point, loading is still true
    const widgetConfig = this.getWidgetConfig();

    fetch(`${process.env.WRI_API_URL}/layer/${widgetConfig.layer_id}`)
      .then((res) => {
        if (res.ok) return res.json();
        throw new Error(res.statusText);
      })
      .then(({ data }) => {
        this.setState({
          layers: [{
            dataset: data.attributes.dataset,
            visible: true,
            layers: [{
              id: data.id,
              active: true,
              ...data.attributes
            }]
          }]
        });
      })
      .catch(err => this.setState({ error: err.message }))
      // We remove the loader because the map will render
      // right away
      .then(() => this.setState({ loading: false }));
  }

  /**
   * Return the widget config
   * @returns {object}
   */
  getWidgetConfig() {
    return (this.props.data && this.props.data.attributes.widgetConfig)
      || this.state.widgetConfig;
  }

  /**
   * Return the type of widget
   * @returns {'vega'|'map'|'text'}
   */
  getWidgetType() {
    const widgetConfig = this.getWidgetConfig();
    return (widgetConfig && widgetConfig.type) || 'vega';
  }

  @Autobind
  handleFavouriteClick() {
    const { isFavourite, widgetId, user } = this.props;
    this.setState({
      loading: true
    });
    if (isFavourite) {
      this.userService.deleteFavourite(isFavourite.id, user.token)
        .then(() => {
          this.setState({
            isFavourite: false,
            loading: false
          });
        }
      ).catch(err => console.error(err));
    } else {
      this.userService.createFavouriteWidget(widgetId, user.token)
        .then(() => {
          this.setState({
            isFavourite: true,
            loading: false
          });
        }
      ).catch(err => console.error(err));
    }
  }

  render() {
    const { isFavourite } = this.state;
    const widgetConfig = this.getWidgetConfig();

    // Type of the widget: "vega", "text" or "map"
    const widgetType = (widgetConfig && widgetConfig.type) || 'vega';

    const iconName = (isFavourite && isFavourite.id) ? 'star-full' : 'star-empty';

    return (

            <Title className="-default">{this.state.name || this.props.name || '–'}</Title>
            <button
              onClick={this.handleFavouriteClick}
            >
              <Icon name={`icon-${iconName}`} className="c-icon -small" />
            </button>

            {this.props.categories.map(category =>
{category}
)}

          <Spinner isLoading={this.state.loading} className="-light -small" />
          { !this.state.error && widgetType === 'text'
            && <TextChart
              widgetConfig={widgetConfig}
              toggleLoading={loading => this.setState({ loading })}
            />
          }
          { !this.state.error && widgetConfig && widgetType === 'vega'
            && <VegaChart
              data={widgetConfig}
              theme={getChartTheme()}
              toggleLoading={loading => this.setState({ loading })}
              reloadOnResize
            />
          }
          {
            !this.state.error && widgetConfig && widgetType === 'map' && this.state.layers
              && (

                  <Map
                    LayerManager={LayerManager}
                    mapConfig={{}}
                    layerGroups={this.state.layers}
                  />
                  <Legend
                    layerGroups={this.state.layers}
                    className={{ color: '-dark' }}
                    toggleLayerGroupVisibility={
                      layerGroup => this.onToggleLayerGroupVisibility(layerGroup)
                    }
                    setLayerGroupsOrder={() => {}}
                    setLayerGroupActiveLayer={() => {}}
                    expanded={false}
                    readonly
                  />

              )
          }
          { !this.state.error && !this.props.data && !this.props.widgetId
            &&

No data

          }
          { this.state.error
            &&

Unable to load the widget {this.state.error}

          }

    );
  }

}

DashboardCard.propTypes = {
  widgetId: PropTypes.string.isRequired,
  categories: PropTypes.arrayOf(PropTypes.string).isRequired,
  isFavourite: PropTypes.bool.isRequired,
  // Redux
  user: PropTypes.object.isRequired,
  // NOTE:
  // The following props will be deprecated once the dashboards
  // have all of their widgets in the API
  name: PropTypes.string,
  data: PropTypes.object // Raw data from the server: { data: { attributes: { ... } } }
};

const mapStateToProps = state => ({
  user: state.user
});

const mapDispatchToProps = () => ({});

export default connect(mapStateToProps, mapDispatchToProps)(DashboardCard);
<|endoftext|>


<commit_before>const Sequelize = require(__dirname + "/../index")
    , DataTypes = require(__dirname + "/../lib/data-types")
    , config    = require(__dirname + "/config/config")
    , fs        = require('fs')
    , buster    = require("buster")

var BusterHelpers = module.exports = {
  Sequelize: Sequelize,

  initTests: function(options) {
    var sequelize = this.createSequelizeInstance(options)

    this.clearDatabase(sequelize, function() {
      if (options.context) {
        options.context.sequelize = sequelize
      }

      if (options.beforeComplete) {
        options.beforeComplete(sequelize, DataTypes)
      }

      if (options.onComplete) {
        options.onComplete(sequelize, DataTypes)
      }
    })
  },

  createSequelizeInstance: function(options) {
    options = options || {}

    options.dialect = options.dialect || 'mysql'
    options.logging = (options.hasOwnProperty('logging') ? options.logging : false)

    var sequelizeOptions = {
      logging: options.logging,
      dialect: options.dialect,
      port:    config[options.dialect].port
    }

    if (process.env.DIALECT === 'postgres-native') {
      sequelizeOptions.native = true
    }

    return new Sequelize(
      config[options.dialect].database,
      config[options.dialect].username,
      config[options.dialect].password,
      sequelizeOptions
    )
  },

  clearDatabase: function(sequelize, callback) {
    sequelize
      .getQueryInterface()
      .dropAllTables()
      .success(function() {
        sequelize.daoFactoryManager.daos = []
        callback && callback()
      })
      .error(function(err) { console.log(err) })
  },

  getSupportedDialects: function() {
    return fs.readdirSync(__dirname + '/../lib/dialects').filter(function(file) {
      return ((file.indexOf('.js') === -1) && (file.indexOf('abstract') === -1))
    })
  },

  getTestDialect: function() {
    var envDialect = process.env.DIALECT || 'mysql'

    if (envDialect === 'postgres-native') {
      envDialect = 'postgres'
    }

    if (this.getSupportedDialects().indexOf(envDialect) === -1) {
      throw new Error('The dialect you have passed is unknown. Did you really mean: ' + envDialect)
    }

    return envDialect
  },

  getTestDialectTeaser: function(moduleName) {
    var dialect = this.getTestDialect()

    if (process.env.DIALECT === 'postgres-native') {
      dialect = 'postgres-native'
    }

    return "[" + dialect.toUpperCase() + "] " + moduleName
  },

  checkMatchForDialects: function(dialect, value, expectations) {
    if (!!expectations[dialect]) {
      expect(value).toMatch(expectations[dialect])
    } else {
      throw new Error('Undefined expectation for "' + dialect + '"!')
    }
  },

  assertException: function(block, msg) {
    try {
      block()
      throw new Error('Passed function did not throw an error')
    } catch(e) {
      buster.assert.equals(e.message, msg)
    }
  }
}
<commit_msg>Added  variables for buster-test/npm buster tests for quicker testing.<commit_after>const Sequelize = require(__dirname + "/../index")
    , DataTypes = require(__dirname + "/../lib/data-types")
    , config    = require(__dirname + "/config/config")
    , fs        = require('fs')
    , buster    = require("buster")

var BusterHelpers = module.exports = {
  Sequelize: Sequelize,

  initTests: function(options) {
    var sequelize = this.createSequelizeInstance(options)

    this.clearDatabase(sequelize, function() {
      if (options.context) {
        options.context.sequelize = sequelize
      }

      if (options.beforeComplete) {
        options.beforeComplete(sequelize, DataTypes)
      }

      if (options.onComplete) {
        options.onComplete(sequelize, DataTypes)
      }
    })
  },

  createSequelizeInstance: function(options) {
    options = options || {}

    options.dialect = options.dialect || 'mysql'
    options.logging = (options.hasOwnProperty('logging') ? options.logging : false)

    var sequelizeOptions = {
      logging: options.logging,
      dialect: options.dialect,
      port:    process.env.SEQ_PORT || config[options.dialect].port
    }

    if (process.env.DIALECT === 'postgres-native') {
      sequelizeOptions.native = true
    }

    return new Sequelize(
      process.env.SEQ_DB    || config[options.dialect].database,
      process.env.SEQ_USER  || process.env.SEQ_USERNAME || config[options.dialect].username,
      process.env.SEQ_PW    || process.env.SEQ_PASSWORD || config[options.dialect].password,
      sequelizeOptions
    )
  },

  clearDatabase: function(sequelize, callback) {
    sequelize
      .getQueryInterface()
      .dropAllTables()
      .success(function() {
        sequelize.daoFactoryManager.daos = []
        callback && callback()
      })
      .error(function(err) { console.log(err) })
  },

  getSupportedDialects: function() {
    return fs.readdirSync(__dirname + '/../lib/dialects').filter(function(file) {
      return ((file.indexOf('.js') === -1) && (file.indexOf('abstract') === -1))
    })
  },

  getTestDialect: function() {
    var envDialect = process.env.DIALECT || 'mysql'

    if (envDialect === 'postgres-native') {
      envDialect = 'postgres'
    }

    if (this.getSupportedDialects().indexOf(envDialect) === -1) {
      throw new Error('The dialect you have passed is unknown. Did you really mean: ' + envDialect)
    }

    return envDialect
  },

  getTestDialectTeaser: function(moduleName) {
    var dialect = this.getTestDialect()

    if (process.env.DIALECT === 'postgres-native') {
      dialect = 'postgres-native'
    }

    return "[" + dialect.toUpperCase() + "] " + moduleName
  },

  checkMatchForDialects: function(dialect, value, expectations) {
    if (!!expectations[dialect]) {
      expect(value).toMatch(expectations[dialect])
    } else {
      throw new Error('Undefined expectation for "' + dialect + '"!')
    }
  },

  assertException: function(block, msg) {
    try {
      block()
      throw new Error('Passed function did not throw an error')
    } catch(e) {
      buster.assert.equals(e.message, msg)
    }
  }
}
<|endoftext|>


<commit_before>'use strict';
var tmp;
angular.module('skuapso.test', ['skuapso', 'skuapso-init'])
;
<commit_msg>js:test added probj to print object<commit_after>'use strict';

var tmp;
angular.module('skuapso.test', ['skuapso', 'skuapso-init'])
;

var objs = [];
function probj(obj, nesting) {
  var id, n = typeof nesting === 'undefined' ? 0 : nesting;
  objs.push(obj);
  for (id in obj) {
    console.debug('%o, %o: %o', n, id, obj[id]);
    if (angular.isArray(obj[id])) continue;
    if (angular.isString(obj[id])) continue;
    if (objs.indexOf(obj[id]) == -1) {
      probj(obj[id], n + 1);
    }
  }
  objs.pop();
};
<|endoftext|>


<commit_before>/* Exports a function which returns an object that overrides the default &
 *   plugin grunt configuration object.
 *
 * You can familiarize yourself with Lineman's defaults by checking out:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
 *   - https://github.com/linemanjs/lineman/blob/master/config/plugins
 *
 * You can also ask Lineman's about config from the command line:
 *
 *   $ lineman config #=> to print the entire config
 *   $ lineman config concat.js #=> to see the JS config for the concat task.
 */
module.exports = function(lineman) {
    //Override application configuration here. Common examples follow in the comments.

    // DO NOT REMOVE
    var app = lineman.config.application;

    return {
        // grunt-angular-templates assumes your module is named "app", but
        // you can override it like so:
        //
        // ngtemplates: {
        //   options: {
        //     module: "myModuleName"
        //   }
        // }

        server: {
            pushState: true
            // API Proxying
            //
            // During development, you'll likely want to make XHR (AJAX) requests to an API on the same
            // port as your lineman development server. By enabling the API proxy and setting the port, all
            // requests for paths that don't match a static asset in ./generated will be forwarded to
            // whatever service might be running on the specified port.
            //
            // apiProxy: {
            //   enabled: true,
            //   host: 'localhost',
            //   port: 3000
            // }
        },

        loadNpmTasks: lineman.config.application.loadNpmTasks.concat("grunt-contrib-copy", "grunt-contrib-clean", "grunt-ts"),

        /*
         * Task Configuration
         */
        copy: {
            ng2_css_generated: {
                // See Copy files to different directory (https://github.com/gruntjs/grunt-contrib-copy/issues/58)
                // I used to ensure that the compiled ts files (js / map) and their companions (ts / html / css) landed on the same folder
                expand: true,
                cwd: "app/ng2",
                src: "<%= files.ng2.css %>",
                dest: "<%= files.ng2.generated %>"
            },
             ng2_html_generated: {
                 // See Copy files to different directory (https://github.com/gruntjs/grunt-contrib-copy/issues/58)
                 // I used to ensure that the compiled ts files (js / map) and their companions (ts / html / css) landed on the same folder
                 expand: true,
                 cwd: "app/ng2",
                 src: "<%= files.ng2.html %>",
                 dest: "<%= files.ng2.generated %>"
             },
            ng2_libs_generated: {
                files: [
                    {expand: true, src: "<%= files.ng2.libs %>", dest: "generated/" }
                ]
            },
            ng2_other_generated: {
               // See Copy files to different directory (https://github.com/gruntjs/grunt-contrib-copy/issues/58)
                // I used to ensure that the compiled ts files (js / map) and their companions (ts / html / css) landed on the same folder
                expand: true,
                cwd: "app/ng2",
                src: ["<%= files.ng2.css %>", "<%= files.ng2.html %>"], //todo consolidate
                dest: "<%= files.ng2.generated %>"
            },
            ng2_libs_dist: {
                files: [
                    {expand: true, src: "<%= files.ng2.libs %>", dest: "dist/" }
                ]
            },
            ng2_other_dist: {
               // See Copy files to different directory (https://github.com/gruntjs/grunt-contrib-copy/issues/58)
                // I used to ensure that the compiled ts files (js / map) and their companions (ts / html / css) landed on the same folder
                expand: true,
                cwd: "app/ng2",
                src: ["<%= files.ng2.css %>", "<%= files.ng2.html %>"], //todo consolidate
                dest: "<%= files.ng2.dist %>"
            },
            systemjs_dist: {
                src: "systemjs.config.js",
                dest: "<%= files.ng2.systemjs.dist %>"
            },
            systemjs_generated: {
                src: "systemjs.config.js",
                dest: "<%= files.ng2.systemjs.generated %>"
            }
        },

        // Added this to fix the following error:
        // Warning: Path must be a string. Received null Use --force to continue.
        // found out about this error here: https://github.com/jshint/jshint/issues/2922
        jshint: {
            options: {
                reporterOutput: ""
            }
        },

        // Task to compile typescript files
        // Look here for config options: https://www.npmjs.com/package/grunt-ts
        ts: {
            development: {
                "src": "app/ng2/**/*.ts",
                "outDir": "<%= files.ng2.generated %>",
                "options": {
                    "emitDecoratorMetadata": true,
                    "module": "system",
                    "moduleResolution": "node",
                    "noImplicitAny": false,
                    "removeComments": false,
                    "sourceMap": true,
                    // using es5 is problematic with NG2-beta
                    // http://stackoverflow.com/questions/33332394/angular-2-typescript-cant-find-names
                    "target": "es6"
                }
            },
            production: {
                "src": "app/ng2/**/*.ts",
                "outDir": "<%= files.ng2.dist %>",
                "options": {
                    "emitDecoratorMetadata": true,
                    "module": "system",
                    "moduleResolution": "node",
                    "noImplicitAny": false,
                    "removeComments": false,
                    "sourceMap": false,
                    // using es5 is problematic with NG2-beta
                    // http://stackoverflow.com/questions/33332394/angular-2-typescript-cant-find-names
                    "target": "es6"
                }
            }
        },

        /*
        * Watch configuration
        */
        watch: {
               ng2_systemjs: {
                    "files": "systemjs.config.js",
                    "tasks": ["copy:systemjs_generated"]
                },
                // renamed & deleted files remain in place, restarting lineman run will fix it
                ng2_css: {
                    "files": "<%= files.ng2.css %>",
                    "tasks": ["copy:ng2_css_generated"]
                },
                // renamed & deleted files remain in place, restarting lineman run will fix it
                ng2_html: {
                    "files": "<%= files.ng2.html %>",
                    "tasks": ["copy:ng2_html_generated"]
                },
                // renamed & deleted files remain in place, restarting lineman run will fix it
                ng2_ts: {
                    "files": "<%= files.ng2.ts %>",
                    "tasks": ["ts:development"]
                }
        },

        /*
        * Workflow configuration
        */
        prependTasks: {
            common: lineman.config.application.prependTasks.common.concat(["ts:development"]),
            dev: ["copy:ng2_other_generated", "copy:ng2_libs_generated"].concat(lineman.config.application.prependTasks.dev),
            dist: ["copy:ng2_other_dist", "copy:ng2_libs_dist"].concat(lineman.config.application.prependTasks.dev)
        }
    };
};
<commit_msg>Removed unused file<commit_after>/* Exports a function which returns an object that overrides the default &
 *   plugin grunt configuration object.
 *
 * You can familiarize yourself with Lineman's defaults by checking out:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
 *   - https://github.com/linemanjs/lineman/blob/master/config/plugins
 *
 * You can also ask Lineman's about config from the command line:
 *
 *   $ lineman config #=> to print the entire config
 *   $ lineman config concat.js #=> to see the JS config for the concat task.
 */
module.exports = function(lineman) {
    //Override application configuration here. Common examples follow in the comments.

    // DO NOT REMOVE
    var app = lineman.config.application;

    return {
        // grunt-angular-templates assumes your module is named "app", but
        // you can override it like so:
        //
        // ngtemplates: {
        //   options: {
        //     module: "myModuleName"
        //   }
        // }

        server: {
            pushState: true
            // API Proxying
            //
            // During development, you'll likely want to make XHR (AJAX) requests to an API on the same
            // port as your lineman development server. By enabling the API proxy and setting the port, all
            // requests for paths that don't match a static asset in ./generated will be forwarded to
            // whatever service might be running on the specified port.
            //
            // apiProxy: {
            //   enabled: true,
            //   host: 'localhost',
            //   port: 3000
            // }
        },

        loadNpmTasks: lineman.config.application.loadNpmTasks.concat("grunt-contrib-copy", "grunt-ts"),

        /*
         * Task Configuration
         */
        copy: {
            ng2_css_generated: {
                // See Copy files to different directory (https://github.com/gruntjs/grunt-contrib-copy/issues/58)
                // I used to ensure that the compiled ts files (js / map) and their companions (ts / html / css) landed on the same folder
                expand: true,
                cwd: "app/ng2",
                src: "<%= files.ng2.css %>",
                dest: "<%= files.ng2.generated %>"
            },
             ng2_html_generated: {
                 // See Copy files to different directory (https://github.com/gruntjs/grunt-contrib-copy/issues/58)
                 // I used to ensure that the compiled ts files (js / map) and their companions (ts / html / css) landed on the same folder
                 expand: true,
                 cwd: "app/ng2",
                 src: "<%= files.ng2.html %>",
                 dest: "<%= files.ng2.generated %>"
             },
            ng2_libs_generated: {
                files: [
                    {expand: true, src: "<%= files.ng2.libs %>", dest: "generated/" }
                ]
            },
            ng2_other_generated: {
               // See Copy files to different directory (https://github.com/gruntjs/grunt-contrib-copy/issues/58)
                // I used to ensure that the compiled ts files (js / map) and their companions (ts / html / css) landed on the same folder
                expand: true,
                cwd: "app/ng2",
                src: ["<%= files.ng2.css %>", "<%= files.ng2.html %>"], //todo consolidate
                dest: "<%= files.ng2.generated %>"
            },
            ng2_libs_dist: {
                files: [
                    {expand: true, src: "<%= files.ng2.libs %>", dest: "dist/" }
                ]
            },
            ng2_other_dist: {
               // See Copy files to different directory (https://github.com/gruntjs/grunt-contrib-copy/issues/58)
                // I used to ensure that the compiled ts files (js / map) and their companions (ts / html / css) landed on the same folder
                expand: true,
                cwd: "app/ng2",
                src: ["<%= files.ng2.css %>", "<%= files.ng2.html %>"], //todo consolidate
                dest: "<%= files.ng2.dist %>"
            },
            systemjs_dist: {
                src: "systemjs.config.js",
                dest: "<%= files.ng2.systemjs.dist %>"
            },
            systemjs_generated: {
                src: "systemjs.config.js",
                dest: "<%= files.ng2.systemjs.generated %>"
            }
        },

        // Added this to fix the following error:
        // Warning: Path must be a string. Received null Use --force to continue.
        // found out about this error here: https://github.com/jshint/jshint/issues/2922
        jshint: {
            options: {
                reporterOutput: ""
            }
        },

        // Task to compile typescript files
        // Look here for config options: https://www.npmjs.com/package/grunt-ts
        ts: {
            development: {
                "src": "app/ng2/**/*.ts",
                "outDir": "<%= files.ng2.generated %>",
                "options": {
                    "emitDecoratorMetadata": true,
                    "module": "system",
                    "moduleResolution": "node",
                    "noImplicitAny": false,
                    "removeComments": false,
                    "sourceMap": true,
                    // using es5 is problematic with NG2-beta
                    // http://stackoverflow.com/questions/33332394/angular-2-typescript-cant-find-names
                    "target": "es6"
                }
            },
            production: {
                "src": "app/ng2/**/*.ts",
                "outDir": "<%= files.ng2.dist %>",
                "options": {
                    "emitDecoratorMetadata": true,
                    "module": "system",
                    "moduleResolution": "node",
                    "noImplicitAny": false,
                    "removeComments": false,
                    "sourceMap": false,
                    // using es5 is problematic with NG2-beta
                    // http://stackoverflow.com/questions/33332394/angular-2-typescript-cant-find-names
                    "target": "es6"
                }
            }
        },

        /*
        * Watch configuration
        */
        watch: {
               ng2_systemjs: {
                    "files": "systemjs.config.js",
                    "tasks": ["copy:systemjs_generated"]
                },
                // renamed & deleted files remain in place, restarting lineman run will fix it
                ng2_css: {
                    "files": "<%= files.ng2.css %>",
                    "tasks": ["copy:ng2_css_generated"]
                },
                // renamed & deleted files remain in place, restarting lineman run will fix it
                ng2_html: {
                    "files": "<%= files.ng2.html %>",
                    "tasks": ["copy:ng2_html_generated"]
                },
                // renamed & deleted files remain in place, restarting lineman run will fix it
                ng2_ts: {
                    "files": "<%= files.ng2.ts %>",
                    "tasks": ["ts:development"]
                }
        },

        /*
        * Workflow configuration
        */
        prependTasks: {
            common: lineman.config.application.prependTasks.common.concat(["ts:development"]),
            dev: ["copy:ng2_other_generated", "copy:ng2_libs_generated"].concat(lineman.config.application.prependTasks.dev),
            dist: ["copy:ng2_other_dist", "copy:ng2_libs_dist"].concat(lineman.config.application.prependTasks.dev)
        }
    };
};
<|endoftext|>


<commit_before>/* Exports a function which returns an object that overrides the default &
 *   plugin grunt configuration object.
 *
 * You can familiarize yourself with Lineman's defaults by checking out:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
 *   - https://github.com/linemanjs/lineman/blob/master/config/plugins
 *
 * You can also ask Lineman's about config from the command line:
 *
 *   $ lineman config #=> to print the entire config
 *   $ lineman config concat_sourcemap.js #=> to see the JS config for the concat task.
 */
module.exports = function(lineman) {
  //Override application configuration here. Common examples follow in the comments.
  return {

    ngtemplates: {
      options: {
        module: "ling"
      }
    },

    // If you are using Coffeescript to define the angular.module for your app,
    // you will need to swap the concat order in config/application.js such that
    // coffeescript files are included before javascript.
    concat_sourcemap: {
      js: {
        src: [
          "<%= files.js.vendor %>",
          "<%= files.coffee.generated %>",
          "<%= files.js.app %>",
          "<%= files.ngtemplates.dest %>"
        ]
      }
    }

    // API Proxying
    //
    // During development, you'll likely want to make XHR (AJAX) requests to an API on the same
    // port as your lineman development server. By enabling the API proxy and setting the port, all
    // requests for paths that don't match a static asset in ./generated will be forwarded to
    // whatever service might be running on the specified port.
    //
    // server: {
    //   apiProxy: {
    //     enabled: true,
    //     host: 'localhost',
    //     port: 3000
    //   }
    // }

    // Sass
    //
    // Lineman supports Sass via grunt-contrib-sass, which requires you first
    // have Ruby installed as well as the `sass` gem. To enable it, comment out the
    // following line:
    //
    // enableSass: true

    // Asset Fingerprints
    //
    // Lineman can fingerprint your static assets by appending a hash to the filename
    // and logging a manifest of logical-to-hashed filenames in dist/assets.json
    // via grunt-asset-fingerprint
    //
    // enableAssetFingerprint: true

    // LiveReload
    //
    // Lineman can LiveReload browsers whenever a file is changed that results in
    // assets to be processed, preventing the need to hit F5/Cmd-R every time you
    // make a change in each browser you're working against. To enable LiveReload,
    // comment out the following line:
    //
    // livereload: true

  };
};
<commit_msg>Enable API proxying.<commit_after>/* Exports a function which returns an object that overrides the default &
 *   plugin grunt configuration object.
 *
 * You can familiarize yourself with Lineman's defaults by checking out:
 *
 *   - https://github.com/linemanjs/lineman/blob/master/config/application.coffee
 *   - https://github.com/linemanjs/lineman/blob/master/config/plugins
 *
 * You can also ask Lineman's about config from the command line:
 *
 *   $ lineman config #=> to print the entire config
 *   $ lineman config concat_sourcemap.js #=> to see the JS config for the concat task.
 */
module.exports = function(lineman) {
  //Override application configuration here. Common examples follow in the comments.
  return {

    ngtemplates: {
      options: {
        module: "ling"
      }
    },

    // If you are using Coffeescript to define the angular.module for your app,
    // you will need to swap the concat order in config/application.js such that
    // coffeescript files are included before javascript.
    concat_sourcemap: {
      js: {
        src: [
          "<%= files.js.vendor %>",
          "<%= files.coffee.generated %>",
          "<%= files.js.app %>",
          "<%= files.ngtemplates.dest %>"
        ]
      }
    },

    // API Proxying
    //
    // During development, you'll likely want to make XHR (AJAX) requests to an API on the same
    // port as your lineman development server. By enabling the API proxy and setting the port, all
    // requests for paths that don't match a static asset in ./generated will be forwarded to
    // whatever service might be running on the specified port.
    //
    server: {
      apiProxy: {
        enabled: true,
        host: 'localhost',
        port: 3000
      }
    }

    // Sass
    //
    // Lineman supports Sass via grunt-contrib-sass, which requires you first
    // have Ruby installed as well as the `sass` gem. To enable it, comment out the
    // following line:
    //
    // enableSass: true

    // Asset Fingerprints
    //
    // Lineman can fingerprint your static assets by appending a hash to the filename
    // and logging a manifest of logical-to-hashed filenames in dist/assets.json
    // via grunt-asset-fingerprint
    //
    // enableAssetFingerprint: true

    // LiveReload
    //
    // Lineman can LiveReload browsers whenever a file is changed that results in
    // assets to be processed, preventing the need to hit F5/Cmd-R every time you
    // make a change in each browser you're working against. To enable LiveReload,
    // comment out the following line:
    //
    // livereload: true

  };
};
<|endoftext|>


<commit_before>const path = require('path');

const gulp = require('gulp');
const HubRegistry = require('gulp-hub');

const conf = require('./conf/gulp.conf');

// Load some files into the registry
const hub = new HubRegistry(<%- json(gulpFiles) %>);

// Tell gulp to use the tasks just loaded
gulp.registry(hub);

<% if (modules === 'inject') { -%>
gulp.task('inject', gulp.series(gulp.parallel('styles', 'scripts'), 'inject'));
<% } -%>
gulp.task('build', <%- buildTask %>);
gulp.task('test', <%- testTask %>);
gulp.task('test:auto', <%- testAutoTask %>);
gulp.task('serve', <%- serveTask %>);
gulp.task('serve:dist', gulp.series('default', 'browsersync:dist'));
gulp.task('default', gulp.series('clean', 'build'));
gulp.task('watch', watch);

function watch(done) {
<% if (modules === 'inject') { -%>
  gulp.watch([
    path.join(conf.paths.src, '**/*.html'),
    'bower.json'
  ], gulp.parallel('inject'));

<% } -%>
  gulp.watch([
<% if (css !== 'css') { -%>
    path.join(conf.paths.src, '**/*.<%- css %>'),
<% } -%>
    path.join(conf.paths.src, '**/*.css')
  ], gulp.series('styles'));

<% if (modules === 'inject') { -%>
  gulp.watch(path.join(conf.paths.src, '/app/**/*.<%- extensions.js %>'), gulp.series('inject'));

<% } else if (modules === 'systemjs') { -%>
  gulp.watch(path.join(conf.paths.src, '/app/**/*.<%- extensions.js %>'), gulp.series('scripts'));

<% } -%>
  done();
}
<commit_msg>Watch ng1 and ng2 html files for browserSync<commit_after>const path = require('path');

const gulp = require('gulp');
const HubRegistry = require('gulp-hub');
const browserSync = require('browser-sync');

const conf = require('./conf/gulp.conf');

// Load some files into the registry
const hub = new HubRegistry(<%- json(gulpFiles) %>);

// Tell gulp to use the tasks just loaded
gulp.registry(hub);

<% if (modules === 'inject') { -%>
gulp.task('inject', gulp.series(gulp.parallel('styles', 'scripts'), 'inject'));
<% } -%>
gulp.task('build', <%- buildTask %>);
gulp.task('test', <%- testTask %>);
gulp.task('test:auto', <%- testAutoTask %>);
gulp.task('serve', <%- serveTask %>);
gulp.task('serve:dist', gulp.series('default', 'browsersync:dist'));
gulp.task('default', gulp.series('clean', 'build'));
gulp.task('watch', watch);

function watch(done) {
<% if (modules === 'inject') { -%>
  gulp.watch([
    path.join(conf.paths.src, 'index.html'),
    'bower.json'
  ], gulp.parallel('inject'));

<% } -%>
<% if (framework !== 'react') { -%>
  gulp.watch(path.join(conf.paths.src, '**/*.html'), browserSync.reload);
<% } -%>
  gulp.watch([
<% if (css !== 'css') { -%>
    path.join(conf.paths.src, '**/*.<%- css %>'),
<% } -%>
    path.join(conf.paths.src, '**/*.css')
  ], gulp.series('styles'));

<% if (modules === 'inject') { -%>
  gulp.watch(path.join(conf.paths.src, '/app/**/*.<%- extensions.js %>'), gulp.series('inject'));

<% } else if (modules === 'systemjs') { -%>
  gulp.watch(path.join(conf.paths.src, '/app/**/*.<%- extensions.js %>'), gulp.series('scripts'));

<% } -%>
  done();
}
<|endoftext|>


<commit_before>'use strict'; // eslint-disable-line semi

const db = require('APP/db')
const Review = require('./review')
const Product = require('./product')
const User = require('./user')
const {expect} = require('chai')

describe('Review', () => {
  before('wait for the db', () => db.didSync)

  let user, product, review;
  before(function() {
    const userPromise = User.create({
      firstName: 'Jake',
      lastName: 'Pressman',
      email: 'jmpressman@gmail.com'
    })

    const productPromise = Product.create({
      name: 'Frankenstein',
      imageURLs: ['one', 'two'],
      price: 100.00,
      description: 'Here is a description of Frankenstein. Highly modular monster. Will stalk you to the ends of the earth. Technically his name is Frankensteins monster. Here is a description of Frankenstein. Highly modular monster. Will stalk you to the ends of the earth. Technically his name is Frankensteins monster. Here is a description of Frankenstein. Highly modular monster. Will stalk you to the ends of the earth. Technically his name is Frankensteins monster.',
      stock: 1
    })

    return Promise.all([userPromise, productPromise])
    .then(([user1, product1]) => {
      user = user1
      product = product1
    })
    .then(() => {
      return user.addProductReviews(product, { rating: 5, description: 'it was the best' });
    })
    .then(([createdReview]) => { review = createdReview[0] })
    .catch((err) => {
      console.log(err);
    })
  })

  describe('newly added review', () => {
    it('has fields we expect', () => {
      expect(review.user_id).to.equal(1)
      expect(review.product_id).to.equal(1)
      expect(review.rating).to.equal(5)
      expect(review.description).to.equal('it was the best')
    })
  })
})
<commit_msg>test(review): modified test specs<commit_after>'use strict'; // eslint-disable-line semi

const db = require('APP/db')
const Review = require('./review')
const Product = require('./product')
const User = require('./user')
const {expect} = require('chai')

describe('Review', () => {
  before('wait for the db', () => db.didSync)

  let user, product, review
  before(function() {
    const userPromise = User.create({
      firstName: 'Jake',
      lastName: 'Pressman',
      email: 'jmpressman@gmail.com'
    })

    const productPromise = Product.create({
      name: 'Frankenstein',
      imageURLs: ['one', 'two'],
      price: 100.00,
      description: 'Here is a description of Frankenstein. Highly modular monster. Will stalk you to the ends of the earth. Technically his name is Frankensteins monster. Here is a description of Frankenstein. Highly modular monster. Will stalk you to the ends of the earth. Technically his name is Frankensteins monster. Here is a description of Frankenstein. Highly modular monster. Will stalk you to the ends of the earth. Technically his name is Frankensteins monster.',
      stock: 1
    })

    return Promise.all([userPromise, productPromise])
    .then(([user1, product1]) => {
      user = user1
      product = product1
    })
    .then(() => {
      return user.addProductReviews(product, { rating: 5, description: 'it was the best' });
    })
    .then(([createdReview]) => { review = createdReview[0] })
    .catch((err) => {
      console.log(err);
    })
  })

  describe('newly added review', () => {
    it('has fields we expect', () => {
      expect(review.rating).to.equal(5)
      expect(review.description).to.equal('it was the best')
    })
  })
})
<|endoftext|>


<commit_before>'use strict';

var Promise = require('es6-promise').Promise;
var Data = require('./Data');
var log = require('./Log');
var sounds = [];
var current = null;
var playingEnabled = true;
var audioFile = null;
var context;
var playingAllSounds = false;

var playSoundFromBuffer = function(arrayBuffer, callback) {
    var sound = context.createBufferSource();
    return context.decodeAudioData(arrayBuffer, function(audioBuffer) {
        if (current !== null && current.isPaying) {
            current.stop();
        }
        sound.buffer = audioBuffer;
        sound.connect(context.destination);
        current = sound;
        sound.start();
        current.isPaying = true;
        current.onended = function() {
            this.isPaying = false;
        };
        callback(sound);
        return;
    });
};

var playSoundFromPath = function(path, callback) {
    if (audioFile !== null) {
        audioFile.pause();
        audioFile.startTime = 0;
    }
    audioFile = new Audio(path);
    audioFile.play().catch(log);

    callback(audioFile);
    return;
};

/**
 * Plays a single audio sample.
 *
 * @param index - index of the point
 */
var playSound = function(index, callback) {
    if (sounds.length > 0) {
        // using concatenated sound file
        // use a clone of the stored array buffer to avoid a detached buffer exception
        var clonedArrayBuffer = sounds[index].slice(0);
        playSoundFromBuffer(clonedArrayBuffer, callback);
    } else {
        // using original wav files
        playSoundFromPath(Data.getUrl(index), callback);
    }
};

var iterateSounds = function(soundIndexes, index) {
    if (index >= soundIndexes.length) {
        playingAllSounds = false;
        return;
    }
    if (playingEnabled) {
        playSound(soundIndexes[index], function(sound) {
            sound.onended = function() {
                iterateSounds(soundIndexes, index + 1);
            };
        });

    } else {
        // end recursion and reset flag
        playingEnabled = true;
    }
};

var doNothing = function() {
};

module.exports = {

    loadSounds: function(array) {
        sounds = array;
    },

    setContext: function(audioContext) {
        context = audioContext;
    },

    playSound: function(index) {
        if (!playingAllSounds) {
            playSound(index, doNothing);
        }
    },

    /**
     * @param {number[]} soundIndexes
     */
    playSounds: function(soundIndexes) {
        if (!playingAllSounds) {
            playingAllSounds = true;
            iterateSounds(soundIndexes, 0);
        }
    },

    stop: function() {
        if (playingEnabled && playingAllSounds) {
            playingEnabled = false;
        }
        playingAllSounds = false;
        if (current !== null && current.isPaying) {
            current.stop(0);
        }
    }
};<commit_msg>stop current audio in 100ms when starting new one<commit_after>'use strict';

var Promise = require('es6-promise').Promise;
var Data = require('./Data');
var log = require('./Log');
var sounds = [];
var current = null;
var playingEnabled = true;
var audioFile = null;
var context;
var playingAllSounds = false;

var playSoundFromBuffer = function(arrayBuffer, callback) {
    var sound = context.createBufferSource();
    return context.decodeAudioData(arrayBuffer, function(audioBuffer) {
        if (current !== null && current.isPlaying) {
            // set audio to stop 100 ms in the future
            current.stop(context.currentTime + 0.1);
        }
        sound.buffer = audioBuffer;
        sound.connect(context.destination);
        current = sound;
        sound.start();
        current.isPlaying = true;
        current.onended = function() {
            this.isPlaying = false;
        };
        callback(sound);
        return;
    });
};

var playSoundFromPath = function(path, callback) {
    if (audioFile !== null) {
        audioFile.pause();
        audioFile.startTime = 0;
    }
    audioFile = new Audio(path);
    audioFile.play().catch(log);
    audioFile.isPlaying = true;
    audioFile.onended = function() {
        this.isPlaying = false;
    };

    callback(audioFile);
    return;
};

/**
 * Plays a single audio sample.
 *
 * @param index - index of the point
 */
var playSound = function(index, callback) {
    if (sounds.length > 0) {
        // using concatenated sound file
        // use a clone of the stored array buffer to avoid a detached buffer exception
        var clonedArrayBuffer = sounds[index].slice(0);
        playSoundFromBuffer(clonedArrayBuffer, callback);
    } else {
        // using original wav files
        playSoundFromPath(Data.getUrl(index), callback);
    }
};

var iterateSounds = function(soundIndexes, index) {
    if (index >= soundIndexes.length) {
        playingAllSounds = false;
        return;
    }
    if (playingEnabled) {
        playSound(soundIndexes[index], function(sound) {
            sound.onended = function() {
                iterateSounds(soundIndexes, index + 1);
            };
        });

    } else {
        // end recursion and reset flag
        playingEnabled = true;
    }
};

var doNothing = function() {
};

module.exports = {

    loadSounds: function(array) {
        sounds = array;
    },

    setContext: function(audioContext) {
        context = audioContext;
    },

    playSound: function(index) {
        if (!playingAllSounds) {
            playSound(index, doNothing);
        }
    },

    /**
     * @param {number[]} soundIndexes
     */
    playSounds: function(soundIndexes) {
        if (!playingAllSounds) {
            playingAllSounds = true;
            iterateSounds(soundIndexes, 0);
        }
    },

    stop: function() {
        try {
            if (playingEnabled && playingAllSounds) {
                playingEnabled = false;
            }
            playingAllSounds = false;
            if (current !== null && current.isPlaying) {
                current.stop();
            }
            if (current !== null && audioFile.isPlaying) {
                audioFile.pause();
            }
        } catch (err) {
            log(err);
        }
    }
};<|endoftext|>


<commit_before>const request = require('request');
const HttpsProxyAgent = require('https-proxy-agent');
const {proxy} = require('../configuration/env-config');
const {ic2Header} = require('../configuration/feeds-config');

const moment = require('moment');
const assign = require('lodash/assign');

const agent = new HttpsProxyAgent(proxy);

const baseOptions = {
	headers: ic2Header,
	agent: agent
};

function Basejob(params) {

	const options = params || {};

	// create a new object containing the baseOptions value and the passed-in options object
	let combinedOptions = assign({}, baseOptions, options);

	this.promise = (fulfill, reject) => {

		// this will perform a get request
		request(combinedOptions, (error, response, body) => {

			if (!error) {
				let data = {};

				// this creates a property to the empty object with name being the value of combinedOptions.name
				// ex data = { treis: {status: 200, time: 'Wednesday, November 9, 2016 10:33 AM'}}
				data[combinedOptions.name] = {
		      			status: response.statusCode,
		      			time: moment().format('llll')
		      		};

		      	// all good, resolve the promise
		      	fulfill(data);
		    } else {
		    	// something went wrong, reject the promise
		      	reject(error);
		    }
		});
	}

};

module.exports = Basejob;<commit_msg>removed proxy<commit_after>const request = require('request');
const HttpsProxyAgent = require('https-proxy-agent');
const {proxy} = require('../configuration/env-config');
const {ic2Header} = require('../configuration/feeds-config');

const moment = require('moment');
const assign = require('lodash/assign');

const agent = new HttpsProxyAgent(proxy);

const baseOptions = {
	headers: ic2Header
};

function Basejob(params) {

	const options = params || {};

	if (process.env.NODE_ENV !== 'production') {
		baseOptions = assign({}, baseOptions, {agent: agent});
	}

	// create a new object containing the baseOptions value and the passed-in options object
	let combinedOptions = assign({}, baseOptions, options);

	this.promise = (fulfill, reject) => {

		// this will perform a get request
		request(combinedOptions, (error, response, body) => {

			if (!error) {
				let data = {};

				// this creates a property to the empty object with name being the value of combinedOptions.name
				// ex data = { treis: {status: 200, time: 'Wednesday, November 9, 2016 10:33 AM'}}
				data[combinedOptions.name] = {
		      			status: response.statusCode,
		      			time: moment().format('llll')
		      		};

		      	// all good, resolve the promise
		      	fulfill(data);
		    } else {
		    	// something went wrong, reject the promise
		      	reject(error);
		    }
		});
	}

};

module.exports = Basejob;<|endoftext|>


<commit_before>///
// Dependencies
///

import React, { Component } from 'react';

import FormGroup from 'react-bootstrap/lib/FormGroup';
import ControlLabel from 'react-bootstrap/lib/ControlLabel';
import FormControl from '../forms/FormControl';

import Form from '../forms/Form';

///
// View
///

class TabsetsFormView extends Component {
	render() {
		return (
			<Form name="tabsets" className="tabsets-form">
				<FormGroup controlId="nameField">
					<ControlLabel>Name</ControlLabel>
					<FormControl
						name="name"
						type="text"
						placeholder="Tabset Name"
					/>
				</FormGroup>
				<FormGroup controlId="logoUrlField">
					<ControlLabel>Logo URL</ControlLabel>
					<FormControl
						name="logoUrl"
						type="text"
						placeholder="https://www.example.com/icon.png"
					/>
				</FormGroup>
			</Form>
		);
	}
}

export default TabsetsFormView;

<commit_msg>feat/cr34 - Applied FormImagicon to Tabsets Add<commit_after>///
// Dependencies
///

import React, { Component } from 'react';

import FormGroup from 'react-bootstrap/lib/FormGroup';
import ControlLabel from 'react-bootstrap/lib/ControlLabel';
import FormControl from '../forms/FormControl';

import Form from '../forms/Form';
import FormImagicon from '../forms/FormImagicon';

///
// View
///

class TabsetsFormView extends Component {
	render() {
		return (
			<Form name="tabsets" className="tabsets-form">

					<FormImagicon
						name="logoUrl"
						alt="Tabset Logo"
						altIcon="link"
						size="l"
					/>

					<FormGroup controlId="nameField">
						<ControlLabel>Name</ControlLabel>
						<FormControl
							name="name"
							type="text"
							placeholder="Tabset Name"
						/>
					</FormGroup>

				{this.props.children}
			</Form>
		);
	}
}

export default TabsetsFormView;

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 Kevin Decker (http://www.incaseofstairs.com/)
 * See LICENSE for license information
 */
var ImageDataUtils;

(function() {
const DEFAULT_SNAP_SCAN_RANGE = 5;

ImageDataUtils = {
    getCoords: function(offset, imageData) {
        var binWidth = imageData.width * 4;
        return {
            x: offset % binWidth,
            y: offset / binWidth | 0
        };
    },
    getOffset: function(coords, imageData) {
        return (coords.x + coords.y*imageData.width)*4;
    },
    getPixel: function(context, coord) {
        return context.getImageData(coord.x, coord.y, 1, 1).data;
    },
    getWindow: function getSnapToWindow(context, coord, windowSize) {
        var firstPixel = {x: Math.max(coord.x-windowSize, 0), y: Math.max(coord.y-windowSize, 0)};
        return {
            firstPixel: firstPixel,
            focusPixel: {x: coord.x-firstPixel.x, y: coord.y-firstPixel.y},
            imageData: context.getImageData(firstPixel.x, firstPixel.y, 2*windowSize, 2*windowSize)
        };
    },
    getLinePixels: function(context, coordStart, coordEnd) {
        // Extract the rectangle that contains our data
        var containingRect = LineUtils.containingRect(coordStart, coordEnd),
            image = context.getImageData(containingRect.x, containingRect.y, containingRect.width+1, containingRect.height+1),
            imageData = image.data;

        // Determine the properties of our line
        var len = LineUtils.distance(coordStart, coordEnd)|0;
        if (!len) {
            return;
        }

        // Create our destination image
        var line = context.createImageData(len, 1),
            lineData = line.data;

        LineUtils.walkLine(coordStart, coordEnd, function(t, coords) {
            // TODO : Examine what sort of interpolation or averaging we want to do if we have a non-integer component
            // Cast to ints
            coords.x |= 0;
            coords.y |= 0;

            var offset = ImageDataUtils.getOffset(coords, image);

            var lineOffset = t*4;
            lineData[lineOffset]   = imageData[offset];
            lineData[lineOffset+1] = imageData[offset+1];
            lineData[lineOffset+2] = imageData[offset+2];
            lineData[lineOffset+3] = imageData[offset+3];
        });

        return line;
    },
    createCanvasFromImageData: function(imageData) {
        var canvas = document.createElement("canvas");
        canvas.setAttribute("width", imageData.width);
        canvas.setAttribute("height", imageData.height);

        var context = canvas.getContext("2d");
        context.putImageData(imageData, 0, 0);

        return canvas;
    },
};
})();
<commit_msg>ImageDataUtils.getInitialSnapToTarget<commit_after>/*
 * Copyright (c) 2011 Kevin Decker (http://www.incaseofstairs.com/)
 * See LICENSE for license information
 */
var ImageDataUtils;

(function() {
const DEFAULT_SNAP_SCAN_RANGE = 10;

function sign(a, b) {
    return (a > b) ? 1 : (a < b) ? -1 : 0;
}

function getPixelIntensity(coord, imageData) {
    var testOffset = ImageDataUtils.getOffset(coord, imageData),
        data = imageData.data;
    return data[testOffset]+data[testOffset+1]+data[testOffset+2]+data[testOffset+3];
}

ImageDataUtils = {
    getCoords: function(offset, imageData) {
        var binWidth = imageData.width * 4;
        return {
            x: offset % binWidth,
            y: offset / binWidth | 0
        };
    },
    getOffset: function(coords, imageData) {
        return (coords.x + coords.y*imageData.width)*4;
    },
    getPixel: function(context, coord) {
        return context.getImageData(coord.x, coord.y, 1, 1).data;
    },
    getWindow: function getSnapToWindow(context, coord, windowSize) {
        var firstPixel = {x: Math.max(coord.x-windowSize, 0), y: Math.max(coord.y-windowSize, 0)};
        return {
            firstPixel: firstPixel,
            focusPixel: {x: coord.x-firstPixel.x, y: coord.y-firstPixel.y},
            imageData: context.getImageData(firstPixel.x, firstPixel.y, 2*windowSize, 2*windowSize)
        };
    },
    getLinePixels: function(context, coordStart, coordEnd) {
        // Extract the rectangle that contains our data
        var containingRect = LineUtils.containingRect(coordStart, coordEnd),
            image = context.getImageData(containingRect.x, containingRect.y, containingRect.width+1, containingRect.height+1),
            imageData = image.data;

        // Determine the properties of our line
        var len = LineUtils.distance(coordStart, coordEnd)|0;
        if (!len) {
            return;
        }

        // Create our destination image
        var line = context.createImageData(len, 1),
            lineData = line.data;

        LineUtils.walkLine(coordStart, coordEnd, function(t, coords) {
            // TODO : Examine what sort of interpolation or averaging we want to do if we have a non-integer component
            // Cast to ints
            coords.x |= 0;
            coords.y |= 0;

            var offset = ImageDataUtils.getOffset(coords, image);

            var lineOffset = t*4;
            lineData[lineOffset]   = imageData[offset];
            lineData[lineOffset+1] = imageData[offset+1];
            lineData[lineOffset+2] = imageData[offset+2];
            lineData[lineOffset+3] = imageData[offset+3];
        });

        return line;
    },
    getInitialSnapToTarget: function(edgeContext, coordStart, scanRange) {
        // Load the window we are concerned with right now
        var snapWindow = ImageDataUtils.getWindow(edgeContext, coordStart, scanRange || DEFAULT_SNAP_SCAN_RANGE),
            focusPixel = snapWindow.focusPixel,
            imageData = snapWindow.imageData,
            data = snapWindow.imageData.data,
            endOffset = ImageDataUtils.getOffset(focusPixel, snapWindow.imageData);

        // Setup our data tracker
        var maximum = focusPixel;
        maximum.distance = 0;
        maximum.intensity = getPixelIntensity(maximum, imageData);

        function checkPixel(coord) {
            var intensity = getPixelIntensity(coord, imageData);

            if (intensity > 256+128) {
                coord.distance = Math.max(Math.abs(coord.x-focusPixel.x), Math.abs(coord.y-focusPixel.y));
                coord.intensity = intensity;
                console.error("checkPixel: " + JSON.stringify(maximum) + " " + JSON.stringify(coord));
                if ((coord.distance-maximum.distance || maximum.intensity-coord.intensity) > 0) {
                    maximum = coord;
                }
            }
        }

        // Scan the window for any pixels that are dratically different
        var y = imageData.height;
        while (y--) {
            // Intensity here should somehow be a delta to find edges that are against transparent sections (or the edge finder needs to start examining transparency)
            checkPixel({x: focusPixel.x, y: y});
        }

        var x = imageData.width;
        while (x--) {
            checkPixel({x: x, y: focusPixel.y});
        }

        // Move the return one pixel further along the path
        maximum.x = maximum.x+sign(maximum.x, focusPixel.x)+snapWindow.firstPixel.x;
        maximum.y = maximum.y+sign(maximum.y, focusPixel.y)+snapWindow.firstPixel.y;

        return maximum;
    },
    createCanvasFromImageData: function(imageData) {
        var canvas = document.createElement("canvas");
        canvas.setAttribute("width", imageData.width);
        canvas.setAttribute("height", imageData.height);

        var context = canvas.getContext("2d");
        context.putImageData(imageData, 0, 0);

        return canvas;
    },
};
})();
<|endoftext|>


<commit_before>'use strict'

const downloadFileFromGithub = require('./download-file-from-github')
const electronInstaller = require('electron-winstaller')
const fs = require('fs-extra')
const glob = require('glob')
const os = require('os')
const path = require('path')
const spawnSync = require('./spawn-sync')

const CONFIG = require('../config')

module.exports = function (packagedAppPath, codeSign) {
  const archSuffix = process.arch === 'ia32' ? '' : '-' + process.arch
  const options = {
    appDirectory: packagedAppPath,
    authors: 'GitHub Inc.',
    iconUrl: `https://raw.githubusercontent.com/atom/atom/master/resources/app-icons/${CONFIG.channel}/atom.ico`,
    loadingGif: path.join(CONFIG.repositoryRootPath, 'resources', 'win', 'loading.gif'),
    outputDirectory: CONFIG.buildOutputPath,
    remoteReleases: `https://atom.io/api/updates${archSuffix}`,
    setupIcon: path.join(CONFIG.repositoryRootPath, 'resources', 'app-icons', CONFIG.channel, 'atom.ico')
  }

  // Remove this once an x64 version is published or atom.io is returning blank instead of 404 for RELEASES-X64
  if (process.arch === 'x64') {
    options.remoteReleases = null
  }

  const certPath = path.join(os.tmpdir(), 'win.p12')
  const signing = codeSign && process.env.WIN_P12KEY_URL

  if (signing) {
    downloadFileFromGithub(process.env.WIN_P12KEY_URL, certPath)
    var signParams = []
    signParams.push(`/f ${certPath}`) // Signing cert file
    signParams.push(`/p ${process.env.WIN_P12KEY_PASSWORD}`) // Signing cert password
    signParams.push('/fd sha256') // File digest algorithm
    signParams.push('/tr http://timestamp.digicert.com') // Time stamp server
    signParams.push('/td sha256') // Times stamp algorithm
    options.signWithParams = signParams.join(' ')
  } else {
    console.log('Skipping code-signing. Specify the --code-sign option and provide a WIN_P12KEY_URL environment variable to perform code-signing'.gray)
  }

  const cleanUp = function () {
    if (fs.existsSync(certPath)) {
      console.log(`Deleting certificate at ${certPath}`)
      fs.removeSync(certPath)
    }

    for (let nupkgPath of glob.sync(`${CONFIG.buildOutputPath}/*.nupkg`)) {
      if (!nupkgPath.includes(CONFIG.appMetadata.version)) {
        console.log(`Deleting downloaded nupkg for previous version at ${nupkgPath} to prevent it from being stored as an artifact`)
        fs.removeSync(nupkgPath)
      }
    }
  }

  // Squirrel signs its own copy of the executables but we need them for the portable ZIP
  const extractSignedExes = function() {
    if (signing) {
      for (let nupkgPath of glob.sync(`${CONFIG.buildOutputPath}/*-full.nupkg`)) {
        if (nupkgPath.includes(CONFIG.appMetadata.version)) {
          nupkgPath = path.resolve(nupkgPath) // Switch from forward-slash notation
          console.log(`Extracting signed executables from ${nupkgPath} for use in portable zip`)
          spawnSync('7z.exe', ['e', nupkgPath, 'lib\\net45\\*.exe', '-aoa', `-o${packagedAppPath}`])
          spawnSync(process.env.COMSPEC, ['/c', 'move', '/y', path.join(packagedAppPath, 'squirrel.exe'), path.join(packagedAppPath, 'update.exe')])
          return
        }
      }
    }
  }

  console.log(`Creating Windows Installer for ${packagedAppPath}`)
  return electronInstaller.createWindowsInstaller(options)
    .then(extractSignedExes, function (error) {
      console.log(`Extracting signed executables failed:\n${error}`)
      cleanUp()
    })
    .then(cleanUp, function (error) {
      console.log(`Windows installer creation failed:\n${error}`)
      cleanUp()
    })
}
<commit_msg>Switch master to new key, old key on old env vars for stable/beta<commit_after>'use strict'

const downloadFileFromGithub = require('./download-file-from-github')
const electronInstaller = require('electron-winstaller')
const fs = require('fs-extra')
const glob = require('glob')
const os = require('os')
const path = require('path')
const spawnSync = require('./spawn-sync')

const CONFIG = require('../config')

module.exports = function (packagedAppPath, codeSign) {
  const archSuffix = process.arch === 'ia32' ? '' : '-' + process.arch
  const options = {
    appDirectory: packagedAppPath,
    authors: 'GitHub Inc.',
    iconUrl: `https://raw.githubusercontent.com/atom/atom/master/resources/app-icons/${CONFIG.channel}/atom.ico`,
    loadingGif: path.join(CONFIG.repositoryRootPath, 'resources', 'win', 'loading.gif'),
    outputDirectory: CONFIG.buildOutputPath,
    remoteReleases: `https://atom.io/api/updates${archSuffix}`,
    setupIcon: path.join(CONFIG.repositoryRootPath, 'resources', 'app-icons', CONFIG.channel, 'atom.ico')
  }

  // Remove this once an x64 version is published or atom.io is returning blank instead of 404 for RELEASES-X64
  if (process.arch === 'x64') {
    options.remoteReleases = null
  }

  const certPath = path.join(os.tmpdir(), 'win.p12')
  const signing = codeSign && process.env.ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL

  if (signing) {
    downloadFileFromGithub(process.env.ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL, certPath)
    var signParams = []
    signParams.push(`/f ${certPath}`) // Signing cert file
    signParams.push(`/p ${process.env.ATOM_WIN_CODE_SIGNING_CERT_PASSWORD}`) // Signing cert password
    signParams.push('/fd sha256') // File digest algorithm
    signParams.push('/tr http://timestamp.digicert.com') // Time stamp server
    signParams.push('/td sha256') // Times stamp algorithm
    options.signWithParams = signParams.join(' ')
  } else {
    console.log('Skipping code-signing. Specify the --code-sign option and provide a ATOM_WIN_CODE_SIGNING_CERT_DOWNLOAD_URL environment variable to perform code-signing'.gray)
  }

  const cleanUp = function () {
    if (fs.existsSync(certPath)) {
      console.log(`Deleting certificate at ${certPath}`)
      fs.removeSync(certPath)
    }

    for (let nupkgPath of glob.sync(`${CONFIG.buildOutputPath}/*.nupkg`)) {
      if (!nupkgPath.includes(CONFIG.appMetadata.version)) {
        console.log(`Deleting downloaded nupkg for previous version at ${nupkgPath} to prevent it from being stored as an artifact`)
        fs.removeSync(nupkgPath)
      }
    }
  }

  // Squirrel signs its own copy of the executables but we need them for the portable ZIP
  const extractSignedExes = function() {
    if (signing) {
      for (let nupkgPath of glob.sync(`${CONFIG.buildOutputPath}/*-full.nupkg`)) {
        if (nupkgPath.includes(CONFIG.appMetadata.version)) {
          nupkgPath = path.resolve(nupkgPath) // Switch from forward-slash notation
          console.log(`Extracting signed executables from ${nupkgPath} for use in portable zip`)
          spawnSync('7z.exe', ['e', nupkgPath, 'lib\\net45\\*.exe', '-aoa', `-o${packagedAppPath}`])
          spawnSync(process.env.COMSPEC, ['/c', 'move', '/y', path.join(packagedAppPath, 'squirrel.exe'), path.join(packagedAppPath, 'update.exe')])
          return
        }
      }
    }
  }

  console.log(`Creating Windows Installer for ${packagedAppPath}`)
  return electronInstaller.createWindowsInstaller(options)
    .then(extractSignedExes, function (error) {
      console.log(`Extracting signed executables failed:\n${error}`)
      cleanUp()
    })
    .then(cleanUp, function (error) {
      console.log(`Windows installer creation failed:\n${error}`)
      cleanUp()
    })
}
<|endoftext|>