<commit_before>/**
 * L is defined by the Leaflet library, see git://github.com/Leaflet/Leaflet.git for documentation
 * We extent L.Layer if it exists, L.Class otherwise. This is for backwards-compatibility with
 * Leaflet < 1.x
 */
L.HexbinLayer = (L.Layer ? L.Layer : L.Class).extend({
	includes: [ L.Mixin.Events ],

	options : {
		radius : 10,
		opacity: 0.5,
		duration: 200,
		lng: function(d) {
			return d[0];
		},
		lat: function(d) {
			return d[1];
		},
		value: function(d) {
			return d.length;
		},
		valueFloor: undefined,
		valueCeil: undefined,
		colorRange: [ '#f7fbff', '#08306b' ],

		onmouseover: undefined,
		onmouseout: undefined,
		click: undefined
	},

	initialize : function(options) {
		L.setOptions(this, options);

		this._hexLayout = d3_hexbin.hexbin()
			.radius(this.options.radius)
			.x(function(d) { return d.point[0]; })
			.y(function(d) { return d.point[1]; });

		this._data = [];
		this._colorScale = d3.scaleLinear()
			.range(this.options.colorRange)
			.clamp(true);

	},

	onAdd : function(map) {
		this._map = map;

		// Create a container for svg.
		this._initContainer();

		// Set up events
		map.on({ 'moveend': this._redraw }, this);

		// Initial draw
		this._redraw();
	},

	onRemove : function(map) {
		this._destroyContainer();

		// Remove events
		map.off({ 'moveend': this._redraw }, this);

		this._container = null;
		this._map = null;

		// Explicitly will leave the data array alone in case the layer will be shown again
		//this._data = [];
	},

	_initContainer : function() {
		// If the container is null or the overlay pane is empty, create the svg element for drawing
		if (null == this._container) {
			var overlayPane = this._map.getPanes().overlayPane;
			this._container = d3.select(overlayPane).append('svg')
				.attr('class', 'leaflet-layer leaflet-zoom-hide');
		}

	},

	_destroyContainer: function() {
		// Remove the svg element
		if (null != this._container) {
			this._container.remove();
		}
	},

	// (Re)draws the hexbin group
	_redraw : function() {
		var that = this;

		if (!that._map) {
			return;
		}

		// Generate the mapped version of the data
		var data = that._data.map(function(d) {
			var lng = that.options.lng(d);
			var lat = that.options.lat(d);

			var point = that._project([ lng, lat ]);
			return { o: d, point: point };
		});

		var zoom = this._map.getZoom();

		// Determine the bounds from the data and scale the overlay
		var padding = this.options.radius * 2;
		var bounds = this._getBounds(data);
		var width = (bounds.max[0] - bounds.min[0]) + (2 * padding),
			height = (bounds.max[1] - bounds.min[1]) + (2 * padding),
			marginTop = bounds.min[1] - padding,
			marginLeft = bounds.min[0] - padding;

		//this._hexLayout.size([ width, height ]);
		this._container
			.attr('width', width).attr('height', height)
			.style('margin-left', marginLeft + 'px')
			.style('margin-top', marginTop + 'px');

		// Select the hex group for the current zoom level. This has
		// the effect of recreating the group if the zoom level has changed
		var join = this._container.selectAll('g.hexbin')
			.data([ zoom ], function(d) { return d; });

		// enter
		var enter = join.enter().append('g')
			.attr('class', function(d) { return 'hexbin zoom-' + d; });

		// enter + update
		var enterUpdate = enter.merge(join);
		enterUpdate.attr('transform', 'translate(' + -marginLeft + ',' + -marginTop + ')');

		// exit
		join.exit().remove();

		// add the hexagons to the select
		this._createHexagons(enterUpdate, data);

	},

	_createHexagons : function(g, data) {
		var that = this;

		// Create the bins using the hexbin layout
		var bins = that._hexLayout(data);

		// Determine the extent of the values
		var extent = d3.extent(bins, function(d) {
			return that.options.value(d);
		});
		if (null == extent[0]) extent[0] = 0;
		if (null == extent[1]) extent[1] = 0;
		if (null != that.options.valueFloor) extent[0] = that.options.valueFloor;
		if (null != that.options.valueCeil) extent[1] = that.options.valueCeil;

		// Match the domain cardinality to that of the color range, to allow for a polylinear scale
		var domain = that._linearlySpace(extent[0], extent[1], that._colorScale.range().length);

		// Set the colorscale domain
		that._colorScale.domain(domain);

		// Join - Join the Hexagons to the data
		var join = g.selectAll('path.hexbin-hexagon')
			.data(bins, function(d) { return d.x + ':' + d.y; });

		// Update - set the fill and opacity on a transition (opacity is re-applied in case the enter transition was cancelled)
		join.transition().duration(that.options.duration)
			.attr('fill', function(d) { return that._colorScale(that.options.value(d)); })
			.attr('fill-opacity', that.options.opacity)
			.attr('stroke-opacity', that.options.opacity);

		// Enter - establish the path, the fill, and the initial opacity
		join.enter().append('path').attr('class', 'hexbin-hexagon')
			.attr('d', function(d) { return 'M' + d.x + ',' + d.y + that._hexLayout.hexagon(); })
			.attr('fill', function(d) { return that._colorScale(that.options.value(d)); })
			.attr('fill-opacity', 0.01)
			.attr('stroke-opacity', 0.01)
			.on('mouseover', function(d, i) {
				if(null != that.options.onmouseover) {
					that.options.onmouseover(d, this, that);
				}
			})
			.on('mouseout', function(d, i) {
				if(null != that.options.onmouseout) {
					that.options.onmouseout(d, this, that);
				}
			})
			.on('click', function(d, i) {
				if(null != that.options.onclick) {
					that.options.onclick(d, this, that);
				}
			})
			.transition().duration(that.options.duration)
			.attr('fill-opacity', that.options.opacity)
			.attr('stroke-opacity', that.options.opacity);

		// Exit
		join.exit()
			.transition().duration(that.options.duration)
			.attr('fill-opacity', 0.01)
			.attr('stroke-opacity', 0.01)
			.remove();

	},

	_project : function(coord) {
		var point = this._map.latLngToLayerPoint([ coord[1], coord[0] ]);
		return [ point.x, point.y ];
	},

	_getBounds: function(data) {
		if(null == data || data.length < 1) {
			return { min: [ 0, 0 ], max: [ 0, 0 ]};
		}

		// bounds is [[min long, min lat], [max long, max lat]]
		var bounds = [ [ 999, 999 ], [ -999, -999 ] ];

		data.forEach(function(element) {
			var x = element.point[0];
			var y = element.point[1];

			bounds[0][0] = Math.min(bounds[0][0], x);
			bounds[0][1] = Math.min(bounds[0][1], y);
			bounds[1][0] = Math.max(bounds[1][0], x);
			bounds[1][1] = Math.max(bounds[1][1], y);
		});

		return { min: bounds[0], max: bounds[1] };
	},

	_linearlySpace: function(from, to, length) {
		var arr = new Array(length);
		var step = (to - from) / Math.max(length - 1, 1);

		for (var i = 0; i < length; ++i) {
			arr[i] = from + (i * step);
		}

		return arr;
	},

	/*
	 * Setter for the data
	 */
	data: function(data) {
		this._data = (null != data)? data : [];
		this._latlngs = this._data.map(function(d) { return L.latLng(d[0], d[1]); });
		this._redraw();
		return this;
	},

	/*
	 * Getter/setter for the colorScale
	 */
	colorScale: function(colorScale) {
		if(undefined === colorScale) {
			return this._colorScale;
		}

		this._colorScale = colorScale;
		this._redraw();
		return this;
	},

	/*
	 * Getter/Setter for the value function
	 */
	value: function(valueFn) {
		if(undefined === valueFn) {
			return this.options.value;
		}

		this.options.value = valueFn;
		this._redraw();
		return this;
	},

	/*
	 * Getter/setter for the mouseover function
	 */
	onmouseover: function(mouseoverFn) {
		this.options.onmouseover = mouseoverFn;
		//this._redraw();
		return this;
	},

	/*
	 * Getter/setter for the mouseout function
	 */
	onmouseout: function(mouseoutFn) {
		this.options.onmouseout = mouseoutFn;
		//this._redraw();
		return this;
	},

	/*
	 * Getter/setter for the click function
	 */
	onclick: function(clickFn) {
		this.options.onclick = clickFn;
		//this._redraw();
		return this;
	},

	/*
	 * Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
	 */
	getLatLngs: function () {
		return this._latlngs;
	},

	/*
	 * Get path geometry as GeoJSON
	 */
	toGeoJSON: function () {
		var multi = this._latlngs[0].isArray && this._latlngs[0] instanceof Array;
		var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 1 : 0);
		return L.GeoJSON.getFeature(this, {
			type: (multi ? 'Multi' : '') + 'LineString',
			coordinates: coords
		});
	}

});

L.hexbinLayer = function(options) {
	return new L.HexbinLayer(options);
};<commit_msg>lazily evaluate latlngs array for getLatLngs and toGeoJSON functions<commit_after>/**
 * L is defined by the Leaflet library, see git://github.com/Leaflet/Leaflet.git for documentation
 * We extent L.Layer if it exists, L.Class otherwise. This is for backwards-compatibility with
 * Leaflet < 1.x
 */
L.HexbinLayer = (L.Layer ? L.Layer : L.Class).extend({
	includes: [ L.Mixin.Events ],

	options : {
		radius : 10,
		opacity: 0.5,
		duration: 200,
		lng: function(d) {
			return d[0];
		},
		lat: function(d) {
			return d[1];
		},
		value: function(d) {
			return d.length;
		},
		valueFloor: undefined,
		valueCeil: undefined,
		colorRange: [ '#f7fbff', '#08306b' ],

		onmouseover: undefined,
		onmouseout: undefined,
		click: undefined
	},

	initialize : function(options) {
		L.setOptions(this, options);

		this._hexLayout = d3_hexbin.hexbin()
			.radius(this.options.radius)
			.x(function(d) { return d.point[0]; })
			.y(function(d) { return d.point[1]; });

		this._data = [];
		this._colorScale = d3.scaleLinear()
			.range(this.options.colorRange)
			.clamp(true);

	},

	onAdd : function(map) {
		this._map = map;

		// Create a container for svg.
		this._initContainer();

		// Set up events
		map.on({ 'moveend': this._redraw }, this);

		// Initial draw
		this._redraw();
	},

	onRemove : function(map) {
		this._destroyContainer();

		// Remove events
		map.off({ 'moveend': this._redraw }, this);

		this._container = null;
		this._map = null;

		// Explicitly will leave the data array alone in case the layer will be shown again
		//this._data = [];
	},

	_initContainer : function() {
		// If the container is null or the overlay pane is empty, create the svg element for drawing
		if (null == this._container) {
			var overlayPane = this._map.getPanes().overlayPane;
			this._container = d3.select(overlayPane).append('svg')
				.attr('class', 'leaflet-layer leaflet-zoom-hide');
		}

	},

	_destroyContainer: function() {
		// Remove the svg element
		if (null != this._container) {
			this._container.remove();
		}
	},

	// (Re)draws the hexbin group
	_redraw : function() {
		var that = this;

		if (!that._map) {
			return;
		}

		// Generate the mapped version of the data
		var data = that._data.map(function(d) {
			var lng = that.options.lng(d);
			var lat = that.options.lat(d);

			var point = that._project([ lng, lat ]);
			return { o: d, point: point };
		});

		var zoom = this._map.getZoom();

		// Determine the bounds from the data and scale the overlay
		var padding = this.options.radius * 2;
		var bounds = this._getBounds(data);
		var width = (bounds.max[0] - bounds.min[0]) + (2 * padding),
			height = (bounds.max[1] - bounds.min[1]) + (2 * padding),
			marginTop = bounds.min[1] - padding,
			marginLeft = bounds.min[0] - padding;

		//this._hexLayout.size([ width, height ]);
		this._container
			.attr('width', width).attr('height', height)
			.style('margin-left', marginLeft + 'px')
			.style('margin-top', marginTop + 'px');

		// Select the hex group for the current zoom level. This has
		// the effect of recreating the group if the zoom level has changed
		var join = this._container.selectAll('g.hexbin')
			.data([ zoom ], function(d) { return d; });

		// enter
		var enter = join.enter().append('g')
			.attr('class', function(d) { return 'hexbin zoom-' + d; });

		// enter + update
		var enterUpdate = enter.merge(join);
		enterUpdate.attr('transform', 'translate(' + -marginLeft + ',' + -marginTop + ')');

		// exit
		join.exit().remove();

		// add the hexagons to the select
		this._createHexagons(enterUpdate, data);

	},

	_createHexagons : function(g, data) {
		var that = this;

		// Create the bins using the hexbin layout
		var bins = that._hexLayout(data);

		// Determine the extent of the values
		var extent = d3.extent(bins, function(d) {
			return that.options.value(d);
		});
		if (null == extent[0]) extent[0] = 0;
		if (null == extent[1]) extent[1] = 0;
		if (null != that.options.valueFloor) extent[0] = that.options.valueFloor;
		if (null != that.options.valueCeil) extent[1] = that.options.valueCeil;

		// Match the domain cardinality to that of the color range, to allow for a polylinear scale
		var domain = that._linearlySpace(extent[0], extent[1], that._colorScale.range().length);

		// Set the colorscale domain
		that._colorScale.domain(domain);

		// Join - Join the Hexagons to the data
		var join = g.selectAll('path.hexbin-hexagon')
			.data(bins, function(d) { return d.x + ':' + d.y; });

		// Update - set the fill and opacity on a transition (opacity is re-applied in case the enter transition was cancelled)
		join.transition().duration(that.options.duration)
			.attr('fill', function(d) { return that._colorScale(that.options.value(d)); })
			.attr('fill-opacity', that.options.opacity)
			.attr('stroke-opacity', that.options.opacity);

		// Enter - establish the path, the fill, and the initial opacity
		join.enter().append('path').attr('class', 'hexbin-hexagon')
			.attr('d', function(d) { return 'M' + d.x + ',' + d.y + that._hexLayout.hexagon(); })
			.attr('fill', function(d) { return that._colorScale(that.options.value(d)); })
			.attr('fill-opacity', 0.01)
			.attr('stroke-opacity', 0.01)
			.on('mouseover', function(d, i) {
				if(null != that.options.onmouseover) {
					that.options.onmouseover(d, this, that);
				}
			})
			.on('mouseout', function(d, i) {
				if(null != that.options.onmouseout) {
					that.options.onmouseout(d, this, that);
				}
			})
			.on('click', function(d, i) {
				if(null != that.options.onclick) {
					that.options.onclick(d, this, that);
				}
			})
			.transition().duration(that.options.duration)
			.attr('fill-opacity', that.options.opacity)
			.attr('stroke-opacity', that.options.opacity);

		// Exit
		join.exit()
			.transition().duration(that.options.duration)
			.attr('fill-opacity', 0.01)
			.attr('stroke-opacity', 0.01)
			.remove();

	},

	_project : function(coord) {
		var point = this._map.latLngToLayerPoint([ coord[1], coord[0] ]);
		return [ point.x, point.y ];
	},

	_getBounds: function(data) {
		if(null == data || data.length < 1) {
			return { min: [ 0, 0 ], max: [ 0, 0 ]};
		}

		// bounds is [[min long, min lat], [max long, max lat]]
		var bounds = [ [ 999, 999 ], [ -999, -999 ] ];

		data.forEach(function(element) {
			var x = element.point[0];
			var y = element.point[1];

			bounds[0][0] = Math.min(bounds[0][0], x);
			bounds[0][1] = Math.min(bounds[0][1], y);
			bounds[1][0] = Math.max(bounds[1][0], x);
			bounds[1][1] = Math.max(bounds[1][1], y);
		});

		return { min: bounds[0], max: bounds[1] };
	},

	_linearlySpace: function(from, to, length) {
		var arr = new Array(length);
		var step = (to - from) / Math.max(length - 1, 1);

		for (var i = 0; i < length; ++i) {
			arr[i] = from + (i * step);
		}

		return arr;
	},

	/*
	 * Setter for the data
	 */
	data: function(data) {
		this._data = (null != data)? data : [];
		this._redraw();
		return this;
	},

	/*
	 * Getter/setter for the colorScale
	 */
	colorScale: function(colorScale) {
		if(undefined === colorScale) {
			return this._colorScale;
		}

		this._colorScale = colorScale;
		this._redraw();
		return this;
	},

	/*
	 * Getter/Setter for the value function
	 */
	value: function(valueFn) {
		if(undefined === valueFn) {
			return this.options.value;
		}

		this.options.value = valueFn;
		this._redraw();
		return this;
	},

	/*
	 * Getter/setter for the mouseover function
	 */
	onmouseover: function(mouseoverFn) {
		this.options.onmouseover = mouseoverFn;
		//this._redraw();
		return this;
	},

	/*
	 * Getter/setter for the mouseout function
	 */
	onmouseout: function(mouseoutFn) {
		this.options.onmouseout = mouseoutFn;
		//this._redraw();
		return this;
	},

	/*
	 * Getter/setter for the click function
	 */
	onclick: function(clickFn) {
		this.options.onclick = clickFn;
		//this._redraw();
		return this;
	},

	/*
	 * Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
	 */
	getLatLngs: function () {
		return this._data.map(function(d) { return L.latLng(d[0], d[1]); });
	},

	/*
	 * Get path geometry as GeoJSON
	 */
	toGeoJSON: function () {
		var latLngs = this._data.map(function(d) { return L.latLng(d[0], d[1]); });
		var multi = latLngs[0].isArray && latLngs[0] instanceof Array;
		var coords = L.GeoJSON.latLngsToCoords(latLngs, multi ? 1 : 0);
		return L.GeoJSON.getFeature(this, {
			type: (multi ? 'Multi' : '') + 'LineString',
			coordinates: coords
		});
	}

});

L.hexbinLayer = function(options) {
	return new L.HexbinLayer(options);
};<|endoftext|>


<commit_before>var CommandManager = require('../command-manager');

CommandManager.register('alias', alias);

function alias(args, stdin, stdout, stderr) {
  var buffer = '';
  if (args.arguments.length) {
    var key = args.arguments.shift();
    var index;
    if (~(index = key.indexOf('='))) {
      var command;

      if (args.arguments.length && index === key.length - 1) {
        command = args.arguments.join(' ');
      } else {
        command = key.substr(index+1);
      }

      key = key.substr(0, index);

      if (command) {
        CommandManager.alias(key, command);
      }
    }
  } else {
    var aliases = CommandManager.alias();

    for (var i in aliases) {
      buffer += i + "='" + aliases[i] + "'"
    }
  }

  stdout(buffer);
}
<commit_msg>Fixed missing alias<commit_after>var CommandManager = require('../command-manager');

CommandManager.register('alias', alias);

function alias(args, stdin, stdout, stderr) {
  var buffer = '';
  if (args.arguments.length) {
    var key = args.arguments.shift();
    var index;
    if (~(index = key.indexOf('='))) {
      var command;

      if (args.arguments.length && index === key.length - 1) {
        command = args.arguments.join(' ');
      } else {
        command = key.substr(index+1);
      }

      key = key.substr(0, index);

      if (command) {
        CommandManager.alias(key, command);
      }
    }
  } else {
    var aliases = CommandManager.alias();

    for (var i in aliases) {
      buffer += i + "='" + aliases[i] + "'";
    }
  }

  stdout(buffer);
}
<|endoftext|>


<commit_before>import mixin from 'reactjs-mixin';
import React from 'react';
import {RouteHandler} from 'react-router';
import {StoreMixin} from 'mesosphere-shared-reactjs';

import AlertPanel from '../../components/AlertPanel';
import Breadcrumbs from '../../components/Breadcrumbs';
import DCOSStore from '../../stores/DCOSStore';
import FilterBar from '../../components/FilterBar';
import FilterHeadline from '../../components/FilterHeadline';
import Icon from '../../components/Icon';
import JobsTable from './JobsTable';
import JobFilterTypes from '../../constants/JobFilterTypes';
import JobSearchFilter from '../../components/JobSearchFilter';
import JobTree from '../../structs/JobTree';
import QueryParamsMixin from '../../mixins/QueryParamsMixin';
import SaveStateMixin from '../../mixins/SaveStateMixin';
import JobFormModal from '../../components/modals/JobFormModal';

const METHODS_TO_BIND = [
  'getHeadline',
  'handleFilterChange',
  'handleCloseJobFormModal',
  'handleOpenJobFormModal',
  'resetFilter',
  'resetFilterQueryParams'
];

var DEFAULT_FILTER_OPTIONS = {
  searchString: ''
};

let saveState_properties = Object.keys(DEFAULT_FILTER_OPTIONS);

class JobsTab extends mixin(StoreMixin, QueryParamsMixin, SaveStateMixin) {

  constructor() {
    super(...arguments);

    this.state = Object.assign({
      isJobFormModalOpen: false
    }, DEFAULT_FILTER_OPTIONS);

    this.saveState_key = 'jobsPage';
    this.saveState_properties = saveState_properties;

    this.store_listeners = [
      {name: 'dcos', events: ['change']},
      {name: 'metronome', events: ['change', 'jobCreateSuccess']}
    ];

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentDidMount() {
    super.componentDidMount();
    let {state} = this;

    Object.keys(DEFAULT_FILTER_OPTIONS).forEach((saveStateKey) => {
      const queryParams = this.getQueryParamObject();
      let saveStateValue = state[saveStateKey];
      if (saveStateValue !== queryParams[saveStateKey]) {
        this.setQueryParam(saveStateKey, saveStateValue);
      }
    });
  }

  handleCloseJobFormModal() {
    this.setState({isJobFormModalOpen: false});
  }

  handleOpenJobFormModal() {
    this.setState({isJobFormModalOpen: true});
  }

  handleFilterChange(filterValues, filterType) {
    var stateChanges = Object.assign({}, this.state);
    stateChanges[filterType] = filterValues;

    this.setState(stateChanges);
  }

  resetFilterQueryParams() {
    let router = this.context.router;
    let queryParams = router.getCurrentQuery();

    Object.values(JobFilterTypes).forEach(function (filterKey) {
      delete queryParams[filterKey];
    });

    router.transitionTo(router.getCurrentPathname(), {}, queryParams);
  }

  resetFilter() {
    var state = Object.assign({}, this.state, DEFAULT_FILTER_OPTIONS);
    this.setState(state, this.resetFilterQueryParams);
  }

  getHeadline(item, filteredJobs) {
    let {state} = this;
    let jobs = item.getItems();

    const hasFiltersApplied = Object.keys(DEFAULT_FILTER_OPTIONS)
      .some((filterKey) => {
        return state[filterKey] != null && state[filterKey].length > 0;
      });

    if (hasFiltersApplied) {
      return (
        <FilterHeadline
          inverseStyle={true}
          onReset={this.resetFilter}
          name="Jobs"
          currentLength={filteredJobs.length}
          totalLength={jobs.length} />
      );
    }

    // Breadcrumbs here
    return (
      <Breadcrumbs />
    );
  }

  getFilteredJobs(item) {
    let {searchString} = this.state;
    let jobs = item.getItems();

    if (searchString) {
      let filterProperties = Object.assign({}, item.getFilterProperties(), {
        name: function (item) {
          return item.getId();
        }
      });

      jobs = item.filterItemsByText(searchString, filterProperties).getItems();
    }
    return jobs;
  }

  getJobTreeView(item) {
    let filteredJobs = this.getFilteredJobs(item);

    return (

        {this.getHeadline(item, filteredJobs)}
        <FilterBar rightAlignLastNChildren={1}>
          <JobSearchFilter handleFilterChange={this.handleFilterChange} />
          <button className="button button-success"
            onClick={this.handleOpenJobFormModal}>
            New Job
          </button>
        </FilterBar>
        <JobsTable jobs={filteredJobs} />

    );
  }

  getAlertPanelFooter() {
    return (

        <button className="button button-stroke button-inverse"
          onClick={this.handleOpenJobFormModal}>
          Create Job
        </button>

    );
  }

  getContents(item) {
    // Render loading screen
    if (!DCOSStore.dataProcessed) {
      return (

      );
    }

    if (item instanceof JobTree && item.getItems().length > 0) {
      return this.getJobTreeView(item);
    }

    if (this.props.params.id) {
      return (
        <RouteHandler />
      );
    }

    // Render empty panel
    return (
      <AlertPanel
        title="No Jobs Created"
        footer={this.getAlertPanelFooter()}
        icon={<Icon id="pages-code" color="white" size="jumbo" />}>

          Create both one-off or scheduled jobs to perform tasks at a predefined
          interval.

      </AlertPanel>
    );
  }

  render() {
    let {id} = this.props.params;
    id = decodeURIComponent(id);

    // Find item in root tree and default to root tree if there is no match
    let item = DCOSStore.jobTree.findItemById(id) || DCOSStore.jobTree;

    return (

        {this.getContents(item)}
        <JobFormModal open={this.state.isJobFormModalOpen}
          onClose={this.handleCloseJobFormModal}/>

    );
  }
}

JobsTab.contextTypes = {
  router: React.PropTypes.func
};

module.exports = JobsTab;
<commit_msg>Fix button state on empty jobs page<commit_after>import mixin from 'reactjs-mixin';
import React from 'react';
import {RouteHandler} from 'react-router';
import {StoreMixin} from 'mesosphere-shared-reactjs';

import AlertPanel from '../../components/AlertPanel';
import Breadcrumbs from '../../components/Breadcrumbs';
import DCOSStore from '../../stores/DCOSStore';
import FilterBar from '../../components/FilterBar';
import FilterHeadline from '../../components/FilterHeadline';
import Icon from '../../components/Icon';
import JobsTable from './JobsTable';
import JobFilterTypes from '../../constants/JobFilterTypes';
import JobSearchFilter from '../../components/JobSearchFilter';
import JobTree from '../../structs/JobTree';
import QueryParamsMixin from '../../mixins/QueryParamsMixin';
import SaveStateMixin from '../../mixins/SaveStateMixin';
import JobFormModal from '../../components/modals/JobFormModal';

const METHODS_TO_BIND = [
  'getHeadline',
  'handleFilterChange',
  'handleCloseJobFormModal',
  'handleOpenJobFormModal',
  'resetFilter',
  'resetFilterQueryParams'
];

var DEFAULT_FILTER_OPTIONS = {
  searchString: ''
};

let saveState_properties = Object.keys(DEFAULT_FILTER_OPTIONS);

class JobsTab extends mixin(StoreMixin, QueryParamsMixin, SaveStateMixin) {

  constructor() {
    super(...arguments);

    this.state = Object.assign({
      isJobFormModalOpen: false
    }, DEFAULT_FILTER_OPTIONS);

    this.saveState_key = 'jobsPage';
    this.saveState_properties = saveState_properties;

    this.store_listeners = [
      {name: 'dcos', events: ['change']},
      {name: 'metronome', events: ['change', 'jobCreateSuccess']}
    ];

    METHODS_TO_BIND.forEach((method) => {
      this[method] = this[method].bind(this);
    });
  }

  componentDidMount() {
    super.componentDidMount();
    let {state} = this;

    Object.keys(DEFAULT_FILTER_OPTIONS).forEach((saveStateKey) => {
      const queryParams = this.getQueryParamObject();
      let saveStateValue = state[saveStateKey];
      if (saveStateValue !== queryParams[saveStateKey]) {
        this.setQueryParam(saveStateKey, saveStateValue);
      }
    });
  }

  handleCloseJobFormModal() {
    this.setState({isJobFormModalOpen: false});
  }

  handleOpenJobFormModal() {
    this.setState({isJobFormModalOpen: true});
  }

  handleFilterChange(filterValues, filterType) {
    var stateChanges = Object.assign({}, this.state);
    stateChanges[filterType] = filterValues;

    this.setState(stateChanges);
  }

  resetFilterQueryParams() {
    let router = this.context.router;
    let queryParams = router.getCurrentQuery();

    Object.values(JobFilterTypes).forEach(function (filterKey) {
      delete queryParams[filterKey];
    });

    router.transitionTo(router.getCurrentPathname(), {}, queryParams);
  }

  resetFilter() {
    var state = Object.assign({}, this.state, DEFAULT_FILTER_OPTIONS);
    this.setState(state, this.resetFilterQueryParams);
  }

  getHeadline(item, filteredJobs) {
    let {state} = this;
    let jobs = item.getItems();

    const hasFiltersApplied = Object.keys(DEFAULT_FILTER_OPTIONS)
      .some((filterKey) => {
        return state[filterKey] != null && state[filterKey].length > 0;
      });

    if (hasFiltersApplied) {
      return (
        <FilterHeadline
          inverseStyle={true}
          onReset={this.resetFilter}
          name="Jobs"
          currentLength={filteredJobs.length}
          totalLength={jobs.length} />
      );
    }

    // Breadcrumbs here
    return (
      <Breadcrumbs />
    );
  }

  getFilteredJobs(item) {
    let {searchString} = this.state;
    let jobs = item.getItems();

    if (searchString) {
      let filterProperties = Object.assign({}, item.getFilterProperties(), {
        name: function (item) {
          return item.getId();
        }
      });

      jobs = item.filterItemsByText(searchString, filterProperties).getItems();
    }
    return jobs;
  }

  getJobTreeView(item) {
    let filteredJobs = this.getFilteredJobs(item);

    return (

        {this.getHeadline(item, filteredJobs)}
        <FilterBar rightAlignLastNChildren={1}>
          <JobSearchFilter handleFilterChange={this.handleFilterChange} />
          <button className="button button-success"
            onClick={this.handleOpenJobFormModal}>
            New Job
          </button>
        </FilterBar>
        <JobsTable jobs={filteredJobs} />

    );
  }

  getAlertPanelFooter() {
    return (

        <button className="button button-success"
          onClick={this.handleOpenJobFormModal}>
          Create Job
        </button>

    );
  }

  getContents(item) {
    // Render loading screen
    if (!DCOSStore.dataProcessed) {
      return (

      );
    }

    if (item instanceof JobTree && item.getItems().length > 0) {
      return this.getJobTreeView(item);
    }

    if (this.props.params.id) {
      return (
        <RouteHandler />
      );
    }

    // Render empty panel
    return (
      <AlertPanel
        title="No Jobs Created"
        footer={this.getAlertPanelFooter()}
        icon={<Icon id="pages-code" color="white" size="jumbo" />}>

          Create both one-off or scheduled jobs to perform tasks at a predefined
          interval.

      </AlertPanel>
    );
  }

  render() {
    let {id} = this.props.params;
    id = decodeURIComponent(id);

    // Find item in root tree and default to root tree if there is no match
    let item = DCOSStore.jobTree.findItemById(id) || DCOSStore.jobTree;

    return (

        {this.getContents(item)}
        <JobFormModal open={this.state.isJobFormModalOpen}
          onClose={this.handleCloseJobFormModal}/>

    );
  }
}

JobsTab.contextTypes = {
  router: React.PropTypes.func
};

module.exports = JobsTab;
<|endoftext|>


<commit_before>import React from "react";

import AOIMap from "./AOIMap";
import {ImageryReview} from "./ImagerySelection";
import {OverviewReview} from "./Overview";
import {AOIReview, PlotReview} from "./PlotDesign";
import {SampleReview} from "./SampleDesign";
import SurveyCardList from "../survey/SurveyCardList";
import SurveyRulesList from "../survey/SurveyRulesList";
import SvgIcon from "../components/svg/SvgIcon";
import UserAssignmentReview from "./UserAssignmentReview";
import QAQCReview from "./QAQCReview";

import {ProjectContext} from "./constants";

export default function ReviewForm() {
    const context = React.useContext(ProjectContext);
    const renderSectionHeader = (title, step, showEditIcon) => (

                {title}

            {showEditIcon ? (
                <button
                    className="btn btn-sm btn-outline-info"
                    onClick={() => context.setContextState({designMode: "wizard", wizardStep: step})}
                    type="button"
                >
                    <SvgIcon color="white" icon="edit" size="1.1rem"/>
                </button>
            ) : null}

    );

    return (

                {renderSectionHeader("Overview", "overview", true)}
                <OverviewReview/>

                {renderSectionHeader("Collection Design", "imagery", true)}
                <AOIMap canDrag={false} context={context}/>

Imagery Selection

                        <ImageryReview/>

AOI Boundary

                        <AOIReview/>

Plot Design

                        <PlotReview/>

Sample Design

                        <SampleReview/>

                {context.designSettings?.userAssignment?.userMethod !== "none"
                    && (

User Assignment

                                <UserAssignmentReview
                                    designSettings={context.designSettings}
                                    institutionUserList={context.institutionUserList}
                                />

Quality Control

                                <QAQCReview
                                    designSettings={context.designSettings}
                                    institutionUserList={context.institutionUserList}
                                />

                    )}

                {renderSectionHeader("Survey Questions", "questions", new Set([undefined, "unpublished", "published"]).has(context.availability))}
                <SurveyCardList editMode="review"/>

                {renderSectionHeader("Survey Rules", "rules", context.availability === "unpublished")}
                <SurveyRulesList inDesignMode={false}/>

    );
}
<commit_msg>Update project status checks<commit_after>import React from "react";

import AOIMap from "./AOIMap";
import {ImageryReview} from "./ImagerySelection";
import {OverviewReview} from "./Overview";
import {AOIReview, PlotReview} from "./PlotDesign";
import {SampleReview} from "./SampleDesign";
import SurveyCardList from "../survey/SurveyCardList";
import SurveyRulesList from "../survey/SurveyRulesList";
import SvgIcon from "../components/svg/SvgIcon";
import UserAssignmentReview from "./UserAssignmentReview";
import QAQCReview from "./QAQCReview";

import {ProjectContext} from "./constants";

export default function ReviewForm() {
    const context = React.useContext(ProjectContext);
    const renderSectionHeader = (title, step, showEditIcon) => (

                {title}

            {showEditIcon ? (
                <button
                    className="btn btn-sm btn-outline-info"
                    onClick={() => context.setContextState({designMode: "wizard", wizardStep: step})}
                    type="button"
                >
                    <SvgIcon color="white" icon="edit" size="1.1rem"/>
                </button>
            ) : null}

    );

    return (

                {renderSectionHeader("Overview", "overview", true)}
                <OverviewReview/>

                {renderSectionHeader("Collection Design", "imagery", true)}
                <AOIMap canDrag={false} context={context}/>

Imagery Selection

                        <ImageryReview/>

AOI Boundary

                        <AOIReview/>

Plot Design

                        <PlotReview/>

Sample Design

                        <SampleReview/>

                {context.designSettings?.userAssignment?.userMethod !== "none"
                    && (

User Assignment

                                <UserAssignmentReview
                                    designSettings={context.designSettings}
                                    institutionUserList={context.institutionUserList}
                                />

Quality Control

                                <QAQCReview
                                    designSettings={context.designSettings}
                                    institutionUserList={context.institutionUserList}
                                />

                    )}

                {renderSectionHeader("Survey Questions", "questions", !["closed", "archived"].includes(context.availability))}
                <SurveyCardList editMode="review"/>

                {renderSectionHeader("Survey Rules", "rules", context.availability === "unpublished")}
                <SurveyRulesList inDesignMode={false}/>

    );
}
<|endoftext|>


<commit_before>/**
 * The garden of the game.
 * This is where the player uses the water from the sessions.
 */
function GardenState () {}

/* Phaser state function */
GardenState.prototype.preload = function() {
	this.load.audio('gardenSpeech', LANG.SPEECH.garden.speech); // audio sprite sheet

	this.load.atlasJSONHash('garden', 'assets/img/garden/atlas.png', 'assets/img/garden/atlas.json');

	this.gardenData = Backend.getGarden() || { fields: [] };
};

/* Phaser state function */
GardenState.prototype.create = function () {
	this.add.sprite(0, 0, 'garden', 'bg');
	var speech = createAudioSheet('gardenSpeech', LANG.SPEECH.garden.markers);

	var sure = false;
	var sign = this.add.sprite(750, 100, 'garden', 'sign');
	sign.inputEnabled = true;
	sign.events.onInputDown.add(function () {
		// This happens either on local machine or on "trial" version of the game.
		if (typeof Routes === 'undefined' || Routes === null) {
			game.state.start(GLOBAL.STATE.scenario, true, false);
			return;
		}

		if (player.water > player.maxWater - 6 && !sure) {
			agent.say(speech, 'ok').play('ok'); // TODO: Are you sure? If so, press again.
			sure = true;
			var sub = EventSystem.subscribe(GLOBAL.EVENT.waterPlant, function () {
				sure = false;
				EventSystem.unsubscribe(sub);
			});
		} else {
			var scen = Backend.getScenario();
			if (scen) {
				var t = new TimelineMax();
				t.addSound(speech, agent, 'ok'); // TODO: Let's go!
				t.addCallback(function () {
					game.state.start(GLOBAL.STATE[scen.subgame], true, false, scen);
				});
			}
		}
	}, this);

	/* Setup the garden fields */
	var rows = 3;
	var columns = 8;
	var startPos = 200;
	var width = this.world.width/columns;
	var height = (this.world.height - startPos)/rows;
	var type, level, water, i;
	var fields = this.gardenData.fields;
	for (var row = 0; row < rows; row++) {
		for (var column = 0; column < columns; column++) {
			type = this.rnd.integerInRange(1, 5);
			level = 0;
			water = 0;

			for (i = 0; i < fields.length; i++) {
				if (fields[i].x === column &&
					fields[i].y === row) {
					/*jshint camelcase:false */
					type = fields[i].content_type || type;
					/*jshint camelcase:true */
					level = fields[i].level || level;
					break;
				}
			}

			this.world.add(new GardenPlant(column, row, column*width, startPos+row*height, width, height, type, level, water));
		}
	}

	/* Add the garden agent */
	var agent = player.createAgent();
	agent.scale.set(0.2);
	agent.x = -100;
	agent.y = startPos + height - agent.height/2;
	this.world.add(agent);
	var currentMove = null;

	/* Add the water can */
	this.world.add(new WaterCan());
	var firstWatering = true;

	/* Add disabler. */
	var disabler = new Cover('#ffffff', 0);
	disabler.visible = false;
	this.world.add(disabler);

	/* Add the menu */
	this.world.add(new Menu());

	/* Move agent when we push a plant. */
	EventSystem.subscribe(GLOBAL.EVENT.plantPress, function (plant) {
		var y = plant.y + plant.plantHeight - agent.height/2;
		var x = plant.x;
		// If this is changed: update the side variable in the waterPlant subscription.
		var side = -plant.width * 0.3;
		if (agent.x > x) {
			x += plant.width;
			side *= -1;
		}
		if (agent.x === x && agent.y === y ) {
			return;
		}

		if (currentMove) {
			currentMove.kill();
		}

		currentMove = new TimelineMax();
		var distance = agent.x - x;
		if (agent.y !== y) {
			if (agent.y % (plant.plantHeight - agent.height/2) < 10) {
				distance = 0;
				currentMove.add(agent.move({ x: x }, Math.abs((agent.x - x)/width)));
			}
			currentMove.add(agent.move({ y: y }, Math.abs((agent.y - y)/height)));
		}
		if (agent.x !== x + side || agent.y !== y) {
			currentMove.add(agent.move({ x: x + side }, Math.abs((distance + side)/width)));
		}
		currentMove.addSound(speech, agent, 'ok', 0);
	});

	/* Water plant when we push it. */
	EventSystem.subscribe(GLOBAL.EVENT.waterPlant, function (plant) {
		var t;
		if (player.water > 0) {
			var side = ((plant.x + plant.width/3) <= agent.x) ? -1 : 1;
			t = agent.water(2, side);
			t.addCallback(function () {
				player.water--;
				plant.water.value++;
				agent.say(speech, 'growing').play('growing');
			}, 'watering');
			if (plant.water.left === 1 && plant.level.left === 1) {
				t.addSound(speech, agent, 'fullGrown');
			}
			if (firstWatering && player.water > 1) {
				firstWatering = false;
				t.addSound(speech, agent, 'waterLeft');
			}
		} else {
			t = new TimelineMax();
			t.addSound(speech, agent, 'waterEmpty');
		}

		t.addCallback(function () { disabler.visible = true; }, 0); // at start
		t.addCallback(function () {
			plant.waterButton.reset();
			disabler.visible = false;
		}); // at end

		if (currentMove && currentMove.progress() < 1) {
			currentMove.add(t);
		}
	});

	/* Check that backend accepts plant upgrade */
	EventSystem.subscribe(GLOBAL.EVENT.plantUpgrade, function (data) {
		/*jshint camelcase:false */
		if (data.remaining_water !== player.water) {
			player.water = data.remaining_water;
		}
		/*jshint camelcase:true */
	});

	/* When the state starts: */
	var t = new TimelineMax();
	t.add(agent.move({ x: this.world.centerX }, 3));
	/*
	if (player.water > 0) {
		if (this.gardenData.fields.length > 0) {
			t.addSound(speech, agent, 'whereTo');
		} else {
			t.addSound(speech, agent, 'haveWater');
		}
	} else {
		if (this.gardenData.fields.length > 0) {
			t.addSound(speech, agent, 'welcomeBack'); // TODO: Perhaps a welcome back?
		} else {
			t.addSound(speech, agent, 'intro');
		}
		t.addSound(speech, agent, 'ready');
	}
	*/
};

/* Phaser state function */
GardenState.prototype.shutdown = onShutDown;

/*MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM*/
/*                              Garden objects                               */
/*WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW*/

/**
 * A garden plant/field.
 * It will level up depending on how much you water it.
 * @param {number} column - The column position of the plant (for server).
 * @param {number} row - The row position of the plant (for server).
 * @param {number} x - X position.
 * @param {number} y - Y position.
 * @param {number} width - The width.
 * @param {number} height - The height.
 * @param {number} type - The type of plant.
 * @param {number} level - The level of the plant.
 * @param {number} water - The amount of water the plant has.
 */
GardenPlant.prototype = Object.create(Phaser.Group.prototype);
GardenPlant.prototype.constructor = GardenPlant;
function GardenPlant (column, row, x, y, width, height, type, level, water) {
	Phaser.Group.call(this, game, null); // Parent constructor.
	var _this = this;
	var maxLevel = 5;
	this.column = column;
	this.row = row;
	this.x = x;
	this.y = y;
	this.plantHeight = height;

	/* The pushable area of the field */
	var bmd = game.add.bitmapData(width, height);
	bmd.ctx.globalAlpha = 0;
	bmd.ctx.fillRect(0, 0, bmd.width, bmd.height);
	var trigger = this.create(0, 0, bmd);
	trigger.inputEnabled = true;
	trigger.events.onInputDown.add(this.down, this);

	if (level !== maxLevel) {
		var hl = game.add.bitmapData(width - 6, height * 0.6);
		hl.ctx.fillStyle = '#6b3e09';
		hl.ctx.globalAlpha = 0.2;
		hl.ctx.roundRect(0, 0, hl.width, hl.height, 10).fill();
		this.highlight = this.create(3, height * 0.4, hl);
	}

	this.type = type;
	var plant = null;

	this.water = new Counter(1, true, water);

	this.level = new Counter(maxLevel, false, level);
	this.level.onAdd = function (current, diff) {
		if (current <= 0) {
			if (plant) { plant.destroy(); }
			return;
		}

		var newPlant = _this.create(width/2, height/2, 'garden', 'plant' + _this.type + '-' + current);
		newPlant.anchor.set(0.5);
		newPlant.scale.set(0.5); // TODO: We should not scale this, use better graphics.

		if (diff > 0) {
			// Plant has leveled up by watering.
			newPlant.alpha = 0;

			/* Check that backend accepts plant upgrade */
			var ev = EventSystem.subscribe(GLOBAL.EVENT.plantUpgrade, function (data) {
				if (!data.success && data.field.x === _this.column && data.field.y === _this.row) {
					_this.level.value = data.field.level;
				}
				EventSystem.unsubscribe(ev);
			});

			/* Upgrade plant animation, ending with sending to backend. */
			TweenMax.to(newPlant, 2, {
				alpha: 1,
				onComplete: function () {
					_this.water.update();
					if (plant) { plant.destroy(); }
					plant = newPlant;

				/*jshint camelcase:false */
				Backend.putUpgradePlant({ field: { x: column, y: row, level: this.value, content_type: type }});
				/*jshint camelcase:true */
				}
			});

		} else {
			// Could be: Setup of plant from constructor
			// Could be: Backend says that water is missing
			if (plant) { plant.destroy(); }
			plant = newPlant;
		}
	};
	this.level.update();

	return this;
}

/**
 * When pushing on a garden plant.
 * Publishes plantPress event.
 * Publishes waterPlant when waterButton is pushed.
 */
GardenPlant.prototype.down = function () {
	var _this = this; // Events do not have access to this

	/* If this plant is active, it means that it is already showing only publish plantPress */
	if (this.active) {
		EventSystem.publish(GLOBAL.EVENT.plantPress, [this]);
		return;
	}

	/* The interface for the plant is set up when needed. */
	if (!this.infoGroup) {
		var height = 100;
		this.infoGroup = game.add.group(this);
		this.infoGroup.x = 0;
		this.infoGroup.y = -height;
		this.infoGroup.visible = false;

		var bmd = game.add.bitmapData(this.width, height);
		bmd.ctx.fillStyle = '#ffffff';
		bmd.ctx.globalAlpha = 0.5;
		bmd.ctx.fillRect(0, 0, bmd.width, bmd.height);
		game.add.sprite(0, 0, bmd, null, this.infoGroup).inputEnabled = true;

		/* The button to push when adding water. */
		this.waterButton = new SpriteButton('objects', 'watering_can', {
			x: this.width/2 - (height - 20)/2,
			y: 10,
			size: height - 20,
			keepDown: true,
			onClick: function () {
				/* Water is added to the plant when animation runs. */
				EventSystem.publish(GLOBAL.EVENT.waterPlant, [_this]);
			}
		});
		this.waterButton.sprite.tint = 0xbb3333;
		this.infoGroup.add(this.waterButton);

		/* Water management */
		var maxLevel = function () {
			_this.waterButton.destroy();
			_this.highlight.destroy();
			game.add.text(_this.width/2, height/2, LANG.TEXT.maxLevel, {
				font: '40pt ' +  GLOBAL.FONT,
				fill: '#5555ff'
			}, _this.infoGroup).anchor.set(0.5);
		};

		/* Check if this plant can be upgraded more. */
		if (this.level.left > 0) {
			this.water.onMax = function () {
				_this.level.value++;
				if (_this.level.value === _this.level.max) {
					_this.water.onMax = null;
					maxLevel();
				}
			};
			this.water.update();
		} else {
			maxLevel();
		}
	}

	fade(this.infoGroup, true, 0.2);

	/* Publish plantPress to hide other possible active plant interfaces. */
	EventSystem.publish(GLOBAL.EVENT.plantPress, [this]);

	/* Subscribe to plantPress to hide this plant interface when applicable. */
	this.active = EventSystem.subscribe(GLOBAL.EVENT.plantPress, function () {
		_this.waterButton.reset();
		_this.hide();
	});
};

/**
 * Hide the plant interface
 */
GardenPlant.prototype.hide = function () {
	EventSystem.unsubscribe(this.active);
	this.active = null;
	fade(this.infoGroup, false, 0.2);
};<commit_msg>Garden: Disable at start<commit_after>/**
 * The garden of the game.
 * This is where the player uses the water from the sessions.
 */
function GardenState () {}

/* Phaser state function */
GardenState.prototype.preload = function() {
	this.load.audio('gardenSpeech', LANG.SPEECH.garden.speech); // audio sprite sheet

	this.load.atlasJSONHash('garden', 'assets/img/garden/atlas.png', 'assets/img/garden/atlas.json');

	this.gardenData = Backend.getGarden() || { fields: [] };
};

/* Phaser state function */
GardenState.prototype.create = function () {
	this.add.sprite(0, 0, 'garden', 'bg');
	var speech = createAudioSheet('gardenSpeech', LANG.SPEECH.garden.markers);

	var sure = false;
	var sign = this.add.sprite(750, 100, 'garden', 'sign');
	sign.inputEnabled = true;
	sign.events.onInputDown.add(function () {
		// This happens either on local machine or on "trial" version of the game.
		if (typeof Routes === 'undefined' || Routes === null) {
			game.state.start(GLOBAL.STATE.scenario, true, false);
			return;
		}

		if (player.water > player.maxWater - 6 && !sure) {
			agent.say(speech, 'ok').play('ok'); // TODO: Are you sure? If so, press again.
			sure = true;
			var sub = EventSystem.subscribe(GLOBAL.EVENT.waterPlant, function () {
				sure = false;
				EventSystem.unsubscribe(sub);
			});
		} else {
			var scen = Backend.getScenario();
			if (scen) {
				var t = new TimelineMax();
				t.addSound(speech, agent, 'ok'); // TODO: Let's go!
				t.addCallback(function () {
					game.state.start(GLOBAL.STATE[scen.subgame], true, false, scen);
				});
			}
		}
	}, this);

	/* Setup the garden fields */
	var rows = 3;
	var columns = 8;
	var startPos = 200;
	var width = this.world.width/columns;
	var height = (this.world.height - startPos)/rows;
	var type, level, water, i;
	var fields = this.gardenData.fields;
	for (var row = 0; row < rows; row++) {
		for (var column = 0; column < columns; column++) {
			type = this.rnd.integerInRange(1, 5);
			level = 0;
			water = 0;

			for (i = 0; i < fields.length; i++) {
				if (fields[i].x === column &&
					fields[i].y === row) {
					/*jshint camelcase:false */
					type = fields[i].content_type || type;
					/*jshint camelcase:true */
					level = fields[i].level || level;
					break;
				}
			}

			this.world.add(new GardenPlant(column, row, column*width, startPos+row*height, width, height, type, level, water));
		}
	}

	/* Add the garden agent */
	var agent = player.createAgent();
	agent.scale.set(0.2);
	agent.x = -100;
	agent.y = startPos + height - agent.height/2;
	this.world.add(agent);
	var currentMove = null;

	/* Add the water can */
	this.world.add(new WaterCan());
	var firstWatering = true;

	/* Add disabler. */
	var disabler = new Cover('#ffffff', 0);
	this.world.add(disabler);

	/* Add the menu */
	this.world.add(new Menu());

	/* Move agent when we push a plant. */
	EventSystem.subscribe(GLOBAL.EVENT.plantPress, function (plant) {
		var y = plant.y + plant.plantHeight - agent.height/2;
		var x = plant.x;
		// If this is changed: update the side variable in the waterPlant subscription.
		var side = -plant.width * 0.3;
		if (agent.x > x) {
			x += plant.width;
			side *= -1;
		}
		if (agent.x === x && agent.y === y ) {
			return;
		}

		if (currentMove) {
			currentMove.kill();
		}

		currentMove = new TimelineMax();
		var distance = agent.x - x;
		if (agent.y !== y) {
			if (agent.y % (plant.plantHeight - agent.height/2) < 10) {
				distance = 0;
				currentMove.add(agent.move({ x: x }, Math.abs((agent.x - x)/width)));
			}
			currentMove.add(agent.move({ y: y }, Math.abs((agent.y - y)/height)));
		}
		if (agent.x !== x + side || agent.y !== y) {
			currentMove.add(agent.move({ x: x + side }, Math.abs((distance + side)/width)));
		}
		currentMove.addSound(speech, agent, 'ok', 0);
	});

	/* Water plant when we push it. */
	EventSystem.subscribe(GLOBAL.EVENT.waterPlant, function (plant) {
		var t;
		if (player.water > 0) {
			var side = ((plant.x + plant.width/3) <= agent.x) ? -1 : 1;
			t = agent.water(2, side);
			t.addCallback(function () {
				player.water--;
				plant.water.value++;
				agent.say(speech, 'growing').play('growing');
			}, 'watering');
			if (plant.water.left === 1 && plant.level.left === 1) {
				t.addSound(speech, agent, 'fullGrown');
			}
			if (firstWatering && player.water > 1) {
				firstWatering = false;
				t.addSound(speech, agent, 'waterLeft');
			}
		} else {
			t = new TimelineMax();
			t.addSound(speech, agent, 'waterEmpty');
		}

		t.addCallback(function () { disabler.visible = true; }, 0); // at start
		t.addCallback(function () {
			plant.waterButton.reset();
			disabler.visible = false;
		}); // at end

		if (currentMove && currentMove.progress() < 1) {
			currentMove.add(t);
		}
	});

	/* Check that backend accepts plant upgrade */
	EventSystem.subscribe(GLOBAL.EVENT.plantUpgrade, function (data) {
		/*jshint camelcase:false */
		if (data.remaining_water !== player.water) {
			player.water = data.remaining_water;
		}
		/*jshint camelcase:true */
	});

	/* When the state starts: */
	var t = new TimelineMax();
	t.add(agent.move({ x: this.world.centerX }, 3));
	t.addCallback(function () { disabler.visible = false; });
	/*
	if (player.water > 0) {
		if (this.gardenData.fields.length > 0) {
			t.addSound(speech, agent, 'whereTo');
		} else {
			t.addSound(speech, agent, 'haveWater');
		}
	} else {
		if (this.gardenData.fields.length > 0) {
			t.addSound(speech, agent, 'welcomeBack'); // TODO: Perhaps a welcome back?
		} else {
			t.addSound(speech, agent, 'intro');
		}
		t.addSound(speech, agent, 'ready');
	}
	*/
};

/* Phaser state function */
GardenState.prototype.shutdown = onShutDown;

/*MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM*/
/*                              Garden objects                               */
/*WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW*/

/**
 * A garden plant/field.
 * It will level up depending on how much you water it.
 * @param {number} column - The column position of the plant (for server).
 * @param {number} row - The row position of the plant (for server).
 * @param {number} x - X position.
 * @param {number} y - Y position.
 * @param {number} width - The width.
 * @param {number} height - The height.
 * @param {number} type - The type of plant.
 * @param {number} level - The level of the plant.
 * @param {number} water - The amount of water the plant has.
 */
GardenPlant.prototype = Object.create(Phaser.Group.prototype);
GardenPlant.prototype.constructor = GardenPlant;
function GardenPlant (column, row, x, y, width, height, type, level, water) {
	Phaser.Group.call(this, game, null); // Parent constructor.
	var _this = this;
	var maxLevel = 5;
	this.column = column;
	this.row = row;
	this.x = x;
	this.y = y;
	this.plantHeight = height;

	/* The pushable area of the field */
	var bmd = game.add.bitmapData(width, height);
	bmd.ctx.globalAlpha = 0;
	bmd.ctx.fillRect(0, 0, bmd.width, bmd.height);
	var trigger = this.create(0, 0, bmd);
	trigger.inputEnabled = true;
	trigger.events.onInputDown.add(this.down, this);

	if (level !== maxLevel) {
		var hl = game.add.bitmapData(width - 6, height * 0.6);
		hl.ctx.fillStyle = '#6b3e09';
		hl.ctx.globalAlpha = 0.2;
		hl.ctx.roundRect(0, 0, hl.width, hl.height, 10).fill();
		this.highlight = this.create(3, height * 0.4, hl);
	}

	this.type = type;
	var plant = null;

	this.water = new Counter(1, true, water);

	this.level = new Counter(maxLevel, false, level);
	this.level.onAdd = function (current, diff) {
		if (current <= 0) {
			if (plant) { plant.destroy(); }
			return;
		}

		var newPlant = _this.create(width/2, height/2, 'garden', 'plant' + _this.type + '-' + current);
		newPlant.anchor.set(0.5);
		newPlant.scale.set(0.5); // TODO: We should not scale this, use better graphics.

		if (diff > 0) {
			// Plant has leveled up by watering.
			newPlant.alpha = 0;

			/* Check that backend accepts plant upgrade */
			var ev = EventSystem.subscribe(GLOBAL.EVENT.plantUpgrade, function (data) {
				if (!data.success && data.field.x === _this.column && data.field.y === _this.row) {
					_this.level.value = data.field.level;
				}
				EventSystem.unsubscribe(ev);
			});

			/* Upgrade plant animation, ending with sending to backend. */
			TweenMax.to(newPlant, 2, {
				alpha: 1,
				onComplete: function () {
					_this.water.update();
					if (plant) { plant.destroy(); }
					plant = newPlant;

				/*jshint camelcase:false */
				Backend.putUpgradePlant({ field: { x: column, y: row, level: this.value, content_type: type }});
				/*jshint camelcase:true */
				}
			});

		} else {
			// Could be: Setup of plant from constructor
			// Could be: Backend says that water is missing
			if (plant) { plant.destroy(); }
			plant = newPlant;
		}
	};
	this.level.update();

	return this;
}

/**
 * When pushing on a garden plant.
 * Publishes plantPress event.
 * Publishes waterPlant when waterButton is pushed.
 */
GardenPlant.prototype.down = function () {
	var _this = this; // Events do not have access to this

	/* If this plant is active, it means that it is already showing only publish plantPress */
	if (this.active) {
		EventSystem.publish(GLOBAL.EVENT.plantPress, [this]);
		return;
	}

	/* The interface for the plant is set up when needed. */
	if (!this.infoGroup) {
		var height = 100;
		this.infoGroup = game.add.group(this);
		this.infoGroup.x = 0;
		this.infoGroup.y = -height;
		this.infoGroup.visible = false;

		var bmd = game.add.bitmapData(this.width, height);
		bmd.ctx.fillStyle = '#ffffff';
		bmd.ctx.globalAlpha = 0.5;
		bmd.ctx.fillRect(0, 0, bmd.width, bmd.height);
		game.add.sprite(0, 0, bmd, null, this.infoGroup).inputEnabled = true;

		/* The button to push when adding water. */
		this.waterButton = new SpriteButton('objects', 'watering_can', {
			x: this.width/2 - (height - 20)/2,
			y: 10,
			size: height - 20,
			keepDown: true,
			onClick: function () {
				/* Water is added to the plant when animation runs. */
				EventSystem.publish(GLOBAL.EVENT.waterPlant, [_this]);
			}
		});
		this.waterButton.sprite.tint = 0xbb3333;
		this.infoGroup.add(this.waterButton);

		/* Water management */
		var maxLevel = function () {
			_this.waterButton.destroy();
			_this.highlight.destroy();
			game.add.text(_this.width/2, height/2, LANG.TEXT.maxLevel, {
				font: '40pt ' +  GLOBAL.FONT,
				fill: '#5555ff'
			}, _this.infoGroup).anchor.set(0.5);
		};

		/* Check if this plant can be upgraded more. */
		if (this.level.left > 0) {
			this.water.onMax = function () {
				_this.level.value++;
				if (_this.level.value === _this.level.max) {
					_this.water.onMax = null;
					maxLevel();
				}
			};
			this.water.update();
		} else {
			maxLevel();
		}
	}

	fade(this.infoGroup, true, 0.2);

	/* Publish plantPress to hide other possible active plant interfaces. */
	EventSystem.publish(GLOBAL.EVENT.plantPress, [this]);

	/* Subscribe to plantPress to hide this plant interface when applicable. */
	this.active = EventSystem.subscribe(GLOBAL.EVENT.plantPress, function () {
		_this.waterButton.reset();
		_this.hide();
	});
};

/**
 * Hide the plant interface
 */
GardenPlant.prototype.hide = function () {
	EventSystem.unsubscribe(this.active);
	this.active = null;
	fade(this.infoGroup, false, 0.2);
};<|endoftext|>


<commit_before>var Container = require('react-container');
var React = require('react');
var Tappable = require('react-tappable');
var Sentry = require('react-sentry');

var { UI } = require('touchstonejs');

const scrollable = Container.initScrollable();

var ComplexLinkItem = React.createClass({
	contextTypes: { peopleStore: React.PropTypes.object.isRequired },

	toggleStar () {
		var person = this.props.person

		this.context.peopleStore.star(person, !person.isStarred)
	},

	render () {
		var person = this.props.person;

		var starIcon, starTap
		if (person.isStarred) {
			starTap = 'item-note text-warning';
			starIcon = 'item-note-icon ion-lg ion-ios-star';

		} else {
			starTap = 'item-note default';
			starIcon = 'item-note-icon ion-lg ion-ios-star-outline';
		}

		return (
			<UI.LinkItem linkTo="tabs:list-details" transition="show-from-right" viewProps={{ person: person, prevView: 'list-complex' }}>
				<UI.ItemMedia avatar={person.picture} avatarInitials={person.initials} />
				<UI.ItemInner>
					<UI.ItemContent>
						<UI.ItemTitle>{person.name.full}</UI.ItemTitle>
						<UI.ItemSubTitle>{person.bio}</UI.ItemSubTitle>
					</UI.ItemContent>
					<Tappable onTap={this.toggleStar} stopPropagation className={starTap}>

					</Tappable>
				</UI.ItemInner>
			</UI.LinkItem>
		);
	}
});

module.exports = React.createClass({
	mixins: [Sentry()],
	contextTypes: { peopleStore: React.PropTypes.object.isRequired },

	statics: {
		navigationBar: 'main',
		getNavigation (props, app) {
			return {
				leftArrow: true,
				leftLabel: 'Lists',
				leftAction: () => { app.transitionTo('tabs:lists', { transition: 'reveal-from-right' }) },
				title: 'Complex'
			}
		}
	},

	getInitialState () {
		return {
			people: this.context.peopleStore.getPeople()
		}
	},

	componentDidMount () {
		var self = this

		this.watch(this.context.peopleStore, 'people-updated', people => {
			self.setState({ people })
		})
	},

	handleModeChange (newMode) {
		var selectedMode = newMode;

		if (this.state.selectedMode === newMode) {
			selectedMode = null;
		}

		this.setState({
			selectedMode: selectedMode
		});
	},

	render () {
		var selectedMode = this.state.selectedMode
		var { people } = this.state

		if (selectedMode === 'A' || selectedMode === 'B') {
			people = people.filter(person => person.category === selectedMode)

		} else if (selectedMode === 'starred') {
			people = people.filter(person => person.isStarred)
		}

		var list = people.sort((a, b) => a.name.full.localeCompare(b.name.full)).map((person, i) => {
			return <ComplexLinkItem key={'person' + i} person={person} />
		});

		return (
			<Container scrollable={scrollable}>
				<UI.SegmentedControl value={this.state.selectedMode} onChange={this.handleModeChange} hasGutter options={[
					{ label: 'A', value: 'A' },
					{ label: 'B', value: 'B' },
					{ label: 'Starred', value: 'starred' }
				]} />
				<UI.Group>
					{list}
				</UI.Group>
			</Container>
		);
	}
});
<commit_msg>adding no results message<commit_after>var Container = require('react-container');
var React = require('react');
var Tappable = require('react-tappable');
var Sentry = require('react-sentry');

var { UI } = require('touchstonejs');

const scrollable = Container.initScrollable();

var ComplexLinkItem = React.createClass({
	contextTypes: { peopleStore: React.PropTypes.object.isRequired },

	toggleStar () {
		var person = this.props.person

		this.context.peopleStore.star(person, !person.isStarred)
	},

	render () {
		var person = this.props.person;

		return (
			<UI.LinkItem linkTo="tabs:list-details" transition="show-from-right" viewProps={{ person: person, prevView: 'list-complex' }}>
				<UI.ItemMedia avatar={person.picture} avatarInitials={person.initials} />
				<UI.ItemInner>
					<UI.ItemContent>
						<UI.ItemTitle>{person.name.full}</UI.ItemTitle>
						<UI.ItemSubTitle>{person.bio}</UI.ItemSubTitle>
					</UI.ItemContent>
					<Tappable onTap={this.toggleStar} stopPropagation>
						<UI.ItemNote icon={person.isStarred ? 'ion-ios-star' : 'ion-ios-star-outline'} type={person.isStarred ? 'warning' : 'default'} />
					</Tappable>
				</UI.ItemInner>
			</UI.LinkItem>
		);
	}
});

module.exports = React.createClass({
	mixins: [Sentry()],
	contextTypes: { peopleStore: React.PropTypes.object.isRequired },

	statics: {
		navigationBar: 'main',
		getNavigation (props, app) {
			return {
				leftArrow: true,
				leftLabel: 'Lists',
				leftAction: () => { app.transitionTo('tabs:lists', { transition: 'reveal-from-right' }) },
				title: 'Complex'
			}
		}
	},

	getInitialState () {
		return {
			people: this.context.peopleStore.getPeople()
		}
	},

	componentDidMount () {
		var self = this

		this.watch(this.context.peopleStore, 'people-updated', people => {
			self.setState({ people })
		})
	},

	handleModeChange (newMode) {
		var selectedMode = newMode;

		if (this.state.selectedMode === newMode) {
			selectedMode = null;
		}

		this.setState({
			selectedMode: selectedMode
		});
	},

	render () {
		var selectedMode = this.state.selectedMode
		var { people } = this.state

		if (selectedMode === 'A' || selectedMode === 'B') {
			people = people.filter(person => person.category === selectedMode)

		} else if (selectedMode === 'starred') {
			people = people.filter(person => person.isStarred)
		}

		var noResultsMessage = (
			<Container direction="column" align="center" justify="center" className="no-results">

Go star some people!

			</Container>
		);

		var list = people.sort((a, b) => a.name.full.localeCompare(b.name.full)).map((person, i) => {
			return <ComplexLinkItem key={'person' + i} person={person} />
		});
		var results = people.length ? <UI.Group>{list}</UI.Group> : noResultsMessage;

		return (
			<Container scrollable={scrollable}>
				<UI.SegmentedControl value={this.state.selectedMode} onChange={this.handleModeChange} hasGutter options={[
					{ label: 'A', value: 'A' },
					{ label: 'B', value: 'B' },
					{ label: 'Starred', value: 'starred' }
				]} />
				{results}
			</Container>
		);
	}
});
<|endoftext|>


<commit_before>var moment = require('moment')
require('moment-countdown')

let timeout = null

const ARTICLE_50 = '2019-04-12T23:00:00Z'

function autoCount (bot, lastTick) {
  const thisTick = moment(ARTICLE_50).countdown().toString().split(/, | and /)[0]
  if (lastTick != null && thisTick !== lastTick) {
    bot.broadcast('Article 50 expires in ' + thisTick)
  }
  timeout = setTimeout(autoCount, 1000, bot, thisTick)
}

module.exports = {
  commands: {
    a50: {
      help: 'Gets the time until the UK Article 50 procedure expires',
      command: function () {
        return 'Article 50 expires in ' + moment(ARTICLE_50).countdown().toString()
      }
    },
    a50e: {
      help: 'Gets the time until the UK Article 50 procedure expires',
      command: () => 'Article 50, as extended, expires in ' + moment('2019-05-22T23:00:00Z').countdown().toString()
    },
    ge: {
      help: 'Gets the time until the next General Election under FTPA',
      command: () => 'Polls open in ' + moment('2022-05-05T08:00:00Z').countdown().toString()
    },
    python2: {
      help: 'Gets the time until Python 2 support is dropped',
      command: function () {
        return 'Python 2.7 support ends in ' + moment('2020-01-01T00:00:00Z').countdown().toString()
      }
    }
  },
  events: {
    selfjoin: function (bot) {
      if (timeout !== null) return
      autoCount(bot, null)
    }
  }
}
<commit_msg>Convert a50 time into CEST<commit_after>var moment = require('moment')
require('moment-countdown')

let timeout = null

const ARTICLE_50 = '2019-04-13T00:00:00+02:00'

function autoCount (bot, lastTick) {
  const thisTick = moment(ARTICLE_50).countdown().toString().split(/, | and /)[0]
  if (lastTick != null && thisTick !== lastTick) {
    bot.broadcast('Article 50 expires in ' + thisTick)
  }
  timeout = setTimeout(autoCount, 1000, bot, thisTick)
}

module.exports = {
  commands: {
    a50: {
      help: 'Gets the time until the UK Article 50 procedure expires',
      command: function () {
        return 'Article 50 expires in ' + moment(ARTICLE_50).countdown().toString()
      }
    },
    a50e: {
      help: 'Gets the time until the UK Article 50 procedure expires',
      command: () => 'Article 50, as extended, expires in ' + moment('2019-05-23T00:00:00+0200').countdown().toString()
    },
    ge: {
      help: 'Gets the time until the next General Election under FTPA',
      command: () => 'Polls open in ' + moment('2022-05-05T08:00:00Z').countdown().toString()
    },
    python2: {
      help: 'Gets the time until Python 2 support is dropped',
      command: function () {
        return 'Python 2.7 support ends in ' + moment('2020-01-01T00:00:00Z').countdown().toString()
      }
    }
  },
  events: {
    selfjoin: function (bot) {
      if (timeout !== null) return
      autoCount(bot, null)
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');

var jobsTemplate = fs.readFileSync(__dirname + '/jobs-tab.html', 'utf8');

var Configuration = function PluginConfiguration(ViewsProvider) {
  ViewsProvider.registerDefaultView('cockpit.processInstance.runtime.tab', {
    id: 'jobs-tab',
    label: 'PLUGIN_JOBS_LABEL',
    template: jobsTemplate,
    priority: 0,
    controller:  [
      '$scope', 'camAPI', 'Notifications', '$translate',
      function($scope, camAPI, Notifications, $translate) {

        var jobProvider = camAPI.resource('job');
        var processInstance = $scope.processInstance;

        $scope.pages = {size: 50, total: 0, current: 1};
        $scope.options = {useJobCreationDate: true};

        $scope.onPaginationChange = function(pages) {
          $scope.pages.current = pages.current;
          updateView();
        };

        var updateView = function() {
          var page =  $scope.pages.current,
              count =  $scope.pages.size,
              firstResult = (page - 1) * count;

          var queryParams = {
            'processInstanceId': processInstance.id,
            'timers': true,
            firstResult: firstResult,
            maxResults: count
          };

          //get 'count' of jobs
          jobProvider.count(queryParams, function(error, response) {
            $scope.pages.total = response;
          });

          //get current page and display it
          $scope.loadingState = 'LOADING';
          jobProvider.list(queryParams, jobCallback);

        };

        var jobCallback = function(err, res) {
          if(err) {
            Notifications.addError({
              status: $translate.instant('PLUGIN_JOBS'),
              message: $translate.instant('PLUGIN_JOBS_LOADING_ERROR')
            });
          }
          else {
            $scope.loadingState = res.length ? 'LOADED' : 'EMPTY';
            $scope.jobs = res;
          }
        };

        var recalculateDate = function(job, useCreationDate) {
          jobProvider.recalculateDuedate({id: job.id +3, creationDateBased: useCreationDate}, function(err) {
            if(err) {
              Notifications.addError({
                status: $translate.instant('PLUGIN_JOBS_RECALCULATE_ERROR'),
                message: $translate.instant('PLUGIN_JOBS_RECALCULATE_ERROR_MESSAGE'),
                duration: 5000
              });
            }
            else {
              Notifications.addMessage({
                status: $translate.instant('PLUGIN_JOBS_RECALCULATE_SUCCESS'),
                message: $translate.instant('PLUGIN_JOBS_RECALCULATE_SUCCESS_MESSAGE'),
                duration: 5000
              });
            }
          });
        };

        $scope.recalculateDateFromCreationTime = function(job) {
          recalculateDate(job, true);
        };

        $scope.recalculateDateFromCurrentTime = function(job) {
          recalculateDate(job, false);
        };

        $scope.loadingState = 'LOADING';

      }]
  });
};

Configuration.$inject = ['ViewsProvider'];

module.exports = Configuration;
<commit_msg>fix(cockpit/history): use correct ID when recalculating Jobs<commit_after>'use strict';

var fs = require('fs');

var jobsTemplate = fs.readFileSync(__dirname + '/jobs-tab.html', 'utf8');

var Configuration = function PluginConfiguration(ViewsProvider) {
  ViewsProvider.registerDefaultView('cockpit.processInstance.runtime.tab', {
    id: 'jobs-tab',
    label: 'PLUGIN_JOBS_LABEL',
    template: jobsTemplate,
    priority: 0,
    controller:  [
      '$scope', 'camAPI', 'Notifications', '$translate',
      function($scope, camAPI, Notifications, $translate) {

        var jobProvider = camAPI.resource('job');
        var processInstance = $scope.processInstance;

        $scope.pages = {size: 50, total: 0, current: 1};
        $scope.options = {useJobCreationDate: true};

        $scope.onPaginationChange = function(pages) {
          $scope.pages.current = pages.current;
          updateView();
        };

        var updateView = function() {
          var page =  $scope.pages.current,
              count =  $scope.pages.size,
              firstResult = (page - 1) * count;

          var queryParams = {
            'processInstanceId': processInstance.id,
            'timers': true,
            firstResult: firstResult,
            maxResults: count
          };

          //get 'count' of jobs
          jobProvider.count(queryParams, function(error, response) {
            $scope.pages.total = response;
          });

          //get current page and display it
          $scope.loadingState = 'LOADING';
          jobProvider.list(queryParams, jobCallback);

        };

        var jobCallback = function(err, res) {
          if(err) {
            Notifications.addError({
              status: $translate.instant('PLUGIN_JOBS'),
              message: $translate.instant('PLUGIN_JOBS_LOADING_ERROR')
            });
          }
          else {
            $scope.loadingState = res.length ? 'LOADED' : 'EMPTY';
            $scope.jobs = res;
          }
        };

        var recalculateDate = function(job, useCreationDate) {
          jobProvider.recalculateDuedate({id: job.id, creationDateBased: useCreationDate}, function(err) {
            if(err) {
              Notifications.addError({
                status: $translate.instant('PLUGIN_JOBS_RECALCULATE_ERROR'),
                message: $translate.instant('PLUGIN_JOBS_RECALCULATE_ERROR_MESSAGE'),
                duration: 5000
              });
            }
            else {
              Notifications.addMessage({
                status: $translate.instant('PLUGIN_JOBS_RECALCULATE_SUCCESS'),
                message: $translate.instant('PLUGIN_JOBS_RECALCULATE_SUCCESS_MESSAGE'),
                duration: 5000
              });
            }
          });
        };

        $scope.recalculateDateFromCreationTime = function(job) {
          recalculateDate(job, true);
        };

        $scope.recalculateDateFromCurrentTime = function(job) {
          recalculateDate(job, false);
        };

        $scope.loadingState = 'LOADING';

      }]
  });
};

Configuration.$inject = ['ViewsProvider'];

module.exports = Configuration;
<|endoftext|>


<commit_before>const functions = require('./');
const config = require('../config').config;
const _ = require('lodash');
const seedrandom = require('seedrandom');
const rng = seedrandom(Math.random(), {entropy: true});

const dice = sides => Math.floor(rng() * sides) + 1;

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

async function asyncForEach(array, callback) {
	for (let index = 0; index < array.length; index++) {
		await callback(array[index], index, array);
	}
}

function polyhedral(sides, str, message) {
	let total = 0, r = 0, text = '', modifier;
	if (str.length > 0) modifier = +(str[str.length - 1]).replace(/\D/g, "");
	//no modifier
	if (str.length < 1) {
		total = dice(sides);
		text = ` rolled a d${sides}: ${total}`;
		//addition modifier
	} else if (str.some(e => e.includes('+'))) {
		r = dice(sides);
		total = r + modifier;
		text = ` rolled a d${sides}: ${r} + ${modifier} for at total of ${total}`;
		//subtraction modifier
	} else if (str.some(e => e.includes('-'))) {
		r = dice(sides);
		total = r - modifier;
		text = ` rolled a d${sides}: ${r} - ${modifier} for at total of ${total}`;
	}
	message.reply(text);
	return total;
}

async function buildPrefix(bot, message) {
	return new Promise(async resolve => {
		let prefix = await functions.readData(bot, message, 'prefix');
		if (!prefix) prefix = functions.config.prefix;

		if (message.content.includes(bot.user.id) && message.content.includes('prefix')) message.channel.send(`${bot.user.username} is using ${prefix} as the activator for this server`);
		//Ignore messages that dont include with the command symbol
		if (!message.content.includes(prefix)) resolve();
		resolve(prefix);
	}).catch(error => message.reply(`That's an Error! ${error} in buildPrefix`));
}

function buildParams(message, prefix) {
	let params = message.content.split(' ');
	if (!params[0].startsWith(prefix)) {
		let newParams = false;
		params.forEach((param, index) => {
			if (param.startsWith(prefix)) newParams = params.slice(index);
		});
		if (!newParams) return;
		params = newParams;
	}
	//remove user mentions
	params.forEach((param, index) => {
		if (param.includes('<') && param.includes('>')) params.splice(index, 1);
	});

	return params;
}

function buildCommand(params) {
	//create command
	if (!params[0]) return [false, params];
	let command = params[0].slice(1);
	params = params.slice(1);
	return [_.toLower(command), params];
}

function buildDescriptor(params) {
	let beg, end;
	let desc = [];
	params.forEach((param, index) => {
		if (param.includes('\"') || param.includes('“') | param.includes('\'')) {
			if (beg === undefined) {
				beg = index;
				end = index;
			} else end = index;
		}
	});

	if (beg !== undefined && end !== undefined) {
		desc = params.slice(beg, end + 1);
		params.splice(beg, end + 1 - beg);
		desc.forEach((word, index) => desc[index] = word.replace(/['"`“]/g, ''));
		desc = desc.join(' ');
	}
	return [desc, params];
}

function buildStats(bot, message) {
	bot.shard.broadcastEval('this.guilds.size')
		.then(results => message.channel.send(`Currently on ${results.reduce((prev, val) => prev + val, 0)} servers!`).catch(console.error))
		.catch(console.error);
	bot.shard.broadcastEval(`(${buildMemberList}).call(this)`)
		.then(list => {
			list = _.flatten(list);
			let users = _.uniq(list).length;
			message.channel.send(`Currently assisting ${users} unique users!`).catch(console.error);
		})
		.catch(console.error);
}

function buildMemberList() {
	let users = [];
	this.guilds.forEach(guild => guild.members.forEach(member => users.push(member.user.id)));
	return users;
}

function checkPatreon(bot, authorID) {
	return new Promise((resolve, reject) => {
		bot.shard.broadcastEval(`(${checkRoles}).call(this, '${authorID}', '${config.patreonGuild}', '${config.patronDiceRole}')`)
			.then(array => resolve(array.some(toggle => toggle)))
			.catch(reject);
	});
}

function checkRoles(authorID, patreonGuild, patronDiceRole) {
	const guild = this.guilds.get(patreonGuild);
	if (!guild) return null;
	return guild.roles.get(patronDiceRole).members.some(member => member.user.id === authorID);
}

exports.buildCommand = buildCommand;
exports.buildDescriptor = buildDescriptor;
exports.buildParams = buildParams;
exports.buildPrefix = buildPrefix;
exports.buildStats = buildStats;
exports.checkPatreon = checkPatreon;
exports.asyncForEach = asyncForEach;
exports.dice = dice;
exports.modifierRoll = polyhedral;
exports.sleep = sleep;

<commit_msg>2.6.2     -stats fix<commit_after>const functions = require('./');
const config = require('../config').config;
const _ = require('lodash');
const seedrandom = require('seedrandom');
const rng = seedrandom(Math.random(), {entropy: true});

const dice = sides => Math.floor(rng() * sides) + 1;

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

async function asyncForEach(array, callback) {
	for (let index = 0; index < array.length; index++) {
		await callback(array[index], index, array);
	}
}

function polyhedral(sides, str, message) {
	let total = 0, r = 0, text = '', modifier;
	if (str.length > 0) modifier = +(str[str.length - 1]).replace(/\D/g, "");
	//no modifier
	if (str.length < 1) {
		total = dice(sides);
		text = ` rolled a d${sides}: ${total}`;
		//addition modifier
	} else if (str.some(e => e.includes('+'))) {
		r = dice(sides);
		total = r + modifier;
		text = ` rolled a d${sides}: ${r} + ${modifier} for at total of ${total}`;
		//subtraction modifier
	} else if (str.some(e => e.includes('-'))) {
		r = dice(sides);
		total = r - modifier;
		text = ` rolled a d${sides}: ${r} - ${modifier} for at total of ${total}`;
	}
	message.reply(text);
	return total;
}

async function buildPrefix(bot, message) {
	return new Promise(async resolve => {
		let prefix = await functions.readData(bot, message, 'prefix');
		if (!prefix) prefix = functions.config.prefix;

		if (message.content.includes(bot.user.id) && message.content.includes('prefix')) message.channel.send(`${bot.user.username} is using ${prefix} as the activator for this server`);
		//Ignore messages that dont include with the command symbol
		if (!message.content.includes(prefix)) resolve();
		resolve(prefix);
	}).catch(error => message.reply(`That's an Error! ${error} in buildPrefix`));
}

function buildParams(message, prefix) {
	let params = message.content.split(' ');
	if (!params[0].startsWith(prefix)) {
		let newParams = false;
		params.forEach((param, index) => {
			if (param.startsWith(prefix)) newParams = params.slice(index);
		});
		if (!newParams) return;
		params = newParams;
	}
	//remove user mentions
	params.forEach((param, index) => {
		if (param.includes('<') && param.includes('>')) params.splice(index, 1);
	});

	return params;
}

function buildCommand(params) {
	//create command
	if (!params[0]) return [false, params];
	let command = params[0].slice(1);
	params = params.slice(1);
	return [_.toLower(command), params];
}

function buildDescriptor(params) {
	let beg, end;
	let desc = [];
	params.forEach((param, index) => {
		if (param.includes('\"') || param.includes('“') | param.includes('\'')) {
			if (beg === undefined) {
				beg = index;
				end = index;
			} else end = index;
		}
	});

	if (beg !== undefined && end !== undefined) {
		desc = params.slice(beg, end + 1);
		params.splice(beg, end + 1 - beg);
		desc.forEach((word, index) => desc[index] = word.replace(/['"`“]/g, ''));
		desc = desc.join(' ');
	}
	return [desc, params];
}

function buildStats(bot, message) {
	message.channel.send(`Currently there are ${bot.shard.count} shards.`).catch(console.error);
	bot.shard.broadcastEval('this.guilds.size')
		.then(results => message.channel.send(`Currently on ${results.reduce((prev, val) => prev + val, 0)} servers.`).catch(console.error))
		.catch(console.error);
	bot.shard.broadcastEval(`(${buildMemberList}).call(this)`)
		.then(list => {
			list = _.flatten(list);
			let users = _.uniq(list).length;
			message.channel.send(`Currently assisting ${users} unique users.`).catch(console.error);
		}).catch(console.error);
}

function buildMemberList() {
	let users = [];
	this.guilds.forEach(guild => guild.members.forEach(member => users.push(member.user.id)));
	return users;
}

function checkPatreon(bot, authorID) {
	return new Promise((resolve, reject) => {
		bot.shard.broadcastEval(`(${checkRoles}).call(this, '${authorID}', '${config.patreonGuild}', '${config.patronDiceRole}')`)
			.then(array => resolve(array.some(toggle => toggle)))
			.catch(reject);
	});
}

function checkRoles(authorID, patreonGuild, patronDiceRole) {
	const guild = this.guilds.get(patreonGuild);
	if (!guild) return null;
	return guild.roles.get(patronDiceRole).members.some(member => member.user.id === authorID);
}

exports.buildCommand = buildCommand;
exports.buildDescriptor = buildDescriptor;
exports.buildParams = buildParams;
exports.buildPrefix = buildPrefix;
exports.buildStats = buildStats;
exports.checkPatreon = checkPatreon;
exports.asyncForEach = asyncForEach;
exports.dice = dice;
exports.modifierRoll = polyhedral;
exports.sleep = sleep;

<|endoftext|>