<commit_before>/**
* @class   AppBuildvolumeModel
* @extends GuiPanelModel
*/
var AppBuildvolumeModel = GuiPanelModel.extend(
{
    /**
    * Panel target id.
    *
    * @protected
    * @property target
    * @type     {String}
    * @default  'columnOne'
    */
    target: 'columnOne',

    /**
    * Panel position index.
    *
    * @protected
    * @property index
    * @type     {Integer}
    * @default  1
    */
    index: 2,

    /**
    * Model setup.
    *
    * Called by GuiModule, immediately after Module create().
    *
    * @method setup
    * @return {Mixed}
    */
    setup: function() {
        // self alias
        var self = this;

        // panel color and icon
        self.color('gray');
        self.icon('cube');

        // size
        self.size = self.module.getLocal('AppViewer3d.size', {
            x: ko.observable(200),
            y: ko.observable(200),
            z: ko.observable(200)
        });

        // texts
        self.texts = {
            floor: self.module.getText('floor'),
            grid : self.module.getText('grid'),
            axes : self.module.getText('axes'),
            box  : self.module.getText('box')
        };

        // after render
        self.afterRender = function(elements, self) {
            var $self   = $('#appbuildvolume-size input');
            self.$sizeX = $($self.get(0));
            self.$sizeY = $($self.get(1));
            self.$sizeZ = $($self.get(2));
        };

        // public events
        self.onSizeChange    = function(size) {};
        self.onToggleElement = function(name) {};

        // on size change
        self.sizeChange = function(self, event) {
            self.onSizeChange({
                x: parseInt(self.$sizeX.val()),
                y: parseInt(self.$sizeY.val()),
                z: parseInt(self.$sizeZ.val()),
            });
        };

        // toggle element
        self.toggleElement = function(self, event) {
            $(event.target).toggleClass('active');
            self.onToggleElement(event.target.value);
        };
    }

});
<commit_msg>fix local storage namespace<commit_after>/**
* @class   AppBuildvolumeModel
* @extends GuiPanelModel
*/
var AppBuildvolumeModel = GuiPanelModel.extend(
{
    /**
    * Panel target id.
    *
    * @protected
    * @property target
    * @type     {String}
    * @default  'columnOne'
    */
    target: 'columnOne',

    /**
    * Panel position index.
    *
    * @protected
    * @property index
    * @type     {Integer}
    * @default  1
    */
    index: 2,

    /**
    * Model setup.
    *
    * Called by GuiModule, immediately after Module create().
    *
    * @method setup
    * @return {Mixed}
    */
    setup: function() {
        // self alias
        var self = this;

        // panel color and icon
        self.color('gray');
        self.icon('cube');

        // size
        self.size = self.module.getLocal('size', {
            x: ko.observable(200),
            y: ko.observable(200),
            z: ko.observable(200)
        }, 'AppViewer3d');

        // texts
        self.texts = {
            floor: self.module.getText('floor'),
            grid : self.module.getText('grid'),
            axes : self.module.getText('axes'),
            box  : self.module.getText('box')
        };

        // after render
        self.afterRender = function(elements, self) {
            var $self   = $('#appbuildvolume-size input');
            self.$sizeX = $($self.get(0));
            self.$sizeY = $($self.get(1));
            self.$sizeZ = $($self.get(2));
        };

        // public events
        self.onSizeChange    = function(size) {};
        self.onToggleElement = function(name) {};

        // on size change
        self.sizeChange = function(self, event) {
            self.onSizeChange({
                x: parseInt(self.$sizeX.val()),
                y: parseInt(self.$sizeY.val()),
                z: parseInt(self.$sizeZ.val()),
            });
        };

        // toggle element
        self.toggleElement = function(self, event) {
            $(event.target).toggleClass('active');
            self.onToggleElement(event.target.value);
        };
    }

});
<|endoftext|>


<commit_before>// @flow

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { loadScript } from 'redux-scripts-manager';
import cx from 'classnames';
import { noop } from 'lodash-es';

import Spacer from 'app/components/Spacer';
import styles from './styles.styl';

type Props = {
  className: ?string,
  videoId: string,
  autoplay: boolean,
  onReady: null | () => void,
  onStateChange: null | (event: {}) => void,
  loadScript: (src: string, callbackName: string) => Promise<void>,
};

@connect(null, { loadScript })
export default class YouTube extends Component<Props, void> {
  static defaultProps = {
    autoplay: false,
    onReady: noop,
    onStateChange: noop,
  };

  componentDidMount() {
    this.props.loadScript('https://www.youtube.com/iframe_api', 'onYouTubeIframeAPIReady')
      .then(() => {
        const { videoId, autoplay } = this.props;
        this.player = new window.YT.Player(this._container, {
          videoId,
          playerVars: {
            autoplay: autoplay ? 1 : 0,
          },
          events: {
            onReady: this.onPlayerReady,
            onStateChange: this.onPlayerStateChange,
          },
        });
      });
  }

  componentDidUpdate(prevProps: Props) {
    if (!this.player) return;

    if (prevProps.videoId !== this.props.videoId) {
      const method = this.props.autoplay ? 'loadVideoById' : 'cueVideoById';
      this.player && this.player[method](this.props.videoId);
    }
  }

  componentWillUnmount() {
    this.player && this.player.destroy();
  }

  onPlayerReady = () => {
    this.props.onReady();
  };

  onPlayerStateChange = (event) => {
    this.props.onStateChange(event);
  };

  _container: ?HTMLDivElement;

  player: null | {
    loadVideoById: (videoId: string) => void,
    cueVideoById: (videoId: string) => void,
  };

  render() {
    return (

        <Spacer className={styles.spacer} ratio={16 / 9} />

 (this._container = ref)} />

    );
  }
}
<commit_msg>Fix flow issue<commit_after>// @flow

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { loadScript } from 'redux-scripts-manager';
import cx from 'classnames';
import { noop } from 'lodash-es';

import Spacer from 'app/components/Spacer';
import styles from './styles.styl';

type Props = {
  className: ?string,
  videoId: string,
  autoplay: boolean,
  onReady: () => void,
  onStateChange: (event: {}) => void,
  loadScript: (src: string, callbackName: string) => Promise<void>,
};

@connect(null, { loadScript })
export default class YouTube extends Component<Props, void> {
  static defaultProps = {
    autoplay: false,
    onReady: noop,
    onStateChange: noop,
  };

  componentDidMount() {
    this.props.loadScript('https://www.youtube.com/iframe_api', 'onYouTubeIframeAPIReady')
      .then(() => {
        const { videoId, autoplay } = this.props;
        this.player = new window.YT.Player(this._container, {
          videoId,
          playerVars: {
            autoplay: autoplay ? 1 : 0,
          },
          events: {
            onReady: this.onPlayerReady,
            onStateChange: this.onPlayerStateChange,
          },
        });
      });
  }

  componentDidUpdate(prevProps: Props) {
    if (!this.player) return;

    if (prevProps.videoId !== this.props.videoId) {
      const method = this.props.autoplay ? 'loadVideoById' : 'cueVideoById';
      this.player && this.player[method](this.props.videoId);
    }
  }

  componentWillUnmount() {
    this.player && this.player.destroy();
  }

  onPlayerReady = () => {
    this.props.onReady();
  };

  onPlayerStateChange = (event) => {
    this.props.onStateChange(event);
  };

  _container: ?HTMLDivElement;

  player: null | {
    loadVideoById: (videoId: string) => void,
    cueVideoById: (videoId: string) => void,
  };

  render() {
    return (

        <Spacer className={styles.spacer} ratio={16 / 9} />

 (this._container = ref)} />

    );
  }
}
<|endoftext|>


<commit_before>import { createSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import uniqBy from 'lodash/uniqBy';
import uniq from 'lodash/uniq';
import groupBy from 'lodash/groupBy';
import intersection from 'lodash/intersection';
import isArray from 'lodash/isArray';
import orderBy from 'lodash/orderBy';
import flatten from 'lodash/flatten';
import sumBy from 'lodash/sumBy';
import { getGhgEmissionDefaults, calculatedRatio } from 'utils/ghg-emissions';

import {
  getYColumnValue,
  getThemeConfig,
  getTooltipConfig,
  sortEmissionsByValue,
  sortLabelByAlpha,
  getColorPalette
} from 'utils/graphs';
import {
  CALCULATION_OPTIONS,
  QUANTIFICATIONS_CONFIG,
  DEFAULT_AXES_CONFIG,
  ALLOWED_SECTORS_BY_SOURCE,
  DATA_SCALE
} from 'data/constants';

// constants needed for data parsing
const BASE_COLORS = ['#25597C', '#DFE9ED'];

const options = Object.keys(CALCULATION_OPTIONS).map(
  calculationKey => CALCULATION_OPTIONS[calculationKey]
);

// meta data for selectors
const getMeta = state => state.meta || {};
const getQuantifications = state => state.quantifications || null;
const getCalculationData = state =>
  (state.calculationData && state.calculationData[state.iso]) || [];

// values from search
const getSourceSelection = state => state.search.source || null;
const getCalculationSelection = state => state.search.calculation || null;
const getVersionSelection = state => state.search.version || null;
const getFilterSelection = state => state.search.filter;

// data for the graph
const getData = state => state.data || [];

const getCountries = state => state.countries.data || null;
const getIso = state => state.iso;

const getCountryByIso = (countries = [], iso) =>
  countries.find(country => country.iso_code3 === iso);

export const getCountry = createSelector(
  [getCountries, getIso],
  getCountryByIso
);

export const getCountryName = createSelector(
  [getCountry],
  (country = {}) => country.wri_standard_name || ''
);

// Sources selectors
export const getSources = createSelector(
  getMeta,
  meta => meta.data_source || null
);
export const getVersions = createSelector(getMeta, meta => meta.gwp || null);

export const getSourceOptions = createSelector(getSources, sources => {
  if (!sources) return [];
  return sources.map(d => ({
    label: d.label,
    value: d.value,
    source: d.source
  }));
});

const parseCalculationData = createSelector([getCalculationData], data => {
  if (!data || !data.length) return null;
  return groupBy(data, 'year');
});

export const getCalculationOptions = () => options;

export const getSourceSelected = createSelector(
  [getSourceOptions, getSourceSelection],
  (sources, selected) => {
    if (!sources || !sources.length) return {};
    if (!selected) return sources[0];
    return sources.find(category => category.value === parseInt(selected, 10));
  }
);

export const getCalculationSelected = createSelector(
  [getCalculationSelection],
  selected => {
    if (!selected) return options[0];
    return options.find(calculation => calculation.value === selected);
  }
);

// Versions selectors
export const getVersionOptions = createSelector(
  [getVersions, getSources, getSourceSelected],
  (versions, sources, sourceSelected) => {
    if (!sourceSelected || !versions) return [];
    const sourceData = sources.find(d => sourceSelected.value === d.value);
    return versions.filter(filter => sourceData.gwp.indexOf(filter.value) > -1);
  }
);

export const getVersionSelected = createSelector(
  [getVersionOptions, getVersionSelection],
  (versions, selected) => {
    if (!versions || !versions.length) return null;
    if (!selected) {
      const AR4Version = versions.find(version => version.label === 'AR4');
      return AR4Version || versions[0];
    }
    return versions.find(version => version.value === parseInt(selected, 10));
  }
);

export const getAllowedSectors = createSelector(
  [getSourceSelected, getVersionSelected],
  (source, version) => {
    if (!source || !version) return null;
    if (source.label === 'UNFCCC') {
      return ALLOWED_SECTORS_BY_SOURCE[source.label][version.label];
    }
    return ALLOWED_SECTORS_BY_SOURCE[source.label];
  }
);

// Filters selector
export const getFilterOptions = createSelector(
  [getData, getMeta, getAllowedSectors],
  (data, meta, sectorsAllowed) => {
    if (!sectorsAllowed || isEmpty(data) || isEmpty(meta)) return [];
    const sectorLabels = uniq(data.map(d => d.sector));
    const filteredSelected = meta.sector.filter(
      filter =>
        sectorLabels.indexOf(filter.label) > -1 &&
        sectorsAllowed.indexOf(filter.label) > -1
    );
    return sortLabelByAlpha(filteredSelected);
  }
);

export const getFiltersSelected = createSelector(
  [getFilterOptions, getFilterSelection, getCalculationSelected],
  (filters, selected, calculation) => {
    if (!filters || !filters.length) return [];
    if (selected === '') return [];
    if (!selected || calculation.value !== 'ABSOLUTE_VALUE') return filters;
    let selectedFilters = [];
    const selectedValues = selected.split(',');
    const selectedValuesNum = selectedValues.map(d => parseInt(d, 10));
    selectedFilters = filters.filter(
      filter => selectedValuesNum.indexOf(filter.value) > -1
    );
    return selectedFilters;
  }
);

// get selector defaults
export const getSelectorDefaults = createSelector(
  [getSourceSelected, getMeta],
  (sourceSelected, meta) => {
    if (!sourceSelected || !meta || isEmpty(meta)) return null;
    return getGhgEmissionDefaults(sourceSelected.label, meta);
  }
);

// Map the data from the API
export const filterData = createSelector(
  [getData, getSourceSelected, getCalculationSelected, getFiltersSelected],
  (data, sourceSelected, calculation, filters) => {
    if (!data || !data.length) return [];
    let filteredData = sortEmissionsByValue(
      data.filter(d => filters.map(f => f.label).indexOf(d.sector.trim()) >= 0)
    );
    // If the data has the AR4 version (latest) we only want to display that data to avoid duplicates
    const hasAR4 = filteredData.some(d => d.gwp === 'AR4');
    if (hasAR4) filteredData = filteredData.filter(d => d.gwp === 'AR4');
    if (calculation.value !== 'ABSOLUTE_VALUE') {
      const dataGrouped = groupBy(
        flatten(filteredData.map(d => d.emissions)),
        'year'
      );
      const dataSummed = Object.keys(dataGrouped).map(year => ({
        year: parseInt(year, 10),
        value: sumBy(dataGrouped[year], 'value')
      }));
      const compressedData = {
        ...filteredData[0],
        sector: 'Total',
        emissions: dataSummed
      };
      return [compressedData];
    }
    return filteredData;
  }
);

export const getQuantificationsData = createSelector(
  getQuantifications,
  quantifications => {
    if (!quantifications) return [];
    const qGrouped = groupBy(quantifications, 'year');
    const qParsed = [];
    // Grouping the same year and value to concat the labels
    Object.keys(qGrouped).forEach(function (year) {
      const values = groupBy(qGrouped[year], 'value');
      Object.keys(values).forEach(function (value) {
        let valuesParsed = {};
        values[value].forEach(function (v, index) {
          if (index === 0) {
            const isRange = isArray(v.value);
            const yValue = isRange
              ? v.value.map(y => y * DATA_SCALE).sort()
              : v.value * DATA_SCALE;
            valuesParsed = {
              x: v.year,
              y: yValue,
              label: v.label,
              isRange
            };
          } else {
            valuesParsed.label += `, ${v.label}`;
          }
        });
        qParsed.push(valuesParsed);
      });
    });
    // Sort desc to avoid z-index problem in the graph
    return orderBy(qParsed, 'x', 'desc');
  }
);

export const getQuantificationsTagsConfig = createSelector(
  getQuantifications,
  quantifications => {
    if (!quantifications) return [];
    const config = [];
    const bau = quantifications.find(q => q.label === 'BAU');
    const qua = quantifications.find(
      q => q.label === 'Unconditional' || q.label === 'Conditional'
    );
    const nq = quantifications.find(q => q.label === 'No quantifiable target');
    if (bau) {
      config.push(QUANTIFICATIONS_CONFIG.bau);
    }
    if (qua) {
      config.push(QUANTIFICATIONS_CONFIG.quantified);
    }
    if (nq) {
      config.push(QUANTIFICATIONS_CONFIG.not_quantifiable);
    }
    return config;
  }
);

export const getChartData = createSelector(
  [
    filterData,
    getFiltersSelected,
    parseCalculationData,
    getCalculationSelected,
    getQuantifications
  ],
  (data, filters, calculationData, calculationSelected) => {
    if (!data || !data.length || !filters || !calculationSelected) {
      return [];
    }
    let xValues = [];
    xValues = data[0].emissions.map(d => d.year);
    if (
      calculationData &&
      calculationSelected.value !== CALCULATION_OPTIONS.ABSOLUTE_VALUE.value
    ) {
      xValues = intersection(
        xValues,
        Object.keys(calculationData || []).map(y => parseInt(y, 10))
      );
    }

    const dataParsed = xValues.map(x => {
      const yItems = {};
      data.forEach(d => {
        const yKey = getYColumnValue(d.sector);
        const yData = d.emissions.find(e => e.year === x);
        const calculationRatio = calculatedRatio(
          calculationSelected.value,
          calculationData,
          x
        );
        if (yData) {
          const scaledYData = yData.value * DATA_SCALE;
          if (yData.value) {
            yItems[yKey] = scaledYData / calculationRatio;
          }
        }
      });
      const item = {
        x,
        ...yItems
      };
      return item;
    });
    return dataParsed;
  }
);

export const getChartXDomain = createSelector([getChartData], data => {
  if (!data) return null;
  const xValues = data.map(d => d.x);
  return { x: [Math.min(...xValues), Math.max(...xValues)] };
});

// variable that caches chart elements assigned color
// to avoid element color changing when the chart is updated
let colorThemeCache = {};

export const getChartConfig = createSelector(
  [filterData, getCalculationSelected],
  (data, calculationSelected) => {
    if (!data || !data.length) return {};
    const yColumns = data.map(d => ({
      label: d.sector,
      value: getYColumnValue(d.sector)
    }));
    const yColumnsChecked = uniqBy(yColumns, 'value');
    const theme = getThemeConfig(
      yColumnsChecked,
      getColorPalette(BASE_COLORS, yColumnsChecked.length)
    );
    colorThemeCache = { ...theme, ...colorThemeCache };
    const tooltip = getTooltipConfig(yColumnsChecked);
    let unit = DEFAULT_AXES_CONFIG.yLeft.unit;
    if (calculationSelected.value === CALCULATION_OPTIONS.PER_GDP.value) {
      unit = `${unit}/ million $ GDP`;
    } else if (
      calculationSelected.value === CALCULATION_OPTIONS.PER_CAPITA.value
    ) {
      unit = `${unit} per capita`;
    }
    const axes = {
      ...DEFAULT_AXES_CONFIG,
      yLeft: {
        ...DEFAULT_AXES_CONFIG.yLeft,
        unit
      }
    };
    return {
      axes,
      theme: colorThemeCache,
      tooltip,
      columns: {
        x: [{ label: 'year', value: 'x' }],
        y: yColumnsChecked
      }
    };
  }
);

export default {
  getSourceOptions,
  getSourceSelected,
  getFilterOptions,
  getFiltersSelected,
  getCalculationData
};
<commit_msg>Avoid null values conversion to 0, fix z-index problem on dots labels<commit_after>import { createSelector } from 'reselect';
import isEmpty from 'lodash/isEmpty';
import uniqBy from 'lodash/uniqBy';
import uniq from 'lodash/uniq';
import groupBy from 'lodash/groupBy';
import intersection from 'lodash/intersection';
import isArray from 'lodash/isArray';
import orderBy from 'lodash/orderBy';
import flatten from 'lodash/flatten';
import sumBy from 'lodash/sumBy';
import { getGhgEmissionDefaults, calculatedRatio } from 'utils/ghg-emissions';

import {
  getYColumnValue,
  getThemeConfig,
  getTooltipConfig,
  sortEmissionsByValue,
  sortLabelByAlpha,
  getColorPalette
} from 'utils/graphs';
import {
  CALCULATION_OPTIONS,
  QUANTIFICATIONS_CONFIG,
  DEFAULT_AXES_CONFIG,
  ALLOWED_SECTORS_BY_SOURCE,
  DATA_SCALE
} from 'data/constants';

// constants needed for data parsing
const BASE_COLORS = ['#25597C', '#DFE9ED'];

const options = Object.keys(CALCULATION_OPTIONS).map(
  calculationKey => CALCULATION_OPTIONS[calculationKey]
);

// meta data for selectors
const getMeta = state => state.meta || {};
const getQuantifications = state => state.quantifications || null;
const getCalculationData = state =>
  (state.calculationData && state.calculationData[state.iso]) || [];

// values from search
const getSourceSelection = state => state.search.source || null;
const getCalculationSelection = state => state.search.calculation || null;
const getVersionSelection = state => state.search.version || null;
const getFilterSelection = state => state.search.filter;

// data for the graph
const getData = state => state.data || [];

const getCountries = state => state.countries.data || null;
const getIso = state => state.iso;

const getCountryByIso = (countries = [], iso) =>
  countries.find(country => country.iso_code3 === iso);

export const getCountry = createSelector(
  [getCountries, getIso],
  getCountryByIso
);

export const getCountryName = createSelector(
  [getCountry],
  (country = {}) => country.wri_standard_name || ''
);

// Sources selectors
export const getSources = createSelector(
  getMeta,
  meta => meta.data_source || null
);
export const getVersions = createSelector(getMeta, meta => meta.gwp || null);

export const getSourceOptions = createSelector(getSources, sources => {
  if (!sources) return [];
  return sources.map(d => ({
    label: d.label,
    value: d.value,
    source: d.source
  }));
});

const parseCalculationData = createSelector([getCalculationData], data => {
  if (!data || !data.length) return null;
  return groupBy(data, 'year');
});

export const getCalculationOptions = () => options;

export const getSourceSelected = createSelector(
  [getSourceOptions, getSourceSelection],
  (sources, selected) => {
    if (!sources || !sources.length) return {};
    if (!selected) return sources[0];
    return sources.find(category => category.value === parseInt(selected, 10));
  }
);

export const getCalculationSelected = createSelector(
  [getCalculationSelection],
  selected => {
    if (!selected) return options[0];
    return options.find(calculation => calculation.value === selected);
  }
);

// Versions selectors
export const getVersionOptions = createSelector(
  [getVersions, getSources, getSourceSelected],
  (versions, sources, sourceSelected) => {
    if (!sourceSelected || !versions) return [];
    const sourceData = sources.find(d => sourceSelected.value === d.value);
    return versions.filter(filter => sourceData.gwp.indexOf(filter.value) > -1);
  }
);

export const getVersionSelected = createSelector(
  [getVersionOptions, getVersionSelection],
  (versions, selected) => {
    if (!versions || !versions.length) return null;
    if (!selected) {
      const AR4Version = versions.find(version => version.label === 'AR4');
      return AR4Version || versions[0];
    }
    return versions.find(version => version.value === parseInt(selected, 10));
  }
);

export const getAllowedSectors = createSelector(
  [getSourceSelected, getVersionSelected],
  (source, version) => {
    if (!source || !version) return null;
    if (source.label === 'UNFCCC') {
      return ALLOWED_SECTORS_BY_SOURCE[source.label][version.label];
    }
    return ALLOWED_SECTORS_BY_SOURCE[source.label];
  }
);

// Filters selector
export const getFilterOptions = createSelector(
  [getData, getMeta, getAllowedSectors],
  (data, meta, sectorsAllowed) => {
    if (!sectorsAllowed || isEmpty(data) || isEmpty(meta)) return [];
    const sectorLabels = uniq(data.map(d => d.sector));
    const filteredSelected = meta.sector.filter(
      filter =>
        sectorLabels.indexOf(filter.label) > -1 &&
        sectorsAllowed.indexOf(filter.label) > -1
    );
    return sortLabelByAlpha(filteredSelected);
  }
);

export const getFiltersSelected = createSelector(
  [getFilterOptions, getFilterSelection, getCalculationSelected],
  (filters, selected, calculation) => {
    if (!filters || !filters.length) return [];
    if (selected === '') return [];
    if (!selected || calculation.value !== 'ABSOLUTE_VALUE') return filters;
    let selectedFilters = [];
    const selectedValues = selected.split(',');
    const selectedValuesNum = selectedValues.map(d => parseInt(d, 10));
    selectedFilters = filters.filter(
      filter => selectedValuesNum.indexOf(filter.value) > -1
    );
    return selectedFilters;
  }
);

// get selector defaults
export const getSelectorDefaults = createSelector(
  [getSourceSelected, getMeta],
  (sourceSelected, meta) => {
    if (!sourceSelected || !meta || isEmpty(meta)) return null;
    return getGhgEmissionDefaults(sourceSelected.label, meta);
  }
);

// Map the data from the API
export const filterData = createSelector(
  [getData, getSourceSelected, getCalculationSelected, getFiltersSelected],
  (data, sourceSelected, calculation, filters) => {
    if (!data || !data.length) return [];
    let filteredData = sortEmissionsByValue(
      data.filter(d => filters.map(f => f.label).indexOf(d.sector.trim()) >= 0)
    );
    // If the data has the AR4 version (latest) we only want to display that data to avoid duplicates
    const hasAR4 = filteredData.some(d => d.gwp === 'AR4');
    if (hasAR4) filteredData = filteredData.filter(d => d.gwp === 'AR4');
    if (calculation.value !== 'ABSOLUTE_VALUE') {
      const dataGrouped = groupBy(
        flatten(filteredData.map(d => d.emissions)),
        'year'
      );
      const dataSummed = Object.keys(dataGrouped).map(year => ({
        year: parseInt(year, 10),
        value: sumBy(dataGrouped[year], 'value')
      }));
      const compressedData = {
        ...filteredData[0],
        sector: 'Total',
        emissions: dataSummed
      };
      return [compressedData];
    }
    return filteredData;
  }
);

export const getQuantificationsData = createSelector(
  getQuantifications,
  quantifications => {
    if (!quantifications) return [];
    const qGrouped = groupBy(quantifications, 'year');
    const qParsed = [];
    // Grouping the same year and value to concat the labels
    Object.keys(qGrouped).forEach(function (year) {
      const values = groupBy(qGrouped[year], 'value');
      Object.keys(values).forEach(function (value) {
        let valuesParsed = {};
        values[value].forEach(function (v, index) {
          if (index === 0) {
            const isRange = isArray(v.value);
            const yValue = isRange
              ? v.value.map(y => y * DATA_SCALE).sort()
              : v.value * DATA_SCALE;
            valuesParsed = {
              x: v.year,
              y: v.value ? yValue : null,
              label: v.label,
              isRange
            };
          } else {
            valuesParsed.label += `, ${v.label}`;
          }
        });
        qParsed.push(valuesParsed);
      });
    });
    // Sort desc to avoid z-index problem in the graph
    return orderBy(qParsed, 'y', 'desc');
  }
);

export const getQuantificationsTagsConfig = createSelector(
  getQuantifications,
  quantifications => {
    if (!quantifications) return [];
    const config = [];
    const bau = quantifications.find(q => q.label === 'BAU');
    const qua = quantifications.find(
      q => q.label === 'Unconditional' || q.label === 'Conditional'
    );
    const nq = quantifications.find(q => q.label === 'No quantifiable target');
    if (bau) {
      config.push(QUANTIFICATIONS_CONFIG.bau);
    }
    if (qua) {
      config.push(QUANTIFICATIONS_CONFIG.quantified);
    }
    if (nq) {
      config.push(QUANTIFICATIONS_CONFIG.not_quantifiable);
    }
    return config;
  }
);

export const getChartData = createSelector(
  [
    filterData,
    getFiltersSelected,
    parseCalculationData,
    getCalculationSelected,
    getQuantifications
  ],
  (data, filters, calculationData, calculationSelected) => {
    if (!data || !data.length || !filters || !calculationSelected) {
      return [];
    }
    let xValues = [];
    xValues = data[0].emissions.map(d => d.year);
    if (
      calculationData &&
      calculationSelected.value !== CALCULATION_OPTIONS.ABSOLUTE_VALUE.value
    ) {
      xValues = intersection(
        xValues,
        Object.keys(calculationData || []).map(y => parseInt(y, 10))
      );
    }

    const dataParsed = xValues.map(x => {
      const yItems = {};
      data.forEach(d => {
        const yKey = getYColumnValue(d.sector);
        const yData = d.emissions.find(e => e.year === x);
        const calculationRatio = calculatedRatio(
          calculationSelected.value,
          calculationData,
          x
        );
        if (yData) {
          const scaledYData = yData.value * DATA_SCALE;
          if (yData.value) {
            yItems[yKey] = scaledYData / calculationRatio;
          }
        }
      });
      const item = {
        x,
        ...yItems
      };
      return item;
    });
    return dataParsed;
  }
);

export const getChartXDomain = createSelector([getChartData], data => {
  if (!data) return null;
  const xValues = data.map(d => d.x);
  return { x: [Math.min(...xValues), Math.max(...xValues)] };
});

// variable that caches chart elements assigned color
// to avoid element color changing when the chart is updated
let colorThemeCache = {};

export const getChartConfig = createSelector(
  [filterData, getCalculationSelected],
  (data, calculationSelected) => {
    if (!data || !data.length) return {};
    const yColumns = data.map(d => ({
      label: d.sector,
      value: getYColumnValue(d.sector)
    }));
    const yColumnsChecked = uniqBy(yColumns, 'value');
    const theme = getThemeConfig(
      yColumnsChecked,
      getColorPalette(BASE_COLORS, yColumnsChecked.length)
    );
    colorThemeCache = { ...theme, ...colorThemeCache };
    const tooltip = getTooltipConfig(yColumnsChecked);
    let unit = DEFAULT_AXES_CONFIG.yLeft.unit;
    if (calculationSelected.value === CALCULATION_OPTIONS.PER_GDP.value) {
      unit = `${unit}/ million $ GDP`;
    } else if (
      calculationSelected.value === CALCULATION_OPTIONS.PER_CAPITA.value
    ) {
      unit = `${unit} per capita`;
    }
    const axes = {
      ...DEFAULT_AXES_CONFIG,
      yLeft: {
        ...DEFAULT_AXES_CONFIG.yLeft,
        unit
      }
    };
    return {
      axes,
      theme: colorThemeCache,
      tooltip,
      columns: {
        x: [{ label: 'year', value: 'x' }],
        y: yColumnsChecked
      }
    };
  }
);

export default {
  getSourceOptions,
  getSourceSelected,
  getFilterOptions,
  getFiltersSelected,
  getCalculationData
};
<|endoftext|>


<commit_before>var expect = require('chai').expect;

describe('Requester Spec: responseTimings', function () {
    var testrun,
        URL = 'http://postman-echo.com/get',
        collection = {
            item: [{
                request: {
                    url: URL,
                    method: 'GET'
                }
            }]
        };

    describe('with responseTimings: undefined', function () {
        before(function (done) {
            this.run({
                collection: collection
            }, function (err, results) {
                testrun = results;
                done(err);
            });
        });

        it('should include timing information by default', function () {
            var response = testrun.response.getCall(0).args[2];

            expect(response).to.have.property('timingStart');
            expect(response).to.have.property('timings');
            expect(response.timings).to.have.property('socket');
            expect(response.timings).to.have.property('lookup');
            expect(response.timings).to.have.property('connect');
            expect(response.timings).to.have.property('response');
            expect(response.timings).to.have.property('end');
        });
    });

    describe('with responseTimings: true', function () {
        before(function (done) {
            this.run({
                requester: {
                    responseTimings: true
                },
                collection: collection
            }, function (err, results) {
                testrun = results;
                done(err);
            });
        });

        it('should include timing information', function () {
            var response = testrun.response.getCall(0).args[2];

            expect(response).to.have.property('timingStart');
            expect(response).to.have.property('timings');
            expect(response.timings).to.have.property('socket');
            expect(response.timings).to.have.property('lookup');
            expect(response.timings).to.have.property('connect');
            expect(response.timings).to.have.property('response');
            expect(response.timings).to.have.property('end');
        });
    });

    describe('with responseTimings: false', function () {
        before(function (done) {
            this.run({
                requester: {
                    responseTimings: false
                },
                collection: collection
            }, function (err, results) {
                testrun = results;
                done(err);
            });
        });

        it('should not include timing information', function () {
            var response = testrun.response.getCall(0).args[2];

            expect(response).to.not.have.property('timingStart');
            expect(response).to.not.have.property('timings');
        });
    });
});
<commit_msg>Minor change in test file<commit_after>var expect = require('chai').expect;

describe('Requester Spec: responseTimings', function () {
    var testrun,
        URL = 'http://postman-echo.com/get',
        collection = {
            item: [{
                request: {
                    url: URL,
                    method: 'GET'
                }
            }]
        };

    describe('with responseTimings: undefined', function () {
        before(function (done) {
            this.run({
                collection: collection
            }, function (err, results) {
                testrun = results;
                done(err);
            });
        });

        it('should include timing information by default', function () {
            var response = testrun.response.getCall(0).args[2];

            expect(response).to.include.all.keys('timingStart', 'timings');
            expect(response.timings).to.be.an('object').that.have.all.keys([
                'socket',
                'lookup',
                'connect',
                'response',
                'end'
            ]);
        });
    });

    describe('with responseTimings: true', function () {
        before(function (done) {
            this.run({
                requester: {
                    responseTimings: true
                },
                collection: collection
            }, function (err, results) {
                testrun = results;
                done(err);
            });
        });

        it('should include timing information', function () {
            var response = testrun.response.getCall(0).args[2];

            expect(response).to.include.all.keys('timingStart', 'timings');
            expect(response.timings).to.be.an('object').that.have.all.keys([
                'socket',
                'lookup',
                'connect',
                'response',
                'end'
            ]);
        });
    });

    describe('with responseTimings: false', function () {
        before(function (done) {
            this.run({
                requester: {
                    responseTimings: false
                },
                collection: collection
            }, function (err, results) {
                testrun = results;
                done(err);
            });
        });

        it('should not include timing information', function () {
            var response = testrun.response.getCall(0).args[2];

            expect(response).to.not.include.all.keys('timingStart', 'timings');
        });
    });
});
<|endoftext|>


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

/**
 * External dependencies
 */
import PropTypes from 'prop-types';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { STORE_NAME as CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import { STORE_NAME as CORE_USER } from '../../../../../googlesitekit/datastore/user/constants';
import { STORE_NAME as MODULES_ANALYTICS, DATE_RANGE_OFFSET } from '../../../../analytics/datastore/constants';
import { isZeroReport } from '../../../../analytics/util/is-zero-report';
import GoogleChart from '../../../../../components/GoogleChart';
import { extractAnalyticsChartData } from '../../../util';
import PreviewBlock from '../../../../../components/PreviewBlock';
import ReportError from '../../../../../components/ReportError';
import ReportZero from '../../../../../components/ReportZero';
const { useSelect } = Data;

export default function UserCountGraph( { dimensionName, dimensionValue } ) {
	const currentEntityURL = useSelect( ( select ) => select( CORE_SITE ).getCurrentEntityURL() );
	const dateRange = useSelect( ( select ) => select( CORE_USER ).getDateRange() );
	const dateRangeDates = useSelect( ( select ) => select( CORE_USER ).getDateRangeDates( {
		compare: true,
		offsetDays: DATE_RANGE_OFFSET,
	} ) );

	const args = {
		startDate: dateRangeDates.startDate,
		endDate: dateRangeDates.endDate,
		dimensions: [ 'ga:date' ],
		metrics: [
			{
				expression: 'ga:users',
				alias: 'Users Over Time',
			},
		],
		orderby: {
			fieldName: 'ga:date',
			sortOrder: 'DESCENDING',
		},
	};

	if ( currentEntityURL ) {
		args.url = currentEntityURL;
	}

	if ( dimensionName && dimensionValue ) {
		args.dimensions.push( dimensionName );
		args.dimensionFilters = {
			[ dimensionName ]: dimensionValue,
		};
	}

	const loaded = useSelect( ( select ) => select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ args ] ) );
	const error = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ args ] ) );
	const report = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( args ) );

	if ( ! loaded ) {
		return <PreviewBlock width="100%" height="320px" shape="square" />;
	}

	if ( error ) {
		return <ReportError moduleSlug="analytics" error={ error } />;
	}

	if ( isZeroReport( report ) ) {
		return <ReportZero moduleSlug="analytics" />;
	}

	const chartData = extractAnalyticsChartData( report, 'ga:users', dateRange );

	return (

			<GoogleChart
				chartType="line"
				data={ chartData }
				options={ {
					animation: {
						startup: true,
					},
					curveType: 'function',
					height: 340,
					width: '100%',
					colors: [ '#1a73e8' ],
					chartArea: {
						height: '80%',
						width: '90%',
					},
					legend: {
						position: 'none',
					},
					hAxis: {
						backgroundColor: '#eef4fd', // rgba(26, 115, 232, 0.08) over the white background.
						format: 'MMM d',
						gridlines: {
							color: '#ffffff',
						},
						textPosition: 'out',
						textStyle: {
							color: '#616161',
							fontSize: 12,
						},
						ticks: [ new Date( dateRangeDates.startDate ), new Date( dateRangeDates.endDate ) ],
					},
					vAxes: {
						0: {
							baseline: 0,
							gridlines: {
								color: '#ffffff',
							},
							viewWindow: {
								max: 1,
								min: 0,
							},
							viewWindowMode: 'explicit',
							textPosition: 'none',
							ticks: [],
						},
						1: {
							gridlines: {
								color: '#ece9f1',
							},
							lineWidth: 3,
							minorGridlines: {
								color: '#ffffff',
							},
							minValue: 0,
							textStyle: {
								color: '#616161',
								fontSize: 12,
							},
							textPosition: 'out',
							viewWindow: {
								min: 0,
							},
						},
					},
					series: {
						0: { targetAxisIndex: 0, lineWidth: 0 },
						1: { color: '#1a73e8', lineWidth: 3, targetAxisIndex: 1 },
					},
					crosshair: {
						color: '#1a73e8',
						opacity: 0.1,
						orientation: 'vertical',
					},
				} }
			/>

	);
}

UserCountGraph.propTypes = {
	dimensionName: PropTypes.string,
	dimensionValue: PropTypes.string,
};
<commit_msg>Reduce height of loading preview block.<commit_after>
/**
 * UserCountGraph component
 *
 * Site Kit by Google, Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { STORE_NAME as CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import { STORE_NAME as CORE_USER } from '../../../../../googlesitekit/datastore/user/constants';
import { STORE_NAME as MODULES_ANALYTICS, DATE_RANGE_OFFSET } from '../../../../analytics/datastore/constants';
import { isZeroReport } from '../../../../analytics/util/is-zero-report';
import GoogleChart from '../../../../../components/GoogleChart';
import { extractAnalyticsChartData } from '../../../util';
import PreviewBlock from '../../../../../components/PreviewBlock';
import ReportError from '../../../../../components/ReportError';
import ReportZero from '../../../../../components/ReportZero';
const { useSelect } = Data;

export default function UserCountGraph( { dimensionName, dimensionValue } ) {
	const currentEntityURL = useSelect( ( select ) => select( CORE_SITE ).getCurrentEntityURL() );
	const dateRange = useSelect( ( select ) => select( CORE_USER ).getDateRange() );
	const dateRangeDates = useSelect( ( select ) => select( CORE_USER ).getDateRangeDates( {
		compare: true,
		offsetDays: DATE_RANGE_OFFSET,
	} ) );

	const args = {
		startDate: dateRangeDates.startDate,
		endDate: dateRangeDates.endDate,
		dimensions: [ 'ga:date' ],
		metrics: [
			{
				expression: 'ga:users',
				alias: 'Users Over Time',
			},
		],
		orderby: {
			fieldName: 'ga:date',
			sortOrder: 'DESCENDING',
		},
	};

	if ( currentEntityURL ) {
		args.url = currentEntityURL;
	}

	if ( dimensionName && dimensionValue ) {
		args.dimensions.push( dimensionName );
		args.dimensionFilters = {
			[ dimensionName ]: dimensionValue,
		};
	}

	const loaded = useSelect( ( select ) => select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ args ] ) );
	const error = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ args ] ) );
	const report = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( args ) );

	if ( ! loaded ) {
		return <PreviewBlock width="100%" height="300px" shape="square" />;
	}

	if ( error ) {
		return <ReportError moduleSlug="analytics" error={ error } />;
	}

	if ( isZeroReport( report ) ) {
		return <ReportZero moduleSlug="analytics" />;
	}

	const chartData = extractAnalyticsChartData( report, 'ga:users', dateRange );

	return (

			<GoogleChart
				chartType="line"
				data={ chartData }
				options={ {
					animation: {
						startup: true,
					},
					curveType: 'function',
					height: 340,
					width: '100%',
					colors: [ '#1a73e8' ],
					chartArea: {
						height: '80%',
						width: '90%',
					},
					legend: {
						position: 'none',
					},
					hAxis: {
						backgroundColor: '#eef4fd', // rgba(26, 115, 232, 0.08) over the white background.
						format: 'MMM d',
						gridlines: {
							color: '#ffffff',
						},
						textPosition: 'out',
						textStyle: {
							color: '#616161',
							fontSize: 12,
						},
						ticks: [ new Date( dateRangeDates.startDate ), new Date( dateRangeDates.endDate ) ],
					},
					vAxes: {
						0: {
							baseline: 0,
							gridlines: {
								color: '#ffffff',
							},
							viewWindow: {
								max: 1,
								min: 0,
							},
							viewWindowMode: 'explicit',
							textPosition: 'none',
							ticks: [],
						},
						1: {
							gridlines: {
								color: '#ece9f1',
							},
							lineWidth: 3,
							minorGridlines: {
								color: '#ffffff',
							},
							minValue: 0,
							textStyle: {
								color: '#616161',
								fontSize: 12,
							},
							textPosition: 'out',
							viewWindow: {
								min: 0,
							},
						},
					},
					series: {
						0: { targetAxisIndex: 0, lineWidth: 0 },
						1: { color: '#1a73e8', lineWidth: 3, targetAxisIndex: 1 },
					},
					crosshair: {
						color: '#1a73e8',
						opacity: 0.1,
						orientation: 'vertical',
					},
				} }
			/>

	);
}

UserCountGraph.propTypes = {
	dimensionName: PropTypes.string,
	dimensionValue: PropTypes.string,
};
<|endoftext|>


<commit_before>//var slackToken = process.env.HUBOT_SLACK_VERIFY_TOKEN;

module.exports = (robot) => {
  // robot.router.post('/hubot/slack-msg-callback', (req, res) => {
  //   var data = null;

  //   if(req.body.payload) {
  //     try {
  //       data = JSON.parse(req.body.payload);
  //     } catch(e) {
  //       robot.logger.error("Invalid JSON submitted to Slack message callback");
  //       //res.send(422)
  //       res.send('You supplied invalid JSON to this endpoint.');
  //       return;
  //     }
  //   } else {
  //     robot.logger.error("Non-JSON submitted to Slack message callback");
  //     //res.send(422)
  //     res.send('You supplied invalid JSON to this endpoint.');
  //     return;
  //   }

  //   if(data.token === slackToken) {
  //     robot.logger.info("Request is good");
  //   } else {
  //     robot.logger.error("Token mismatch on Slack message callback");
  //     //res.send(403)
  //     res.send('You are not authorized to use this endpoint.');
  //     return;
  //   }

  //   var handled = robot.emit(`slack:msg_action:${data.callback_id}`, data, res);
  //   if (!handled) {
  //     //res.send(500)
  //     res.send('No scripts handled the action.');
  //   }
  // });
};
<commit_msg>update slack-msg-callback.js<commit_after>//var slackToken = process.env.HUBOT_SLACK_VERIFY_TOKEN;

module.exports = function(robot)  {
  // robot.router.post('/hubot/slack-msg-callback', (req, res) => {
  //   var data = null;

  //   if(req.body.payload) {
  //     try {
  //       data = JSON.parse(req.body.payload);
  //     } catch(e) {
  //       robot.logger.error("Invalid JSON submitted to Slack message callback");
  //       //res.send(422)
  //       res.send('You supplied invalid JSON to this endpoint.');
  //       return;
  //     }
  //   } else {
  //     robot.logger.error("Non-JSON submitted to Slack message callback");
  //     //res.send(422)
  //     res.send('You supplied invalid JSON to this endpoint.');
  //     return;
  //   }

  //   if(data.token === slackToken) {
  //     robot.logger.info("Request is good");
  //   } else {
  //     robot.logger.error("Token mismatch on Slack message callback");
  //     //res.send(403)
  //     res.send('You are not authorized to use this endpoint.');
  //     return;
  //   }

  //   var handled = robot.emit(`slack:msg_action:${data.callback_id}`, data, res);
  //   if (!handled) {
  //     //res.send(500)
  //     res.send('No scripts handled the action.');
  //   }
  // });
};
<|endoftext|>


<commit_before>import Ember from 'ember';
import config from '../config/environment';

function Menu() {
    var gui = window.requireNode('nw.gui');
    var menu = new gui.Menu();

    // Commands
    var cut = new gui.MenuItem({
        label: 'Cut',
        click: function () {
            document.execCommand('cut');
        }
    });
    var copy = new gui.MenuItem({
        label: 'Copy',
        click: function () {
            document.execCommand('copy');
        }
    });
    var paste = new gui.MenuItem({
        label: 'Paste',
        click: function () {
            document.execCommand('paste');
        }
    });
    var emberInspector = new gui.MenuItem({
        label: 'Ember Inspector',
        click: function () {
            var s = document.createElement('script');
            s.src = 'http://ember-extension.s3.amazonaws.com/dist_bookmarklet/load_inspector.js';
            document.body.appendChild(s);
        }
    });

    menu.append(cut);
    menu.append(copy);
    menu.append(paste);

    if (config.environment === 'development') {
        menu.append(emberInspector);
    }

    // Mac Menu
    if (process && process.platform === 'darwin') {
        var mb = new gui.Menu({type: 'menubar'});
        mb.createMacBuiltin('Azure Storage Explorer');
        gui.Window.get().menu = mb;
    }

    return menu;
}

var contextMenu = {
    setup: function () {
        var menu = new Menu();

        Ember.$(document).on('contextmenu', function (e) {
            e.preventDefault();
            menu.popup(e.originalEvent.x, e.originalEvent.y);
        });
    }
};

export default contextMenu;
<commit_msg>Add DevTools to Context Menu<commit_after>import Ember from 'ember';
import config from '../config/environment';

function Menu() {
    var gui = window.requireNode('nw.gui');
    var menu = new gui.Menu();

    // Commands
    var cut = new gui.MenuItem({
        label: 'Cut',
        click: function () {
            document.execCommand('cut');
        }
    });
    var copy = new gui.MenuItem({
        label: 'Copy',
        click: function () {
            document.execCommand('copy');
        }
    });
    var paste = new gui.MenuItem({
        label: 'Paste',
        click: function () {
            document.execCommand('paste');
        }
    });
    var emberInspector = new gui.MenuItem({
        label: 'Ember Inspector',
        click: function () {
            var s = document.createElement('script');
            s.src = 'http://ember-extension.s3.amazonaws.com/dist_bookmarklet/load_inspector.js';
            document.body.appendChild(s);
        }
    });
    var devTools = new gui.MenuItem({
        label: 'DevTools',
        click: function () {
            require('nw.gui').Window.get().showDevTools();
        }
    });

    menu.append(cut);
    menu.append(copy);
    menu.append(paste);

    if (config.environment === 'development') {
        menu.append(emberInspector);
        menu.append(devTools);
    }

    // Mac Menu
    if (process && process.platform === 'darwin') {
        var mb = new gui.Menu({type: 'menubar'});
        mb.createMacBuiltin('Azure Storage Explorer');
        gui.Window.get().menu = mb;
    }

    return menu;
}

var contextMenu = {
    setup: function () {
        var menu = new Menu();

        Ember.$(document).on('contextmenu', function (e) {
            e.preventDefault();
            menu.popup(e.originalEvent.x, e.originalEvent.y);
        });
    }
};

export default contextMenu;
<|endoftext|>


<commit_before>define( [ "ember", "./metadata" ], function( Ember, metadata ) {

	var	nwGui       = window.nwDispatcher.requireNwGui(),
		nwWindow    = nwGui.Window.get(),

		trayIcon    = null,
		isHidden    = false,
		isMaximized = false,
		isMinimized = false,

		trayTooltip = metadata.package.config[ "display-name" ],
		trayIconImg = (function getTrayIconRes() {
			var	dpr	= window.devicePixelRatio,
				res	= process.platform !== "darwin" || dpr > 2
					? 48
					: dpr > 1
						? 32
						: 16;
			return metadata.package.config[ "tray-icon" ].replace( "{res}", res );
		})(),
		trayMenu    = (function() {
			var menu = new nwGui.Menu();

			menu.taskbar = true;
			menu.toggleVisibility = function() {
				nwWindow.toggleVisibility();
				// also toggle taskbar visiblity on click (gui_integration === both)
				if ( menu.taskbar ) {
					nwWindow.setShowInTaskbar( !isHidden );
				}
			};

			menu.append( new nwGui.MenuItem({
				label: "Toggle visibility",
				click: menu.toggleVisibility
			}));

			menu.append( new nwGui.MenuItem({
				label: "Close application",
				click: function() {
					nwWindow.close();
				}
			}));

			return menu;
		})();

	if ( /^win/.test( process.platform ) ) {
		// register AppUserModelID
		// this is required for toast notifications on windows
		// https://github.com/rogerwang/node-webkit/wiki/Notification#windows
		var shortcut = "%@\\Microsoft\\Windows\\Start Menu\\Programs\\%@.lnk".fmt(
			process.env.APPDATA,
			Ember.get( metadata, "package.config.display-name" )
		);
		nwGui.App.createShortcut( shortcut );
	}

	function removeTrayIcon() {
		if ( trayIcon ) {
			trayIcon.remove();
			trayIcon = null;
		}
	}

	window.addEventListener( "beforeunload", function() {
		// remove all listeners
		nwWindow.removeAllListeners();
		process.removeAllListeners();
		// prevent tray icons from stacking up when refreshing the page or devtools
		removeTrayIcon();
	}, false );

	nwWindow.on( "maximize",   function onMaximize()   { isMaximized = true;  } );
	nwWindow.on( "unmaximize", function onUnmaximize() { isMaximized = false; } );
	nwWindow.on( "minimize",   function onMinimize()   { isMinimized = true;  } );
	nwWindow.on( "restore",    function onRestore()    { isMinimized = false; } );

	nwWindow.toggleMaximize = function toggleMaximize( bool ) {
		if ( bool === undefined ) { bool = isMaximized; }
		nwWindow[ bool ? "unmaximize" : "maximize" ]();
	};

	nwWindow.toggleMinimize = function toggleMinimize( bool ) {
		if ( bool === undefined ) { bool = isMinimized; }
		nwWindow[ bool ? "restore" : "minimize" ]();
	};

	nwWindow.toggleVisibility = function toggleVisibility( bool ) {
		if ( bool === undefined ) { bool = isHidden; }
		nwWindow[ bool ? "show" : "hide" ]();
		isHidden = !bool;
	};

	nwWindow.setShowInTray = function setShowInTray( bool, taskbar ) {
		// always remove the tray icon...
		// we need a new click event listener in case the taskbar param has changed
		removeTrayIcon();
		if ( bool ) {
			trayIcon = new nwGui.Tray({ icon: trayIconImg });
			trayIcon.tooltip = trayTooltip;
			trayIcon.menu = trayMenu;
			trayIcon.iconsAreTemplates = false;
			trayIcon.on( "click", trayMenu.toggleVisibility );
			trayMenu.taskbar = taskbar;
		}
	};

	nwWindow.changeIntegrations = function changeIntegrations( taskbar, tray ) {
		nwWindow.setShowInTaskbar( taskbar );
		nwWindow.setShowInTray( tray, taskbar );
	};

	nwWindow.cookiesRemoveAll = function cookiesRemoveAll() {
		var Cookies = nwWindow.cookies;
		Cookies.getAll( {}, function( cookies ) {
			[].forEach.call( cookies, function( c ) {
				Cookies.remove({
					url: "http" + ( c.secure ? "s" : "" ) + "://" + c.domain + c.path,
					name: c.name
				});
			});
		});
	};

	Ember.Application.initializer({
		name: "node-webkit",

		initialize: function( container ) {
			// inject nwGui and nwWindow into all routes and controllers
			container.register( "nw:nwGui",    nwGui,    { instantiate: false } );
			container.register( "nw:nwWindow", nwWindow, { instantiate: false } );
			container.injection( "route",      "nwGui",    "nw:nwGui" );
			container.injection( "controller", "nwGui",    "nw:nwGui" );
			container.injection( "route",      "nwWindow", "nw:nwWindow" );
			container.injection( "controller", "nwWindow", "nw:nwWindow" );

			// listen for the close event and show the dialog instead of strictly shutting down
			nwWindow.on( "close", function() {
				if ( location.pathname !== "/index.html" ) {
					return this.close( true );
				}

				try {
					nwWindow.toggleVisibility( true );
					nwWindow.focus();
					container.lookup( "controller:application" ).send( "winClose" );
				} catch ( e ) {
					this.close( true );
				}
			});
		}
	});

});
<commit_msg>Don't create a startmenu shortcut on win7. see #44<commit_after>define( [ "ember", "./metadata", "utils/semver" ], function( Ember, metadata, semver ) {

	var	nwGui       = window.nwDispatcher.requireNwGui(),
		nwWindow    = nwGui.Window.get(),

		trayIcon    = null,
		isHidden    = false,
		isMaximized = false,
		isMinimized = false,

		trayTooltip = metadata.package.config[ "display-name" ],
		trayIconImg = (function getTrayIconRes() {
			var	dpr	= window.devicePixelRatio,
				res	= process.platform !== "darwin" || dpr > 2
					? 48
					: dpr > 1
						? 32
						: 16;
			return metadata.package.config[ "tray-icon" ].replace( "{res}", res );
		})(),
		trayMenu    = (function() {
			var menu = new nwGui.Menu();

			menu.taskbar = true;
			menu.toggleVisibility = function() {
				nwWindow.toggleVisibility();
				// also toggle taskbar visiblity on click (gui_integration === both)
				if ( menu.taskbar ) {
					nwWindow.setShowInTaskbar( !isHidden );
				}
			};

			menu.append( new nwGui.MenuItem({
				label: "Toggle visibility",
				click: menu.toggleVisibility
			}));

			menu.append( new nwGui.MenuItem({
				label: "Close application",
				click: function() {
					nwWindow.close();
				}
			}));

			return menu;
		})();

	var OS   = require( "os" );
	var win8 = "6.2.0";

	if (
		// check if current platform is windows
		   /^win/.test( process.platform )
		// check if windows version is >= 8
		&& semver.sort([ OS.release(), win8 ]).shift() === win8
	) {
		// register AppUserModelID
		// this is required for toast notifications on windows 8+
		// https://github.com/rogerwang/node-webkit/wiki/Notification#windows
		var shortcut = "%@\\Microsoft\\Windows\\Start Menu\\Programs\\%@.lnk".fmt(
			process.env.APPDATA,
			Ember.get( metadata, "package.config.display-name" )
		);
		nwGui.App.createShortcut( shortcut );
	}

	function removeTrayIcon() {
		if ( trayIcon ) {
			trayIcon.remove();
			trayIcon = null;
		}
	}

	window.addEventListener( "beforeunload", function() {
		// remove all listeners
		nwWindow.removeAllListeners();
		process.removeAllListeners();
		// prevent tray icons from stacking up when refreshing the page or devtools
		removeTrayIcon();
	}, false );

	nwWindow.on( "maximize",   function onMaximize()   { isMaximized = true;  } );
	nwWindow.on( "unmaximize", function onUnmaximize() { isMaximized = false; } );
	nwWindow.on( "minimize",   function onMinimize()   { isMinimized = true;  } );
	nwWindow.on( "restore",    function onRestore()    { isMinimized = false; } );

	nwWindow.toggleMaximize = function toggleMaximize( bool ) {
		if ( bool === undefined ) { bool = isMaximized; }
		nwWindow[ bool ? "unmaximize" : "maximize" ]();
	};

	nwWindow.toggleMinimize = function toggleMinimize( bool ) {
		if ( bool === undefined ) { bool = isMinimized; }
		nwWindow[ bool ? "restore" : "minimize" ]();
	};

	nwWindow.toggleVisibility = function toggleVisibility( bool ) {
		if ( bool === undefined ) { bool = isHidden; }
		nwWindow[ bool ? "show" : "hide" ]();
		isHidden = !bool;
	};

	nwWindow.setShowInTray = function setShowInTray( bool, taskbar ) {
		// always remove the tray icon...
		// we need a new click event listener in case the taskbar param has changed
		removeTrayIcon();
		if ( bool ) {
			trayIcon = new nwGui.Tray({ icon: trayIconImg });
			trayIcon.tooltip = trayTooltip;
			trayIcon.menu = trayMenu;
			trayIcon.iconsAreTemplates = false;
			trayIcon.on( "click", trayMenu.toggleVisibility );
			trayMenu.taskbar = taskbar;
		}
	};

	nwWindow.changeIntegrations = function changeIntegrations( taskbar, tray ) {
		nwWindow.setShowInTaskbar( taskbar );
		nwWindow.setShowInTray( tray, taskbar );
	};

	nwWindow.cookiesRemoveAll = function cookiesRemoveAll() {
		var Cookies = nwWindow.cookies;
		Cookies.getAll( {}, function( cookies ) {
			[].forEach.call( cookies, function( c ) {
				Cookies.remove({
					url: "http" + ( c.secure ? "s" : "" ) + "://" + c.domain + c.path,
					name: c.name
				});
			});
		});
	};

	Ember.Application.initializer({
		name: "node-webkit",

		initialize: function( container ) {
			// inject nwGui and nwWindow into all routes and controllers
			container.register( "nw:nwGui",    nwGui,    { instantiate: false } );
			container.register( "nw:nwWindow", nwWindow, { instantiate: false } );
			container.injection( "route",      "nwGui",    "nw:nwGui" );
			container.injection( "controller", "nwGui",    "nw:nwGui" );
			container.injection( "route",      "nwWindow", "nw:nwWindow" );
			container.injection( "controller", "nwWindow", "nw:nwWindow" );

			// listen for the close event and show the dialog instead of strictly shutting down
			nwWindow.on( "close", function() {
				if ( location.pathname !== "/index.html" ) {
					return this.close( true );
				}

				try {
					nwWindow.toggleVisibility( true );
					nwWindow.focus();
					container.lookup( "controller:application" ).send( "winClose" );
				} catch ( e ) {
					this.close( true );
				}
			});
		}
	});

});
<|endoftext|>


<commit_before>const assert = require('assert');
const chai = require('chai');

const app = require('../../../../src/app');

const courseService = app.service('courses');

// const testObjects = require('../helpers/testObjects')(app);

describe('course service', () => {
	it('registered the courses service', () => {
		assert.ok(courseService);
	});

	it('creates a course', () => courseService.create({
		name: 'testCourse',
		schoolId: '0000d186816abba584714c5f',
		userIds: [],
		classIds: [],
		teacherIds: [],
		ltiToolIds: [],
	})
		.then((course) => {
			chai.expect(course.name).to.equal('testCourse');
			chai.expect(course.userIds).to.have.lengthOf(0);
		}));
});
<commit_msg>test course patch permissions<commit_after>const { expect } = require('chai');

const app = require('../../../../src/app');

const courseService = app.service('courses');

const testObjects = require('../../helpers/testObjects')(app);

describe('course service', () => {
	it('registered the courses service', () => {
		expect(courseService).to.not.be.undefined;
	});

	it('creates a course', async () => {
		const course = await courseService.create({
			name: 'testCourse',
			schoolId: '0000d186816abba584714c5f',
			userIds: [],
			classIds: [],
			teacherIds: [],
			ltiToolIds: [],
		});
		expect(course.name).to.equal('testCourse');
		expect(course.userIds).to.have.lengthOf(0);
	});

	it('teacher can PATCH course', async () => {
		const teacher = await testObjects.createTestUser({ roles: ['teacher'] });
		const course = await testObjects.createTestCourse({ name: 'courseNotChanged', teacherIds: [teacher._id] });
		const params = await testObjects.generateRequestParamsFromUser(teacher);

		const result = await courseService.patch(course._id, { name: 'courseChanged' }, params);
		expect(result.name).to.equal('courseChanged');
	});

	it('substitution teacher can not PATCH course', async () => {
		try {
			const teacher = await testObjects.createTestUser({ roles: ['teacher'] });
			const course = await testObjects.createTestCourse({
				name: 'courseNotChanged', substitutionIds: [teacher._id],
			});
			const params = await testObjects.generateRequestParamsFromUser(teacher);
			await courseService.patch(course._id, { name: 'courseChanged' }, params);
			throw new Error('should have failed');
		} catch (err) {
			expect(err.message).to.not.equal('should have failed');
			expect(err.code).to.eq(403);
		}
	});

	/* it('teacher can DELETE course', async () => {
		const teacher = await testObjects.createTestUser({ roles: ['teacher'] });
		const course = await testObjects.createTestCourse({ name: 'course', teacherIds: [teacher._id] });
		const params = await testObjects.generateRequestParamsFromUser(teacher);

		const result = await courseService.remove(course._id, params);
		expect(result.name).to.equal('courseChanged');
	}); */
});
<|endoftext|>


<commit_before>// Copyright (c) 2013 The Axiom Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import AxiomError from 'axiom/core/error';

import JsFileSystem from 'axiom/fs/js_file_system';
import JsEntry from 'axiom/fs/js_entry';
import Path from 'axiom/fs/path';

import Termcap from 'axiom_shell/util/termcap';
import WashBuiltins from 'axiom_shell/exe/wash_builtins';
import environment from 'axiom_shell/environment';
import minimist from 'minimist';

/**
 * The shell read-eval-print loop.
 */
export var Shell = function(executeContext) {
  this.executeContext = executeContext;
  executeContext.onSignal.addListener(this.onSignal_.bind(this));

  this.fileSystem = environment.getServiceBinding('filesystems@axiom');

  if (!this.executeContext.getEnv('$PWD'))
    this.executeContext.setEnv('$PWD', '/');

  this.inputHistory = [];

  // The list of currently active jobs.
  this.executeContextList_ = [];

  // The job in the foreground (receives keyboard input).
  this.foregroundContext_ = null;

  this.tc_ = new Termcap();
  this.promptString_ = this.tc_.output(
      '%set-attr(FG_BOLD, FG_CYAN)wash$ %set-attr()');

  this.builtins = new WashBuiltins(this);
  this.builtinsFS = new JsFileSystem();
  this.builtinsFS.rootDirectory.install(this.builtins.callbacks);
};

/**
 * The main entrypoint when invoked as a JsExecutable.
 */
Shell.main = function(executeContext) {
  var shell = new Shell(executeContext);
  window.wash_ = shell;  // Console debugging aid.
  executeContext.ready();

  return shell.readEvalPrintLoop();
};

export default Shell.main;

Shell.prototype.absPath = function(path) {
  return Path.abs(this.executeContext.getEnv('$PWD', '/'), path);
};

Shell.prototype.findExecutable = function(path) {
  var searchList;

  var envPath = this.executeContext.getEnv('@PATH', []);
  if (path.substr(0, 1) == '/') {
    searchList = [path];
  } else {
    searchList = envPath.map(function(p) { return p + '/' + path });
  }

  var searchNextPath = function() {
    if (!searchList.length)
      return Promise.reject(new AxiomError.NotFound('path', path));

    var currentPath = searchList.shift();
    return this.fileSystem.stat(currentPath).then(
      function(statResult) {
        if (statResult.mode & Path.mode.x)
          return {absPath: currentPath, stat: statResult};

        return searchNextPath();
      }
    ).catch(function(value) {
      if (AxiomError.NotFound.test(value))
        return searchNextPath();

      return Promise.reject(value);
    });
  }.bind(this);

  return searchNextPath();
};

Shell.prototype.read = function() {
  return this.findExecutable('readline').then(
    function(result) {
      return this.executeContext.callPromise(
          this.fileSystem,
          result.absPath,
          { promptString: this.promptString_,
            inputHistory: this.inputHistory
          });
    }.bind(this)
  );
};

/**
 * Parse and evaluate a line of shell input.
 */
Shell.prototype.evaluate = function(value) {
  var str = value.trim();

  if (!str)
    return Promise.resolve();

  if (str != this.inputHistory[0])
    this.inputHistory.unshift(str);

  var ary = this.parseShellInput(str);
  return this.dispatch(ary[0], ary[1]);
};

Shell.prototype.readEvalPrint = function() {
  return this.read().then(
    function(result) {
      if (result == null) {
        // EOF from readline.
        return Promise.resolve(null);
      }

      if (typeof result != 'string') {
        return Promise.reject(new AxiomError.Runtime(
            'Unexpected type from readline: ' + (typeof value)));
      }

      return this.evaluate(result).then(
        function(value) {
          if (typeof value != 'undefined' && typeof value != 'number' &&
              value != null) {
            this.println(JSON.stringify(value, null, '  '));
          }

          return Promise.resolve(value);
        }.bind(this));
    }.bind(this)
  ).catch(
    function(error) {
      this.printErrorValue(error);
      return Promise.reject(error);
    }.bind(this)
  );
};

/**
 * Read-eval-print-loop.
 */
Shell.prototype.readEvalPrintLoop = function() {
  return this.readEvalPrint().then(
    function(value) {
      if (this.executeContext.isReadyState('READY'))
        return this.readEvalPrintLoop();

      return Promise.resolve(value);
    }.bind(this)
  ).catch(
    function(value) {
      if (this.executeContext.isReadyState('READY'))
        return this.readEvalPrintLoop();

      return Promise.reject(value);
    }.bind(this)
  );
};

Shell.prototype.parseShellInput = function(str) {
  var pos = str.indexOf(' ');
  var path, argv;
  if (pos > -1) {
    path = str.substr(0, pos);
    argv = str.substr(pos + 1).trim();
  } else {
    path = str;
    argv = null;
  }

  if (path.substr(0, 2) == './')
    path = this.executeContext.getEnv('$PWD', '/') + path.substr(2);

  return [path, argv];
};

Shell.prototype.dispatch = function(path, argv) {
  return this.builtinsFS.stat(path).then(
    function(statResult) {
      argv = this.parseArgv(statResult.argSigil, argv);
      return this.builtinsFS.binding.createContext('execute', path, argv).then(
        function(cx) {
          return this.dispatchExecuteContext(cx);
        }.bind(this));
    }.bind(this)
  ).catch(
    function(error) {
      if (!AxiomError.NotFound.test(error))
        return error;

      return this.findExecutable(path).then(
        function(result) {
          argv = this.parseArgv(result.stat.argSigil, argv);
          return this.fileSystem.createContext(
              'execute', result.absPath, argv).then(
            function(cx) {
              return this.dispatchExecuteContext(cx);
            }.bind(this));
        }.bind(this));
    }.bind(this)
  );
};

Shell.prototype.dispatchExecuteContext = function(cx) {
  this.executeContext.setCallee(cx);
  return cx.executePromise();
};

Shell.prototype.parseArgv = function(argSigil, argv) {
  if (!argv) {
    if (argSigil == '$')
      return '';

    if (argSigil == '@')
      return [];

    if (argSigil == '%')
      return {};

    return null;
  }

  if (/[\{\[\"\']/.test(argv.substr(0, 1))) {
    // argv starts with {, [, ", or '... parse it as JSON.
    try {
      return JSON.parse(argv);
    } catch (ex) {
      throw AxiomError.Runtime('Error parsing arguments: ' + ex);
    }

  } else {
    if (argSigil == '$' || argSigil == '*')
      return argv;

    if (argSigil == '@')
      return argv.split(/\s+/g);

    if (argSigil == '%')
      return minimist(argv.split(/\s+/g), {});
  }
};

Shell.prototype.printErrorValue = function(value) {
  var args = [];
  if (!(value instanceof AxiomError)) {
    if (value instanceof Error) {
      console.log('printErrorValue:', value);
      value = new AxiomError.Runtime(value.message);
    } else if (value instanceof Object) {
      value = new AxiomError.Runtime(value.toString());
    } else {
      value = new AxiomError.Runtime(JSON.stringify(value));
    }
  }

  for (var key in value.errorValue) {
    args.push(key + ': ' + JSON.stringify(value.errorValue[key]));
  }

  var str = this.tc_.output('%set-attr(FG_BOLD, FG_RED)' + value.errorName +
                            '%set-attr()');
  if (args.length)
    str += ': ' + args.join(', ');

  this.errorln(str);
};

Shell.prototype.println = function(str) {
  this.executeContext.stdout(str + '\n');
};

Shell.prototype.errorln = function(str) {
  this.executeContext.stderr(str + '\n');
};

Shell.prototype.onSignal_ = function(name) {
  console.log('Caught signal: ' + name);
  if (name == 'interrupt')
    this.readEvalPrintLoop();
};
<commit_msg>wash.js/parseArgv(): Set default argv string to ''<commit_after>// Copyright (c) 2013 The Axiom Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import AxiomError from 'axiom/core/error';

import JsFileSystem from 'axiom/fs/js_file_system';
import JsEntry from 'axiom/fs/js_entry';
import Path from 'axiom/fs/path';

import Termcap from 'axiom_shell/util/termcap';
import WashBuiltins from 'axiom_shell/exe/wash_builtins';
import environment from 'axiom_shell/environment';
import minimist from 'minimist';

/**
 * The shell read-eval-print loop.
 */
export var Shell = function(executeContext) {
  this.executeContext = executeContext;
  executeContext.onSignal.addListener(this.onSignal_.bind(this));

  this.fileSystem = environment.getServiceBinding('filesystems@axiom');

  if (!this.executeContext.getEnv('$PWD'))
    this.executeContext.setEnv('$PWD', '/');

  this.inputHistory = [];

  // The list of currently active jobs.
  this.executeContextList_ = [];

  // The job in the foreground (receives keyboard input).
  this.foregroundContext_ = null;

  this.tc_ = new Termcap();
  this.promptString_ = this.tc_.output(
      '%set-attr(FG_BOLD, FG_CYAN)wash$ %set-attr()');

  this.builtins = new WashBuiltins(this);
  this.builtinsFS = new JsFileSystem();
  this.builtinsFS.rootDirectory.install(this.builtins.callbacks);
};

/**
 * The main entrypoint when invoked as a JsExecutable.
 */
Shell.main = function(executeContext) {
  var shell = new Shell(executeContext);
  window.wash_ = shell;  // Console debugging aid.
  executeContext.ready();

  return shell.readEvalPrintLoop();
};

export default Shell.main;

Shell.prototype.absPath = function(path) {
  return Path.abs(this.executeContext.getEnv('$PWD', '/'), path);
};

Shell.prototype.findExecutable = function(path) {
  var searchList;

  var envPath = this.executeContext.getEnv('@PATH', []);
  if (path.substr(0, 1) == '/') {
    searchList = [path];
  } else {
    searchList = envPath.map(function(p) { return p + '/' + path });
  }

  var searchNextPath = function() {
    if (!searchList.length)
      return Promise.reject(new AxiomError.NotFound('path', path));

    var currentPath = searchList.shift();
    return this.fileSystem.stat(currentPath).then(
      function(statResult) {
        if (statResult.mode & Path.mode.x)
          return {absPath: currentPath, stat: statResult};

        return searchNextPath();
      }
    ).catch(function(value) {
      if (AxiomError.NotFound.test(value))
        return searchNextPath();

      return Promise.reject(value);
    });
  }.bind(this);

  return searchNextPath();
};

Shell.prototype.read = function() {
  return this.findExecutable('readline').then(
    function(result) {
      return this.executeContext.callPromise(
          this.fileSystem,
          result.absPath,
          { promptString: this.promptString_,
            inputHistory: this.inputHistory
          });
    }.bind(this)
  );
};

/**
 * Parse and evaluate a line of shell input.
 */
Shell.prototype.evaluate = function(value) {
  var str = value.trim();

  if (!str)
    return Promise.resolve();

  if (str != this.inputHistory[0])
    this.inputHistory.unshift(str);

  var ary = this.parseShellInput(str);
  return this.dispatch(ary[0], ary[1]);
};

Shell.prototype.readEvalPrint = function() {
  return this.read().then(
    function(result) {
      if (result == null) {
        // EOF from readline.
        return Promise.resolve(null);
      }

      if (typeof result != 'string') {
        return Promise.reject(new AxiomError.Runtime(
            'Unexpected type from readline: ' + (typeof value)));
      }

      return this.evaluate(result).then(
        function(value) {
          if (typeof value != 'undefined' && typeof value != 'number' &&
              value != null) {
            this.println(JSON.stringify(value, null, '  '));
          }

          return Promise.resolve(value);
        }.bind(this));
    }.bind(this)
  ).catch(
    function(error) {
      this.printErrorValue(error);
      return Promise.reject(error);
    }.bind(this)
  );
};

/**
 * Read-eval-print-loop.
 */
Shell.prototype.readEvalPrintLoop = function() {
  return this.readEvalPrint().then(
    function(value) {
      if (this.executeContext.isReadyState('READY'))
        return this.readEvalPrintLoop();

      return Promise.resolve(value);
    }.bind(this)
  ).catch(
    function(value) {
      if (this.executeContext.isReadyState('READY'))
        return this.readEvalPrintLoop();

      return Promise.reject(value);
    }.bind(this)
  );
};

Shell.prototype.parseShellInput = function(str) {
  var pos = str.indexOf(' ');
  var path, argv;
  if (pos > -1) {
    path = str.substr(0, pos);
    argv = str.substr(pos + 1).trim();
  } else {
    path = str;
    argv = null;
  }

  if (path.substr(0, 2) == './')
    path = this.executeContext.getEnv('$PWD', '/') + path.substr(2);

  return [path, argv];
};

Shell.prototype.dispatch = function(path, argv) {
  return this.builtinsFS.stat(path).then(
    function(statResult) {
      argv = this.parseArgv(statResult.argSigil, argv);
      return this.builtinsFS.binding.createContext('execute', path, argv).then(
        function(cx) {
          return this.dispatchExecuteContext(cx);
        }.bind(this));
    }.bind(this)
  ).catch(
    function(error) {
      if (!AxiomError.NotFound.test(error))
        return error;

      return this.findExecutable(path).then(
        function(result) {
          argv = this.parseArgv(result.stat.argSigil, argv);
          return this.fileSystem.createContext(
              'execute', result.absPath, argv).then(
            function(cx) {
              return this.dispatchExecuteContext(cx);
            }.bind(this));
        }.bind(this));
    }.bind(this)
  );
};

Shell.prototype.dispatchExecuteContext = function(cx) {
  this.executeContext.setCallee(cx);
  return cx.executePromise();
};

Shell.prototype.parseArgv = function(argSigil, argv) {
  if (!argv)
    argv = '';

  if (/[\{\[\"\']/.test(argv.substr(0, 1))) {
    // argv starts with {, [, ", or '... parse it as JSON.
    try {
      return JSON.parse(argv);
    } catch (ex) {
      throw AxiomError.Runtime('Error parsing arguments: ' + ex);
    }

  } else {
    if (argSigil == '$' || argSigil == '*')
      return argv;

    if (argSigil == '@')
      return argv.split(/\s+/g);

    if (argSigil == '%')
      return minimist(argv.split(/\s+/g), {});
  }
};

Shell.prototype.printErrorValue = function(value) {
  var args = [];
  if (!(value instanceof AxiomError)) {
    if (value instanceof Error) {
      console.log('printErrorValue:', value);
      value = new AxiomError.Runtime(value.message);
    } else if (value instanceof Object) {
      value = new AxiomError.Runtime(value.toString());
    } else {
      value = new AxiomError.Runtime(JSON.stringify(value));
    }
  }

  for (var key in value.errorValue) {
    args.push(key + ': ' + JSON.stringify(value.errorValue[key]));
  }

  var str = this.tc_.output('%set-attr(FG_BOLD, FG_RED)' + value.errorName +
                            '%set-attr()');
  if (args.length)
    str += ': ' + args.join(', ');

  this.errorln(str);
};

Shell.prototype.println = function(str) {
  this.executeContext.stdout(str + '\n');
};

Shell.prototype.errorln = function(str) {
  this.executeContext.stderr(str + '\n');
};

Shell.prototype.onSignal_ = function(name) {
  console.log('Caught signal: ' + name);
  if (name == 'interrupt')
    this.readEvalPrintLoop();
};
<|endoftext|>


<commit_before>module.exports = function(robot) {

    var Trello = require("node-trello");

    var key = process.env.HUBOT_TRELLO_KEY;
    var token = 'jvh';process.env.HUBOT_TRELLO_TOKEN;

    var t = new Trello(key, token);

    robot.respond(/trello account name/i, function(res_r) {

        t.get("/1/members/me", function(err, data) {
            if (err) {
                //console.log(err);
                //throw err;
                res_r.send('Error: ' + err['responseBody']);
                return false;
            };
            //res_r.send(res);
            res_r.send(data['fullName']);
        });
    })

    /*/
    /// TODO: add more functionality
    /*/
}<commit_msg>update trello-integration.js<commit_after>module.exports = function(robot) {
    'use strict'

    var slackmsg = require("./slackMsgs.js");
    var request = require('request');
    var Trello = require('node-trello');

    // auth
    var key = process.env.HUBOT_TRELLO_KEY;
    var token = process.env.HUBOT_TRELLO_TOKEN;
    var trello = new Trello(key, token);

    function sendMessageToSlackResponseURL(responseURL, JSONmessage){
      var postOptions = {
          uri: responseURL,
          method: 'POST',
          headers: {
              'Content-type': 'application/json'
          },
          json: JSONmessage
      };
      request(postOptions, (error, response, body) => {
          if (error){
              // handle errors as you see fit
          };
      })
    }

    // Associate a board with a specific Channel
    robot.hear(/trello board (.*)/i, function(res_r) {
        let board = res_r.match[1];
        // TODO!
    })

    // trello board
    robot.hear(/trello board/i, function(res_r){
        // TODO: fetch the board id from other source (env, redis or mongodb)
        let boardId = 'BE7seI7e';
        let args = {fields: "name,url,prefs"};

        trello.get("/1/board/"+boardId, args, function(err, data){
            if (err){
                res.send('Error: ' + err);
                robot.logger.error(err);
                return 0;
            }
            // else !err
            let msg = slackmsg.buttons();
            msg.attachments[0].title = `<${data.url}|${data.name}>`;
            msg.attachments[0].title_url = 'www.google.com'
            msg.attachments[0].author_name = 'Board'
            msg.attachments[0].callback_id = `trello_board`;
            msg.attachments[0].color = `${data.prefs.backgroundColor}`;

            // attach the board lists to buttons
            let joinBtn = {"name": "join", "text": "Join","type":"button", "value": "join"};
            let subBtn  = {"name": "sub", "text": "Subscribe","type":"button", "value": "sub"};
            let starBtn = {"name": "star", "text": "Star","type":"button", "value": "star"};
            let listsBtn= {"name": "lists", "text": "Lists","type":"button", "value": "lists"};
            let doneBtn = {"name": "done", "text": "Done","type":"button", "value": "done","style": "danger"};
            msg.attachments[0].actions.push(joinBtn);
            msg.attachments[0].actions.push(subBtn);
            msg.attachments[0].actions.push(starBtn);
            msg.attachments[0].actions.push(listsBtn);
            msg.attachments[0].actions.push(doneBtn);

            res_r.send(msg);
        })
    })

    /*******************************************************************/
    /*                        robot.on listeners                       */
    /*******************************************************************/

    var slackCB = 'slack:msg_action:';

    // responding to 'trello_board' interactive message
    robot.on(slackCB + 'trello_board', function(data, res){
        robot.logger.info(`robot.on: ${slackCB}trello_board`);
        let btnId = data.actions[0].value;
        let btnName = data.actions[0].name;
        let response_url = data.response_url;
        let msg;

        switch (btnId) {
          case 'join':
            break;
          case 'sub':
            break;
          case 'star':
                break;
          case 'lists':
            res.status(200).end() // best practice to respond with 200 status
            // get board info to fetch lists
            let boardId = 'BE7seI7e';
            let args = {lists:"all"};
            trello.get("1/board/"+boardId, args, function(err, data){
                if (err){
                    res.send(err);
                    robot.logger.error(err);
                    return;
                }
                // else if (!err)
                // create buttons msg
                let msg = slackmsg.buttons();
                msg.text = `*${data.name}* board`;

                msg.attachments[0].text = `Available lists`;
                msg.attachments[0].callback_id = `trello_list`;
                let listsNum = Object.keys(data.lists).length;
                for (var i=0; i<listsNum; i++){
                    // TODO change value to some id or something similar
                    let name = data.lists[i].name;
                    let id = data.lists[i].id;
                    let list = {"name": name, "text": name, "type":"button", "value": id};
                    msg.attachments[0].actions.push(list);
                }
                sendMessageToSlackResponseURL(response_url, msg);
            })
            break;
          case 'done':
            //res.status(200).end() // best practice to respond with 200 status
            msg = slackmsg.plainText();
            res.send(msg);
            //sendMessageToSlackResponseURL(response_url, msg);
            // res.send(msg);
            break;
          default:
            //Statements executed when none of the values match the value of the expression
            break;
        }
    })

    // responding to 'trello_list' interactive message
    robot.on(slackCB + 'trello_list', function(data_board, res){
        let response_url = data_board.response_url;

        res.status(200).end() // best practice to respond with 200 status
        robot.logger.info(`robot.on: ${slackCB}trello_list`);
        let listId = data_board.actions[0].value;
        let listName = data_board.actions[0].name;

        // call function to fetch list - provide list id
        let args = {cards: "all"};
        trello.get("/1/lists/"+listId, args, function(err, data){
            if (err){
                robot.logger.error(err);
                res.send(`Error: ${err}`)
                return 0;
            }
            // else !err
            // create buttons msg
            let msg = slackmsg.buttons();
            msg.text = `*${listName}* list`;
            msg.attachments[0].text = `Available Cards`;
            msg.attachments[0].callback_id = `trello_list`;

            let cardsNum = Object.keys(data.cards).length;
            robot.logger.info(`total cards: ${cardsNum}`);
            for (var i=0; i<cardsNum; i++){
                let card    = data.cards[i].name;
                let cardId  = data.cards[i].id;
                let item    = {"name": card, "text": card,"type":"button", "value": cardId};
                msg.attachments[0].actions.push(item);
            }

            // respond with information for that list
            sendMessageToSlackResponseURL(response_url, msg);
        })
    })

    /*  TODO: add more functionality */

}

    /* developer's personal notes */

    /* template */

    // robot.respond(/trello /i, function(res_r) {
    //     t.post("/1/", function(err, data){
    //         if (err){
    //             res_r.send('Error Encountered: '+ err['responseBody']);
    //         }
    //     })
    // })

/* An example of using slack's response_url. ~For future use */
/* Add this snippet inside robot.on that u want to trigger   */

    // var response_url = data.response_url;
    // var slackMsg = require('./slackMsgs');
    // var response = slackMsg.ephemeralMsg();

    // sendMessageToSlackResponseURL(response_url, response);

<|endoftext|>