<commit_before>/** @flow */
import Immutable from 'immutable'
import PropTypes from 'prop-types'
import React, { PureComponent } from 'react'
import { Redirect } from 'react-router'
import { HashRouter, Route } from 'react-router-dom'

import ComponentLink from './ComponentLink'
import styles from './Application.css'
import NavLink from './NavLink'
import Wizard from './Wizard'
import { TYPES } from './Icon'
import { generateRandomList } from './utils'

import ArrowKeyStepperExample from '../ArrowKeyStepper/ArrowKeyStepper.example'
import AutoSizerExample from '../AutoSizer/AutoSizer.example'
import CellMeasurerExample from '../CellMeasurer/CellMeasurer.example'
import CollectionExample from '../Collection/Collection.example'
import ColumnSizerExample from '../ColumnSizer/ColumnSizer.example'
import GridExample from '../Grid/Grid.example'
import InfiniteLoaderExample from '../InfiniteLoader/InfiniteLoader.example'
import ListExample from '../List/List.example'
import MasonryExample from '../Masonry/Masonry.example'
import MultiGridExample from '../MultiGrid/MultiGrid.example'
import ScrollSyncExample from '../ScrollSync/ScrollSync.example'
import TableExample from '../Table/Table.example'
import WindowScrollerExample from '../WindowScroller/WindowScroller.example'

const COMPONENT_EXAMPLES_MAP = {
  '/components/ArrowKeyStepper': ArrowKeyStepperExample,
  '/components/AutoSizer': AutoSizerExample,
  '/components/CellMeasurer': CellMeasurerExample,
  '/components/Collection': CollectionExample,
  '/components/ColumnSizer': ColumnSizerExample,
  '/components/Grid': GridExample,
  '/components/Masonry': MasonryExample,
  '/components/InfiniteLoader': InfiniteLoaderExample,
  '/components/List': ListExample,
  '/components/MultiGrid': MultiGridExample,
  '/components/ScrollSync': ScrollSyncExample,
  '/components/Table': TableExample,
  '/components/WindowScroller': WindowScrollerExample
}

// HACK Generate arbitrary data for use in example components :)
const list = Immutable.List(generateRandomList())

export default class Application extends PureComponent {
  static childContextTypes = {
    list: PropTypes.instanceOf(Immutable.List).isRequired,
    customElement: PropTypes.any,
    isScrollingCustomElement: PropTypes.bool.isRequired,
    setScrollingCustomElement: PropTypes.func
  };

  state = {
    isScrollingCustomElement: false
  }

  constructor (props) {
    super(props)
    this.setScrollingCustomElement = this.setScrollingCustomElement.bind(this)
  }

  setScrollingCustomElement (custom) {
    this.setState({ isScrollingCustomElement: custom })
  }

  getChildContext () {
    const { customElement, isScrollingCustomElement } = this.state
    return {
      list,
      customElement,
      isScrollingCustomElement,
      setScrollingCustomElement: this.setScrollingCustomElement
    }
  }

  render () {
    const { isScrollingCustomElement } = this.state
    const bodyStyle = isScrollingCustomElement ? styles.ScrollingBody : styles.Body
    return (
      <HashRouter>

                  React

                  Virtualized

                <NavLink to='/components/List' iconType={TYPES.COMPONENTS}>Components</NavLink>
                <NavLink to='/wizard' iconType={TYPES.WIZARD}>Wizard</NavLink>
                <NavLink href='https://github.com/bvaughn/react-virtualized' iconType={TYPES.SOURCE}>Source</NavLink>
                <NavLink href='https://github.com/bvaughn/react-virtualized/tree/master/docs#documentation' iconType={TYPES.DOCUMENTATION}>Documentation</NavLink>
                <NavLink href='https://github.com/bvaughn/react-virtualized/issues' iconType={TYPES.ISSUES}>Issues</NavLink>

              <ComponentLink to='/components/Collection'>Collection</ComponentLink>
              <ComponentLink to='/components/Grid'>Grid</ComponentLink>
              <ComponentLink to='/components/List'>List</ComponentLink>
              <ComponentLink to='/components/Masonry'>Masonry</ComponentLink>
              <ComponentLink to='/components/Table'>Table</ComponentLink>

              <ComponentLink to='/components/ArrowKeyStepper'>ArrowKeyStepper</ComponentLink>
              <ComponentLink to='/components/AutoSizer'>AutoSizer</ComponentLink>
              <ComponentLink to='/components/CellMeasurer'>CellMeasurer</ComponentLink>
              <ComponentLink to='/components/ColumnSizer'>ColumnSizer</ComponentLink>
              <ComponentLink to='/components/InfiniteLoader'>InfiniteLoader</ComponentLink>
              <ComponentLink to='/components/MultiGrid'>MultiGrid</ComponentLink>
              <ComponentLink to='/components/ScrollSync'>ScrollSync</ComponentLink>
              <ComponentLink to='/components/WindowScroller'>WindowScroller</ComponentLink>

 this.setState({ customElement: e })}>

              <Route path='/wizard' component={Wizard} />
              {Object.keys(COMPONENT_EXAMPLES_MAP).map((route) => (
                <Route
                  key={route}
                  path={route}
                  component={COMPONENT_EXAMPLES_MAP[route]}
                />
              ))}
              <Route
                exactly
                path='/'
                render={() => (
                  <Redirect to='/components/List' />
                )}
              />

      </HashRouter>
    )
  }
}
<commit_msg>Changed exactly prop on Route component to exact for RRV4 final<commit_after>/** @flow */
import Immutable from 'immutable'
import PropTypes from 'prop-types'
import React, { PureComponent } from 'react'
import { Redirect } from 'react-router'
import { HashRouter, Route } from 'react-router-dom'

import ComponentLink from './ComponentLink'
import styles from './Application.css'
import NavLink from './NavLink'
import Wizard from './Wizard'
import { TYPES } from './Icon'
import { generateRandomList } from './utils'

import ArrowKeyStepperExample from '../ArrowKeyStepper/ArrowKeyStepper.example'
import AutoSizerExample from '../AutoSizer/AutoSizer.example'
import CellMeasurerExample from '../CellMeasurer/CellMeasurer.example'
import CollectionExample from '../Collection/Collection.example'
import ColumnSizerExample from '../ColumnSizer/ColumnSizer.example'
import GridExample from '../Grid/Grid.example'
import InfiniteLoaderExample from '../InfiniteLoader/InfiniteLoader.example'
import ListExample from '../List/List.example'
import MasonryExample from '../Masonry/Masonry.example'
import MultiGridExample from '../MultiGrid/MultiGrid.example'
import ScrollSyncExample from '../ScrollSync/ScrollSync.example'
import TableExample from '../Table/Table.example'
import WindowScrollerExample from '../WindowScroller/WindowScroller.example'

const COMPONENT_EXAMPLES_MAP = {
  '/components/ArrowKeyStepper': ArrowKeyStepperExample,
  '/components/AutoSizer': AutoSizerExample,
  '/components/CellMeasurer': CellMeasurerExample,
  '/components/Collection': CollectionExample,
  '/components/ColumnSizer': ColumnSizerExample,
  '/components/Grid': GridExample,
  '/components/Masonry': MasonryExample,
  '/components/InfiniteLoader': InfiniteLoaderExample,
  '/components/List': ListExample,
  '/components/MultiGrid': MultiGridExample,
  '/components/ScrollSync': ScrollSyncExample,
  '/components/Table': TableExample,
  '/components/WindowScroller': WindowScrollerExample
}

// HACK Generate arbitrary data for use in example components :)
const list = Immutable.List(generateRandomList())

export default class Application extends PureComponent {
  static childContextTypes = {
    list: PropTypes.instanceOf(Immutable.List).isRequired,
    customElement: PropTypes.any,
    isScrollingCustomElement: PropTypes.bool.isRequired,
    setScrollingCustomElement: PropTypes.func
  };

  state = {
    isScrollingCustomElement: false
  }

  constructor (props) {
    super(props)
    this.setScrollingCustomElement = this.setScrollingCustomElement.bind(this)
  }

  setScrollingCustomElement (custom) {
    this.setState({ isScrollingCustomElement: custom })
  }

  getChildContext () {
    const { customElement, isScrollingCustomElement } = this.state
    return {
      list,
      customElement,
      isScrollingCustomElement,
      setScrollingCustomElement: this.setScrollingCustomElement
    }
  }

  render () {
    const { isScrollingCustomElement } = this.state
    const bodyStyle = isScrollingCustomElement ? styles.ScrollingBody : styles.Body
    return (
      <HashRouter>

                  React

                  Virtualized

                <NavLink to='/components/List' iconType={TYPES.COMPONENTS}>Components</NavLink>
                <NavLink to='/wizard' iconType={TYPES.WIZARD}>Wizard</NavLink>
                <NavLink href='https://github.com/bvaughn/react-virtualized' iconType={TYPES.SOURCE}>Source</NavLink>
                <NavLink href='https://github.com/bvaughn/react-virtualized/tree/master/docs#documentation' iconType={TYPES.DOCUMENTATION}>Documentation</NavLink>
                <NavLink href='https://github.com/bvaughn/react-virtualized/issues' iconType={TYPES.ISSUES}>Issues</NavLink>

              <ComponentLink to='/components/Collection'>Collection</ComponentLink>
              <ComponentLink to='/components/Grid'>Grid</ComponentLink>
              <ComponentLink to='/components/List'>List</ComponentLink>
              <ComponentLink to='/components/Masonry'>Masonry</ComponentLink>
              <ComponentLink to='/components/Table'>Table</ComponentLink>

              <ComponentLink to='/components/ArrowKeyStepper'>ArrowKeyStepper</ComponentLink>
              <ComponentLink to='/components/AutoSizer'>AutoSizer</ComponentLink>
              <ComponentLink to='/components/CellMeasurer'>CellMeasurer</ComponentLink>
              <ComponentLink to='/components/ColumnSizer'>ColumnSizer</ComponentLink>
              <ComponentLink to='/components/InfiniteLoader'>InfiniteLoader</ComponentLink>
              <ComponentLink to='/components/MultiGrid'>MultiGrid</ComponentLink>
              <ComponentLink to='/components/ScrollSync'>ScrollSync</ComponentLink>
              <ComponentLink to='/components/WindowScroller'>WindowScroller</ComponentLink>

 this.setState({ customElement: e })}>

              <Route path='/wizard' component={Wizard} />
              {Object.keys(COMPONENT_EXAMPLES_MAP).map((route) => (
                <Route
                  key={route}
                  path={route}
                  component={COMPONENT_EXAMPLES_MAP[route]}
                />
              ))}
              <Route
                exact
                path='/'
                render={() => (
                  <Redirect to='/components/List' />
                )}
              />

      </HashRouter>
    )
  }
}
<|endoftext|>


<commit_before>//============== Eventhandler ==================//

$(window).load(function() {										// warte darauf, dass der Inhalt geladen wurde
	$(document).keydown(function(event) {
		if (event.keyCode === 27) {								// Escape wurde gedrueckt
			$('#zoomWrap').hide();								// verstecke das Bildfenster
		}
	});

	$('#cityform .submitForm').on('click', function() {
		$('#cityform').submit();
	});

	$('#newcityform').submit(function(event) {
		if ($('#formemail').val().substring($('#formemail').val().length-20, $('#formemail').val().length) !== "@beuth-hochschule.de") {		// wenn die letzten 20 Zeichen nicht dem String entsprechen
			event.preventDefault();																// Abbruch
		}
	});

	$('#zoom a').on('click', function() {
		$('#zoomWrap').hide();
	});

	/*var trs = document.getElementsByTagName('tr');
	for (var x=0; x<trs.length; x++) {
		trs[x].addEventListener('mouseover', function() {
			var tds = this.getElementsByTagName('td');
			tds[10].style.visibility = 'visible';
		}, false);
		trs[x].addEventListener('mouseout', function() {
			var tds = this.getElementsByTagName('td');
			tds[10].style.visibility = 'hidden';
		}, false);
	}*/

	$('select').on('change', function() {
		if ($(this).find('option:selected').val() === "neuestadt") {								// wenn eine neue Stadt eingetragen werden soll
			var userInput = prompt("Geben Sie den Namen der neuen Stadt ein:");
			if (userInput !== "" && userInput !== null) {
				$(this).append(new Option(userInput, formatValue(userInput), true, true));						// erstelle neue Option mit der Benutzereingabe
			}
		}
	});

	$('.zoomlink').on('click', function() {
		var img = $(this).find('img').attr('src');
		$('#zoomImage').attr('src', img);
		$('#zoomWrap').show();
	});

	$('.editlink').on('click', function() {
		$(this).parent().parent().find('.editable').hide();
		$(this).parent().parent().find('.edit').show();
	});

	$('.savelink').on('click', function() {
		var $tr = $(this).parent().parent();
		$tr.find('.editable.date').text(formatDate($tr.find('input[type=date]').val()));
		$tr.find('.editable.temp').html($tr.find('input[type=number]').val() + " °C");
		$tr.find('.editable.city').text($tr.find('select option:selected').text());
		$tr.find('.editable.comment').text($tr.find('input[type=text]').val());
		$tr.find('.edit').hide();
		$tr.find('.editable').show();
	});

	$('.deletelink').on('click', function(e) {
		e.preventDefault();
		var el = $(this).parent();
		var title = el.attr('data-title');
		var msg = el.attr('data-message');
		var dataForm = el.attr('data-form');

		$('#formConfirm')
			.find('#frm_body').html(msg)
			.end().find('#frm_title').html(title)
			.end().modal('show');

		//$('#formConfirm').find('#frm_submit').attr('data-form', dataForm);
	});

	$('#formConfirm').on('click', '#frm_submit', function(e) {
		/*var id = $(this).attr('data-form');
		$(id).submit();*/
	});

	initialize();
});

//============== Hauptfunktionen ===============//

function initialize() {
	$.backstretch("img/wetter_bg.jpg");

	/*$.backstretch([
		"img/wetter_bg.jpg",
		"img/wetter/wetter1.jpg",
		"img/wetter/wetter2.jpg",
		"img/wetter/wetter3.jpg",
		"img/wetter/wetter4.jpg",
		"img/wetter/wetter5.jpg",
		"img/wetter/wetter6.jpg",
		"img/wetter/wetter7.jpg"
	], {duration: 4000, fade: 750});*/

	var today = new Date();									// neues Datum erzeugen
	var dd = today.getDate();								// hole den Tag
	var mm = today.getMonth()+1;							// hole den Monat; +1 weil hier Januar mit 0 gezaehlt wird
	var yyyy = today.getFullYear();							// hole das Jahr
	$('#formdate').val(yyyy + "-" + mm + "-" + dd);			// formdate auf das heutige Datum setzen
	$('select').each(function() {
		addCities($(this));
	});
}

function addCities($select) {
	$select.append(new Option("Stadt", "", true));						// damit man nicht alle Staedte mehrfach eintragen muss
	$('select [value=""]').attr('disabled', true);
	$select.append(new Option("Berlin", "koeln"));
	$select.append(new Option("Köln", "berlin"));
	$select.append(new Option("Frankfurt", "frankfurt"));
	$select.append(new Option("Hamburg", "hamburg"));
	$select.append(new Option("München", "muenchen"));
	$select.append(new Option("Neue Stadt...", "neuestadt"));
}

//============== Helferfunktionen ==============//

function formatValue(str) {									// ersetze alle dt. Umlaute und gib das Wort in Kleinbuchstaben zurueck
	return str.toLowerCase().replace(/\u00e4/g, "ae").replace(/\u00f6/g, "oe").replace(/\u00fc/g, "ue").replace(/\u00df/g, "ss").replace(/ /g, "_");
}

function formatDate(date) {									// uebersetze ein Datum vom ISO 8601-Format in die dt. Schreibweise und gib es zurueck
	return date.replace(/(\d\d\d\d)-(\d\d)-(\d\d)/i, "$3.$2.$1");
}<commit_msg>Changed variables<commit_after>//============== Eventhandler ==================//

$(window).load(function() {										// warte darauf, dass der Inhalt geladen wurde
	$(document).keydown(function(event) {
		if (event.keyCode === 27) {								// Escape wurde gedrueckt
			$('#zoomWrap').hide();								// verstecke das Bildfenster
		}
	});

	$('#cityform .submitForm').on('click', function() {
		$('#cityform').submit();
	});

	$('#newcityform').submit(function(event) {
		if ($('#formemail').val().substring($('#formemail').val().length-20, $('#formemail').val().length) !== "@beuth-hochschule.de") {		// wenn die letzten 20 Zeichen nicht dem String entsprechen
			event.preventDefault();																// Abbruch
		}
	});

	$('#zoom a').on('click', function() {
		$('#zoomWrap').hide();
	});

	/*var trs = document.getElementsByTagName('tr');
	for (var x=0; x<trs.length; x++) {
		trs[x].addEventListener('mouseover', function() {
			var tds = this.getElementsByTagName('td');
			tds[10].style.visibility = 'visible';
		}, false);
		trs[x].addEventListener('mouseout', function() {
			var tds = this.getElementsByTagName('td');
			tds[10].style.visibility = 'hidden';
		}, false);
	}*/

	$('select').on('change', function() {
		if ($(this).find('option:selected').val() === "neuestadt") {								// wenn eine neue Stadt eingetragen werden soll
			var userInput = prompt("Geben Sie den Namen der neuen Stadt ein:");
			if (userInput !== "" && userInput !== null) {
				$(this).append(new Option(userInput, formatValue(userInput), true, true));						// erstelle neue Option mit der Benutzereingabe
			}
		}
	});

	$('.zoomlink').on('click', function() {
		var img = $(this).find('img').attr('src');
		$('#zoomImage').attr('src', img);
		$('#zoomWrap').show();
	});

	$('.editlink').on('click', function() {
		$(this).parent().parent().find('.editable').hide();
		$(this).parent().parent().find('.edit').show();
	});

	$('.savelink').on('click', function() {
		var tr = $(this).parent().parent();
		tr.find('.editable.date').text(formatDate(tr.find('input[type=date]').val()));
		tr.find('.editable.temp').html(tr.find('input[type=number]').val() + " °C");
		tr.find('.editable.city').text(tr.find('select option:selected').text());
		tr.find('.editable.comment').text(tr.find('input[type=text]').val());
		tr.find('.edit').hide();
		tr.find('.editable').show();
	});

	$('.deletelink').on('click', function(e) {
		e.preventDefault();
		var el = $(this).parent();
		var title = el.attr('data-title');
		var msg = el.attr('data-message');
		var dataForm = el.attr('data-form');

		$('#formConfirm')
			.find('#frm_body').html(msg)
			.end().find('#frm_title').html(title)
			.end().modal('show');

		//$('#formConfirm').find('#frm_submit').attr('data-form', dataForm);
	});

	$('#formConfirm').on('click', '#frm_submit', function(e) {
		/*var id = $(this).attr('data-form');
		$(id).submit();*/
	});

	initialize();
});

//============== Hauptfunktionen ===============//

function initialize() {
	$.backstretch("img/wetter_bg.jpg");

	/*$.backstretch([
		"img/wetter_bg.jpg",
		"img/wetter/wetter1.jpg",
		"img/wetter/wetter2.jpg",
		"img/wetter/wetter3.jpg",
		"img/wetter/wetter4.jpg",
		"img/wetter/wetter5.jpg",
		"img/wetter/wetter6.jpg",
		"img/wetter/wetter7.jpg"
	], {duration: 4000, fade: 750});*/

	var today = new Date();									// neues Datum erzeugen
	var dd = today.getDate();								// hole den Tag
	var mm = today.getMonth()+1;							// hole den Monat; +1 weil hier Januar mit 0 gezaehlt wird
	var yyyy = today.getFullYear();							// hole das Jahr
	$('#formdate').val(yyyy + "-" + mm + "-" + dd);			// formdate auf das heutige Datum setzen
	$('select').each(function() {
		addCities($(this));
	});
}

function addCities(select) {
	select.append(new Option("Stadt", "", true));						// damit man nicht alle Staedte mehrfach eintragen muss
	$('select [value=""]').attr('disabled', true);
	select.append(new Option("Berlin", "koeln"));
	select.append(new Option("Köln", "berlin"));
	select.append(new Option("Frankfurt", "frankfurt"));
	select.append(new Option("Hamburg", "hamburg"));
	select.append(new Option("München", "muenchen"));
	select.append(new Option("Neue Stadt...", "neuestadt"));
}

//============== Helferfunktionen ==============//

function formatValue(str) {									// ersetze alle dt. Umlaute und gib das Wort in Kleinbuchstaben zurueck
	return str.toLowerCase().replace(/\u00e4/g, "ae").replace(/\u00f6/g, "oe").replace(/\u00fc/g, "ue").replace(/\u00df/g, "ss").replace(/ /g, "_");
}

function formatDate(date) {									// uebersetze ein Datum vom ISO 8601-Format in die dt. Schreibweise und gib es zurueck
	return date.replace(/(\d\d\d\d)-(\d\d)-(\d\d)/i, "$3.$2.$1");
}<|endoftext|>


<commit_before>import request from 'request';
import Clock from './clock.js';
import retry from './retry.js';
import {ByPassRetryError} from './retry.js';
import debug from 'debug';

const logger = debug('kadira-core:transport');

const DEFAULTS = {
  appId: '',
  appSecret: '',
  endpoint: 'https://enginex.kadira.io',
  hostname: 'localhost',
  clockSyncInterval: 1000 * 60,
  dataFlushInterval: 1000 * 10,
};

// exporting this for if we need to get this as a NPM module.
export class Kadira {
  constructor(_options) {
    this._options = Object.assign({}, DEFAULTS, _options);
    this._headers = {
      'content-type': 'application/json',
      accepts: 'application/json',
      'KADIRA-APP-ID': this._options.appId,
      'KADIRA-APP-SECRET': this._options.appSecret,
    };

    this._clock = new Clock({
      endpoint: this._options.endpoint + '/simplentp/sync',
    });

    this._clockSyncInterval = null;
  }

  connect() {
    logger('connecting with', this._options);
    return this._checkAuth()
      .then(() => this._clock.sync())
      .then(() => {
        this._clockSyncInterval = setInterval(
          () => this._clock.sync(),
          this._options.clockSyncInterval
        );
      });
  }

  disconnect() {
    logger('disconnect');
    clearInterval(this._clockSyncInterval);
  }

  getJob(id) {
    const body = {action: 'get', params: {}};
    Object.assign(body.params, {id});

    const url = this._options.endpoint + '/jobs';
    const params = {
      body,
      headers: this._headers,
      json: true
    };

    logger('get job', id);
    return this._send(url, params);
  }

  updateJob(id, diff) {
    const body = {action: 'set', params: {}};
    Object.assign(body.params, diff, {id});

    const url = this._options.endpoint + '/jobs';
    const params = {
      body,
      headers: this._headers,
      json: true
    };

    logger('update job', id);
    return this._send(url, params);
  }

  // send the given payload to the server
  sendData(_payload) {
    const payload = {
      ..._payload,
      host: this._options.hostname
    };

    const url = this._options.endpoint;
    const body = JSON.stringify(payload);
    const params = {
      body,
      headers: this._headers,
    };

    logger(`send data - ${body.substr(0, 50)}...`);
    return this._send(url, params);
  }

  // ping the server to check whether appId and appSecret
  // are valid and correct. Data sent inside http headers.
  _checkAuth() {
    const uri = this._options.endpoint + '/ping';
    const params = {headers: this._headers};
    return this._send(uri, params);
  }

  // communicates with the server with http (using fetch)
  // Also handles response http status codes and  retries
  _send(url, params) {
    return retry(() => {
      return new Promise((resolve, reject) => {
        request.post(url, params, (err, res, body) => {
          if (res.statusCode === 200) {
            return resolve(body);
          }

          if (res.statusCode === 401) {
            logger('Error: Unauthorized');
            return reject(new ByPassRetryError('Unauthorized'));
          }

          if (res.statusCode >= 400 && res.statusCode < 500) {
            const message = `Agent Error: ${res.statusCode}`;
            logger(`Error: ${message}`);
            return reject(new ByPassRetryError(message));
          }

          const message = `Request failed: ${res.statusCode}`;
          logger(`Error: ${message}`);
          reject(new Error(message));
        });
      });
    });
  }
}

export default Kadira;
<commit_msg>Fix request errors<commit_after>import request from 'request';
import Clock from './clock.js';
import retry from './retry.js';
import {ByPassRetryError} from './retry.js';
import debug from 'debug';

const logger = debug('kadira-core:transport');

const DEFAULTS = {
  appId: '',
  appSecret: '',
  endpoint: 'https://enginex.kadira.io',
  hostname: 'localhost',
  clockSyncInterval: 1000 * 60,
  dataFlushInterval: 1000 * 10,
};

// exporting this for if we need to get this as a NPM module.
export class Kadira {
  constructor(_options) {
    this._options = Object.assign({}, DEFAULTS, _options);
    this._headers = {
      'content-type': 'application/json',
      accepts: 'application/json',
      'KADIRA-APP-ID': this._options.appId,
      'KADIRA-APP-SECRET': this._options.appSecret,
    };

    this._clock = new Clock({
      endpoint: this._options.endpoint + '/simplentp/sync',
    });

    this._clockSyncInterval = null;
  }

  connect() {
    logger('connecting with', this._options);
    return this._checkAuth()
      .then(() => this._clock.sync())
      .then(() => {
        this._clockSyncInterval = setInterval(
          () => this._clock.sync(),
          this._options.clockSyncInterval
        );
      });
  }

  disconnect() {
    logger('disconnect');
    clearInterval(this._clockSyncInterval);
  }

  getJob(id) {
    const body = {action: 'get', params: {}};
    Object.assign(body.params, {id});

    const url = this._options.endpoint + '/jobs';
    const params = {
      body,
      headers: this._headers,
      json: true
    };

    logger('get job', id);
    return this._send(url, params);
  }

  updateJob(id, diff) {
    const body = {action: 'set', params: {}};
    Object.assign(body.params, diff, {id});

    const url = this._options.endpoint + '/jobs';
    const params = {
      body,
      headers: this._headers,
      json: true
    };

    logger('update job', id);
    return this._send(url, params);
  }

  // send the given payload to the server
  sendData(_payload) {
    const payload = {
      ..._payload,
      host: this._options.hostname
    };

    const url = this._options.endpoint;
    const body = JSON.stringify(payload);
    const params = {
      body,
      headers: this._headers,
    };

    logger(`send data - ${body.substr(0, 50)}...`);
    return this._send(url, params);
  }

  // ping the server to check whether appId and appSecret
  // are valid and correct. Data sent inside http headers.
  _checkAuth() {
    const uri = this._options.endpoint + '/ping';
    const params = {headers: this._headers};
    return this._send(uri, params);
  }

  // communicates with the server with http (using fetch)
  // Also handles response http status codes and  retries
  _send(url, params) {
    return retry(() => {
      return new Promise((resolve, reject) => {
        request.post(url, params, (err, res, body) => {
          if (err) {
            return reject(err);
          }

          if (res.statusCode === 200) {
            return resolve(body);
          }

          if (res.statusCode === 401) {
            logger('Error: Unauthorized');
            return reject(new ByPassRetryError('Unauthorized'));
          }

          if (res.statusCode >= 400 && res.statusCode < 500) {
            const message = `Agent Error: ${res.statusCode}`;
            logger(`Error: ${message}`);
            return reject(new ByPassRetryError(message));
          }

          const message = `Request failed: ${res.statusCode}`;
          logger(`Error: ${message}`);
          reject(new Error(message));
        });
      });
    });
  }
}

export default Kadira;
<|endoftext|>


<commit_before>const { resolve } = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const InlineManifestWebpackPlugin = require('inline-manifest-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');

module.exports = {
  output: {
    path: resolve(__dirname, './public'),
    filename: '[name].js',
    publicPath: '/',
    chunkFilename: '[id].[chunkhash].js'
  },
  resolve: {
    extensions: ['.js', '.jsx', '.json']
  },
  stats: {
    colors: true,
    reasons: true,
    chunks: true
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
        include: [
          resolve('')
        ]
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'sass-loader']
        })
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
        use: {
          loader: 'url-loader',
          query: {
            name: '[hash].[ext]',
            limit: 10000
          }
        }
      },
      {
        test: /\.(eot|ttf|wav|mp3)$/,
        use: {
          loader: 'file-loader',
          query: {
            name: '[hash].[ext]'
          }
        }
      }
    ]
  },
  plugins: [
    new ProgressBarPlugin(),
    new webpack.NamedModulesPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new ExtractTextPlugin('styles.[name].css'),
    new InlineManifestWebpackPlugin()
  ]
};
<commit_msg>add common webpack config<commit_after>const { resolve } = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const InlineManifestWebpackPlugin = require('inline-manifest-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');

module.exports = {
  // entry: ['./client/index.jsx'],
  output: {
    path: resolve(__dirname, './public'),
    filename: '[name].js',
    publicPath: '/',
    chunkFilename: '[id].[chunkhash].js'
  },
  resolve: {
    extensions: ['.js', '.jsx', '.json']
  },
  stats: {
    colors: true,
    reasons: true,
    chunks: true
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
        include: [
          resolve('')
        ]
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'sass-loader']
        })
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
        use: {
          loader: 'url-loader',
          query: {
            name: '[hash].[ext]',
            limit: 10000
          }
        }
      },
      {
        test: /\.(png|svg|jpg|gif|eot|ttf|wav|mp3)$/,
        use: {
          loader: 'file-loader'
        }
      }
    ]
  },
  plugins: [
    new ProgressBarPlugin(),
    new webpack.NamedModulesPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    new ExtractTextPlugin('styles.[name].css'),
    new InlineManifestWebpackPlugin()
  ]
};
<|endoftext|>


<commit_before>var level = function (game) {
};

level.prototype = {
    name: null,
    config: {},
    keys: {},
    trains: [],
    grid: 32,
    groups: {},
    init: function (config) {
        console.log('level.init');
        this.name = config;
        this.config = {};
        this.keys = {};
        this.trains = [];
    },
    create: function () {
        console.log('level.create');
        this.config.level = this.game.cache.getJSON(this.name);
        this.config.trains = this.game.cache.getJSON('trains');

        this.game.add.image(0, 0, this.config.level.backgroundImage);

        this.game.input.keyboard.addKeyCapture([Phaser.Keyboard.ESC]);
        this.keys.esc = this.game.input.keyboard.addKey(Phaser.Keyboard.ESC);

        this.createTrains();
    },
    createTrains: function () {
        this.groups.trains = this.game.add.group();
        var data;
        for (var i = 0; i < this.config.level.trains.length; i++) {
            data = this.config.level.trains[i];
            this.trains[i] = this.createTrain(data);
        }
        this.game.world.bringToTop(this.groups.trains);
    },
    createTrain: function(data) {
        var train = new Train();
        train.init();
        train.type = data.type;
        this.addWaggons(train, data);
        train.waggonLength = data.waggonLength;
        train.baseSpeed = this.config.trains[train.type].speed;
        train.start.x = data.track[data.waggonLength][0] * this.grid;
        train.start.y = data.track[data.waggonLength][1] * this.grid;
        train.end.x = data.track[data.track.length - 1][0] * this.grid;
        train.end.y = data.track[data.track.length - 1][1] * this.grid;
        train.sprite = this.game.add.sprite(train.start.x, train.start.y, 'tex_train_'+this.config.trains[train.type].image);
        train.sprite.anchor.setTo(0.5, 0.5);
        train.sprite.angle = data.startRotation;
        this.groups.trains.add(train.sprite);
        train.waggons.forEach(function (waggon) {
            this.groups.trains.add(waggon.sprite);
        }.bind(this));
        for (var i = 0; i < data.track.length; i++) {
            var track = data.track[i];
            var sprite = this.game.add.sprite(track[0] * this.grid + (this.grid / 2), track[1] * this.grid + (this.grid / 2), 'tex_rail_'+track[2]);
            sprite.anchor.setTo(0.5, 0.5);
            sprite.angle = track[3];
            train.track.sprites.push(sprite);
            train.track.coords.x.push(sprite.position.x);
            train.track.coords.y.push(sprite.position.y);
            if(i > 1) {
                train.track.coords.a.push(this.game.math.angleBetweenPoints(train.track.sprites[train.track.sprites.length - 2], sprite.position));
            } else {
                train.track.coords.a.push(this.game.math.degToRad(data.startRotation));
            }
        }
        train.incStep(train.waggonLength);
        return train;
    },
    addWaggons: function (train, data) {
        for (var i = 0; i < data.waggonLength; i++) {
            var waggon = new TrainWaggon();
            var startPosition = {
                x: data.track[i][0] * this.grid,
                y: data.track[i][1] * this.grid
            };
            waggon.sprite = this.game.add.sprite(startPosition.x, startPosition.y, 'tex_train_'+this.config.trains[data.type].image);
            waggon.sprite.anchor.setTo(0.5, 0.5);
            waggon.sprite.angle = data.startRotation;
            train.waggons.push(waggon);
        }
    },
    update: function() {
        //console.log('level.update');
        if (this.keys.esc.isDown) {
            this.game.state.clearCurrentState();
            this.game.state.start('Menu');
            return true;
        }

        this.trains.forEach(function(train) {
            train.move();
        });
    }
};
<commit_msg>add basic collision check for trains<commit_after>var level = function (game) {
};

level.prototype = {
    name: null,
    config: {},
    keys: {},
    trains: [],
    grid: 32,
    groups: {},
    init: function (config) {
        console.log('level.init');
        this.name = config;
        this.config = {};
        this.keys = {};
        this.trains = [];
    },
    create: function () {
        console.log('level.create');
        this.config.level = this.game.cache.getJSON(this.name);
        this.config.trains = this.game.cache.getJSON('trains');

        this.game.add.image(0, 0, this.config.level.backgroundImage);

        this.game.input.keyboard.addKeyCapture([Phaser.Keyboard.ESC]);
        this.keys.esc = this.game.input.keyboard.addKey(Phaser.Keyboard.ESC);

        this.createTrains();
    },
    createTrains: function () {
        this.groups.trains = this.game.add.group();
        var data;
        for (var i = 0; i < this.config.level.trains.length; i++) {
            data = this.config.level.trains[i];
            this.trains[i] = this.createTrain(data);
        }
        this.game.world.bringToTop(this.groups.trains);
    },
    createTrain: function(data) {
        var train = new Train();
        train.init();
        train.type = data.type;
        this.addWaggons(train, data);
        train.waggonLength = data.waggonLength;
        train.baseSpeed = this.config.trains[train.type].speed;
        train.start.x = data.track[data.waggonLength][0] * this.grid;
        train.start.y = data.track[data.waggonLength][1] * this.grid;
        train.end.x = data.track[data.track.length - 1][0] * this.grid;
        train.end.y = data.track[data.track.length - 1][1] * this.grid;
        train.sprite = this.game.add.sprite(train.start.x, train.start.y, 'tex_train_'+this.config.trains[train.type].image);
        train.sprite.anchor.setTo(0.5, 0.5);
        train.sprite.angle = data.startRotation;
        this.groups.trains.add(train.sprite);
        train.waggons.forEach(function (waggon) {
            this.groups.trains.add(waggon.sprite);
        }.bind(this));
        for (var i = 0; i < data.track.length; i++) {
            var track = data.track[i];
            var sprite = this.game.add.sprite(track[0] * this.grid + (this.grid / 2), track[1] * this.grid + (this.grid / 2), 'tex_rail_'+track[2]);
            sprite.anchor.setTo(0.5, 0.5);
            sprite.angle = track[3];
            train.track.sprites.push(sprite);
            train.track.coords.x.push(sprite.position.x);
            train.track.coords.y.push(sprite.position.y);
            if(i > 1) {
                train.track.coords.a.push(this.game.math.angleBetweenPoints(train.track.sprites[train.track.sprites.length - 2], sprite.position));
            } else {
                train.track.coords.a.push(this.game.math.degToRad(data.startRotation));
            }
        }
        train.incStep(train.waggonLength);
        return train;
    },
    addWaggons: function (train, data) {
        for (var i = 0; i < data.waggonLength; i++) {
            var waggon = new TrainWaggon();
            var startPosition = {
                x: data.track[i][0] * this.grid,
                y: data.track[i][1] * this.grid
            };
            waggon.sprite = this.game.add.sprite(startPosition.x, startPosition.y, 'tex_train_'+this.config.trains[data.type].image);
            waggon.sprite.anchor.setTo(0.5, 0.5);
            waggon.sprite.angle = data.startRotation;
            train.waggons.push(waggon);
        }
    },
    checkCollisions: function () {
        var trains = this.trains;

        function isIntersecting(spriteA, spriteB) {
            var boundsA = spriteA.getBounds();
            var boundsB = spriteB.getBounds();
            return Phaser.Rectangle.intersects(boundsA, boundsB);
        }

        for (var i = 0; i < trains.length -1; i++) {
            var spritesToCheck = trains[i].getAllSprites();
            for (var j = i+1; j < trains.length; j++) {
                spritesToCheck.some(function (sprite) {
                    if (isIntersecting(sprite, trains[j].sprite)) {
                        trains[i].onCollide(trains[j]);
                        trains[j].onCollide(trains[i]);
                    }
                });
            }
        }
    },
    update: function() {
        //console.log('level.update');
        if (this.keys.esc.isDown) {
            this.game.state.clearCurrentState();
            this.game.state.start('Menu');
            return true;
        }

        this.trains.forEach(function(train) {
            train.move();
        });
        this.checkCollisions();
    }
};
<|endoftext|>


<commit_before>'use strict'

//var roller = require('../lib/node-roll-master/bin/roll')

/** [TO DO] create rollers for:
 *
 * Cortex (multiple pools of die types; highlight best X results - usually 2)
 * Infinity (opposed roll under target # and closest to target # wins; critical if exactly target #)
 * Fate (special die type)
 *
 */

 /** Example dice codes
  *  ==================
  *
  * 3d6,2d8 ...........roll 2 pools of dice and return results
  * 8d10t>8s3..........roll 1 pool of dice and tell me if I get at least 3 dice showing an 8 or higher; return results
  * 7d6s2t>4!..........roll 1 pool of dice and tell me if I get at least 2 dice showing a 4 or higher; explode any dice that roll a 6; return results
  * 5d6b2..............roll 1 pool of dice and highlight the best 2 results
  * 4d6b3=.............roll 4 dice; keep the best 3 and total them
  */

module.exports = (app) => {
  let slapp = app.slapp
  let kv = app.dataStore

  //const fullDiceRegExp = /(\d*)([d](\d*)([\+|\-|\*|\/](\d*)))+/ig
  const diceRegExp = /(\d{1,}d\d{1,})/i            // /((\d*)[d](\d*))+/i
  const fateDiceRegExp = /(\d{1,}df)/i
  const bestOrWorstResultsRegExp = /([b w](\d{1,}))/i
  const successRegExp = /(s\d{1,})/i
  const targetRegExp = /(t[><](\d{1,}))/i
  const modifierRegExp = /([ \+ \- \* \/ ](\d{1,}))/ig
  const addModifierRegExp = /(\+\d{1,})/ig
  const subtractModifierRegExp = /(\-\d{1,})/ig
  const multiplyModifierRegExp = /(\*\d{1,})/ig
  const divideModifierRegExp = /(\/\d{1,})/ig

  const multiplePoolsSeparator = ','
  const explodeSymbol = '!'
  const sumResultsSymbol = '='
  const HighlightNoResults = 0
  const HighlightBestResults = 1
  const HighlightWorstResults = 2
  const contextSymbol = ':'

  const fateDiceSymbol = 'f'

  const MessageContextUser = 0
  const MessageContextCharacter = 1

  const diceRollIcon = 'https://d30y9cdsu7xlg0.cloudfront.net/png/10617-200.png'
  const diceRollMessageColor = '#ffb84d'
  const diceRollUser = 'RpgXDice'

  // Slash Command: ...
  slapp.command('/roll', (msg) => {

    var messageContext = MessageContextUser
    var commandParameters = null
    var command = null

    var results = []
    var rolls = []

    var username = diceRollUser
    var diceRollerName = msg.body.user_name
    var diceRollerThumb = diceRollIcon
    var diceRollerColor = diceRollMessageColor

    //    /(\w*)+[\|]/i

// =============================================================
    // ====  Get message context
    if (msg.body.text.indexOf(contextSymbol) != -1) {
      commandParameters = msg.body.text.split(contextSymbol)
      username = commandParameters[0]
      diceRollerName = commandParameters[0]
      command = commandParameters[1]
      messageContext = MessageContextCharacter
    } else {
      command = msg.body.text
    }

        // Get what dice pools we are rolling
    if (command.indexOf(multiplePoolsSeparator)) {
      rolls = command.split(multiplePoolsSeparator)
    } else {
      rolls.push(command)
    }

    // [DEBUG]
    console.info(`[DEBUG] rolls: ${rolls}`)
    // [TO DO] add error handling. If there are no dice to roll then we need to give feedback to the user and exit

    //
    for (var i = 0; i < rolls.length; i++) {

      // [DEBUG]
      console.log(`roll: ${rolls[i]}`)

      var diceArray = rolls[i].match(diceRegExp)
      var dice = "1d6"
      var quantityArray = null
      var quantity = 1
      var facesArray = null
      var faces = 6

      // [DEBUG]
      console.info(`[DEBUG] diceArray: ${diceArray}`)

      if (diceArray) {
        // [DEBUG]
        console.info(`[DEBUG] diceArray has value...`)

        quantityArray = diceArray[0].match(/^(\d*d)/i)
        if (quantityArray) {
          // [DEBUG]
          console.info(`[DEBUG] quantityArray has value...`)
          quantity = quantityArray[0].match(/^(\d*)/)[0]
        }
        facesArray = diceArray[0].match(/(d\d{1,})/i)
        if (facesArray) {
          // [DEBUG]
          console.info(`[DEBUG] facesArray has value...`)
          faces = facesArray[0].match(/(\d{1,})/)[0]
        }
      }

      // See if we are using the Target number option
      var target = rolls[i].match(targetRegExp)
      if (target) { target = target[0].match(/[(\d*)]+/)[0] }

      // See if we are using the Successes required option
      var successesRequired = rolls[i].match(successRegExp)
      if (successesRequired) { successesRequired = successesRequired[0].match(/[(\d*)]+/)[0] }

      var modifiers = rolls[i].match(modifierRegExp)

      var resultsToHighlight = rolls[i].match(bestOrWorstResultsRegExp)
      var highlightType = HighlightNoResults
      if (resultsToHighlight) {
        if (resultsToHighlight[0].match(/[b]/i)) {
          highlightType = HighlightBestResults
        } else if (resultsToHighlight[0].match(/[w]/i)) {
          highlightType = HighlightWorstResults
        }
      }

      var bTotalResults = false
      if (rolls[i].indexOf(sumResultsSymbol) != -1) { bTotalResults = true }

      results.push(diceRoll(quantity, faces, target, modifiers, successesRequired, bTotalResults))
    }

    // [DEBUG]
      console.info(`[DEBUG] message context: ${messageContext}`)

    if(messageContext == MessageContextCharacter) {

      // [DEBUG]
      console.info(`[DEBUG] message context is CHARACTER`)

      // retrieve npc data if it exists
      kv.get(`${msg.body.user_id}::NPC::${diceRollerName}`, function (err, val) {

        if (!err) {
          if (val) {
            diceRollerThumb = val.thumb
            diceRollerColor = val.color

            // [DEBUG]
            console.info(`thumb: ${val.thumb} | color: ${val.color}`)

            for (var k = 0; k < results.length; k++) {
              //msg.say(`${msg.body.user_name} rolled: ${results[k].quantity}d${results[k].faces} [${results[k].rolls}] (*${results[k].modifiedTotal}*)`)

              // [DEBUG]
              console.info(`diceRollerThumb: ${diceRollerThumb} | diceRollerColor: ${diceRollerColor}`)

              msg.say({
                response_type: 'in_channel',
                username: `${username}   (@${msg.body.user_name})`,
                icon_url: `${diceRollerThumb}`,
                text: '',
                attachments: [{
                  text: `${results[k].quantity}d${results[k].faces} [${results[k].rolls}] (*${results[k].modifiedTotal}*)`,
                  //title: `${diceRollerName} rolled:`,
                  color: `${diceRollerColor}`,
                  mrkdwn_in: ["text", "pretext"],
                  thumb_url: `${diceRollIcon}`
                }]
              })
            }
          }  else {
            console.error(`[ERROR] no value for [${msg.body.user_id}::NPC::${diceRollerName}]`)
          }
        } else {
            // [TO DO] handle error
            console.error(`[ERROR] issue retrieving data for [${msg.body.user_id}::NPC::${diceRollerName}]`)
        }
      })
    } else {
      // [DEBUG]
      console.info(`[DEBUG] message context is USER`)

      for (var k = 0; k < results.length; k++) {
        //msg.say(`${msg.body.user_name} rolled: ${results[k].quantity}d${results[k].faces} [${results[k].rolls}] (*${results[k].modifiedTotal}*)`)

        // [DEBUG]
        console.info(`diceRollerThumb: ${diceRollerThumb} | diceRollerColor: ${diceRollerColor}`)

        msg.say({
          response_type: 'in_channel',
          username: `${username}   (@${msg.body.user_name})`,
          icon_url: `${diceRollerThumb}`,
          text: '',
          attachments: [{
            text: `${results[k].quantity}d${results[k].faces} [${results[k].rolls}] (*${results[k].modifiedTotal}*)`,
            title: `${diceRollerName} rolled:`,
            color: `${diceRollerColor}`,
            mrkdwn_in: ["text", "pretext"],
            thumb_url: `${diceRollIcon}`
          }]
        })
      }
    }
// =============================================================
  })

    // dice stuff was here

    // msg stuff was here

      /** [TO DO]
       * use attachments and message buttons to show/hide roll details
       *
       * use icon to distringuish die rolls: https://d30y9cdsu7xlg0.cloudfront.net/png/10617-200.png
       */

  /**
   *
   * @param {*} quantity
   * @param {*} faces
   * @param {*} target
   * @param {*} modifiers
   * @param {*} successesRequired
   */

  var diceRoll = function (quantity, faces, target, modifiers, successesRequired) {
    var poolResults = {
      quantity: quantity,
      faces: faces,
      modifiers: modifiers,
      modifier: 0,
      target: target,
      successesRequired: successesRequired,
      total: 0,
      modifiedTotal: 0,
      rolls: []
    }

    // [DEBUG]
    console.info(`[DEBUG] modifer list: ${modifiers}`)
    var modifier = 0
    if (modifiers) {
      for (var j = 0; j < modifiers.length; j++) {
        modifier += parseInt(modifiers[j])
        // [DEBUG]
        console.info(`[DEBUG] modifier: ${parseInt(modifiers[j])}`)
      }
      poolResults.modifier = modifier
    }

    // [DEBUG]
    console.info(`[DEBUG] modifier total: ${modifier}`)

    var rollResults = []
    var rollTotal = 0

    for (var i = 0; i < quantity; i++) {
      var roll = Math.floor(Math.random() * faces) + 1
      rollTotal += roll
      rollResults.push(roll)
    }

    poolResults.total = rollTotal;
    poolResults.modifiedTotal = rollTotal + modifier

    /** [TO DO]
     *
     * sum total; if required
     * get best or worst results; if required
     *
    */

    poolResults.rolls = rollResults

    return poolResults
  }
}<commit_msg>tweaking regex<commit_after>'use strict'

//var roller = require('../lib/node-roll-master/bin/roll')

/** [TO DO] create rollers for:
 *
 * Cortex (multiple pools of die types; highlight best X results - usually 2)
 * Infinity (opposed roll under target # and closest to target # wins; critical if exactly target #)
 * Fate (special die type)
 *
 */

 /** Example dice codes
  *  ==================
  *
  * 3d6,2d8 ...........roll 2 pools of dice and return results
  * 8d10t>8s3..........roll 1 pool of dice and tell me if I get at least 3 dice showing an 8 or higher; return results
  * 7d6s2t>4!..........roll 1 pool of dice and tell me if I get at least 2 dice showing a 4 or higher; explode any dice that roll a 6; return results
  * 5d6b2..............roll 1 pool of dice and highlight the best 2 results
  * 4d6b3=.............roll 4 dice; keep the best 3 and total them
  */

module.exports = (app) => {
  let slapp = app.slapp
  let kv = app.dataStore

  //const fullDiceRegExp = /(\d*)([d](\d*)([\+|\-|\*|\/](\d*)))+/ig
  const diceRegExp = /(\d{1,}d\d{1,})/i            // /((\d*)[d](\d*))+/i
  const fateDiceRegExp = /(\d{1,}df)/i
  const bestOrWorstResultsRegExp = /([b w](\d{1,}))/i
  const successRegExp = /(s\d{1,})/i
  const targetRegExp = /(t[><](\d{1,}))/i
  const modifierRegExp = /([ \+ \- \* \/ ](\d{1,}))/ig
  const addModifierRegExp = /(\+\d{1,})/ig
  const subtractModifierRegExp = /(\-\d{1,})/ig
  const multiplyModifierRegExp = /(\*\d{1,})/ig
  const divideModifierRegExp = /(\/\d{1,})/ig

  const multiplePoolsSeparator = ','
  const explodeSymbol = '!'
  const sumResultsSymbol = '='
  const HighlightNoResults = 0
  const HighlightBestResults = 1
  const HighlightWorstResults = 2
  const contextSymbol = ':'

  const fateDiceSymbol = 'f'

  const MessageContextUser = 0
  const MessageContextCharacter = 1

  const diceRollIcon = 'https://d30y9cdsu7xlg0.cloudfront.net/png/10617-200.png'
  const diceRollMessageColor = '#ffb84d'
  const diceRollUser = 'RpgXDice'

  // Slash Command: ...
  slapp.command('/roll', (msg) => {

    var messageContext = MessageContextUser
    var commandParameters = null
    var command = null

    var results = []
    var rolls = []

    var username = diceRollUser
    var diceRollerName = msg.body.user_name
    var diceRollerThumb = diceRollIcon
    var diceRollerColor = diceRollMessageColor

    //    /(\w*)+[\|]/i

// =============================================================
    // ====  Get message context
    if (msg.body.text.indexOf(contextSymbol) != -1) {
      commandParameters = msg.body.text.split(contextSymbol)
      username = commandParameters[0]
      diceRollerName = commandParameters[0]
      command = commandParameters[1]
      messageContext = MessageContextCharacter
    } else {
      command = msg.body.text
    }

        // Get what dice pools we are rolling
    if (command.indexOf(multiplePoolsSeparator)) {
      rolls = command.split(multiplePoolsSeparator)
    } else {
      rolls.push(command)
    }

    // [DEBUG]
    console.info(`[DEBUG] rolls: ${rolls}`)
    // [TO DO] add error handling. If there are no dice to roll then we need to give feedback to the user and exit

    //
    for (var i = 0; i < rolls.length; i++) {

      // [DEBUG]
      console.log(`roll: ${rolls[i]}`)

      var diceArray = rolls[i].match(diceRegExp)
      var dice = "1d6"
      var quantityArray = null
      var quantity = 0
      var facesArray = null
      var faces = 0

      // [DEBUG]
      console.info(`[DEBUG] diceArray: ${diceArray}`)

      if (diceArray) {
        // [DEBUG]
        console.info(`[DEBUG] diceArray has value...`)

        quantityArray = diceArray[0].match(/^(\d{1,}d)/i)
        if (quantityArray) {
          // [DEBUG]
          console.info(`[DEBUG] quantityArray has value...`)
          quantity = quantityArray[0].match(/^(\d{1,})/)[0]
        }
        facesArray = diceArray[0].match(/(d\d{1,})/i)
        if (facesArray) {
          // [DEBUG]
          console.info(`[DEBUG] facesArray has value...`)
          faces = facesArray[0].match(/(\d{1,})/)[0]
        }
      }

      // See if we are using the Target number option
      var target = rolls[i].match(targetRegExp)
      if (target) { target = target[0].match(/[(\d*)]+/)[0] }

      // See if we are using the Successes required option
      var successesRequired = rolls[i].match(successRegExp)
      if (successesRequired) { successesRequired = successesRequired[0].match(/[(\d*)]+/)[0] }

      var modifiers = rolls[i].match(modifierRegExp)

      var resultsToHighlight = rolls[i].match(bestOrWorstResultsRegExp)
      var highlightType = HighlightNoResults
      if (resultsToHighlight) {
        if (resultsToHighlight[0].match(/[b]/i)) {
          highlightType = HighlightBestResults
        } else if (resultsToHighlight[0].match(/[w]/i)) {
          highlightType = HighlightWorstResults
        }
      }

      var bTotalResults = false
      if (rolls[i].indexOf(sumResultsSymbol) != -1) { bTotalResults = true }

      results.push(diceRoll(quantity, faces, target, modifiers, successesRequired, bTotalResults))
    }

    // [DEBUG]
      console.info(`[DEBUG] message context: ${messageContext}`)

    if(messageContext == MessageContextCharacter) {

      // [DEBUG]
      console.info(`[DEBUG] message context is CHARACTER`)

      // retrieve npc data if it exists
      kv.get(`${msg.body.user_id}::NPC::${diceRollerName}`, function (err, val) {

        if (!err) {
          if (val) {
            diceRollerThumb = val.thumb
            diceRollerColor = val.color

            // [DEBUG]
            console.info(`thumb: ${val.thumb} | color: ${val.color}`)

            for (var k = 0; k < results.length; k++) {
              //msg.say(`${msg.body.user_name} rolled: ${results[k].quantity}d${results[k].faces} [${results[k].rolls}] (*${results[k].modifiedTotal}*)`)

              // [DEBUG]
              console.info(`diceRollerThumb: ${diceRollerThumb} | diceRollerColor: ${diceRollerColor}`)

              msg.say({
                response_type: 'in_channel',
                username: `${username}   (@${msg.body.user_name})`,
                icon_url: `${diceRollerThumb}`,
                text: '',
                attachments: [{
                  text: `${results[k].quantity}d${results[k].faces} [${results[k].rolls}] (*${results[k].modifiedTotal}*)`,
                  //title: `${diceRollerName} rolled:`,
                  color: `${diceRollerColor}`,
                  mrkdwn_in: ["text", "pretext"],
                  thumb_url: `${diceRollIcon}`
                }]
              })
            }
          }  else {
            console.error(`[ERROR] no value for [${msg.body.user_id}::NPC::${diceRollerName}]`)
          }
        } else {
            // [TO DO] handle error
            console.error(`[ERROR] issue retrieving data for [${msg.body.user_id}::NPC::${diceRollerName}]`)
        }
      })
    } else {
      // [DEBUG]
      console.info(`[DEBUG] message context is USER`)

      for (var k = 0; k < results.length; k++) {
        //msg.say(`${msg.body.user_name} rolled: ${results[k].quantity}d${results[k].faces} [${results[k].rolls}] (*${results[k].modifiedTotal}*)`)

        // [DEBUG]
        console.info(`diceRollerThumb: ${diceRollerThumb} | diceRollerColor: ${diceRollerColor}`)

        msg.say({
          response_type: 'in_channel',
          username: `${username}   (@${msg.body.user_name})`,
          icon_url: `${diceRollerThumb}`,
          text: '',
          attachments: [{
            text: `${results[k].quantity}d${results[k].faces} [${results[k].rolls}] (*${results[k].modifiedTotal}*)`,
            title: `${diceRollerName} rolled:`,
            color: `${diceRollerColor}`,
            mrkdwn_in: ["text", "pretext"],
            thumb_url: `${diceRollIcon}`
          }]
        })
      }
    }
// =============================================================
  })

    // dice stuff was here

    // msg stuff was here

      /** [TO DO]
       * use attachments and message buttons to show/hide roll details
       *
       * use icon to distringuish die rolls: https://d30y9cdsu7xlg0.cloudfront.net/png/10617-200.png
       */

  /**
   *
   * @param {*} quantity
   * @param {*} faces
   * @param {*} target
   * @param {*} modifiers
   * @param {*} successesRequired
   */

  var diceRoll = function (quantity, faces, target, modifiers, successesRequired) {
    var poolResults = {
      quantity: quantity,
      faces: faces,
      modifiers: modifiers,
      modifier: 0,
      target: target,
      successesRequired: successesRequired,
      total: 0,
      modifiedTotal: 0,
      rolls: []
    }

    // [DEBUG]
    console.info(`[DEBUG] modifer list: ${modifiers}`)
    var modifier = 0
    if (modifiers) {
      for (var j = 0; j < modifiers.length; j++) {
        modifier += parseInt(modifiers[j])
        // [DEBUG]
        console.info(`[DEBUG] modifier: ${parseInt(modifiers[j])}`)
      }
      poolResults.modifier = modifier
    }

    // [DEBUG]
    console.info(`[DEBUG] modifier total: ${modifier}`)

    var rollResults = []
    var rollTotal = 0

    for (var i = 0; i < quantity; i++) {
      var roll = Math.floor(Math.random() * faces) + 1
      rollTotal += roll
      rollResults.push(roll)
    }

    poolResults.total = rollTotal;
    poolResults.modifiedTotal = rollTotal + modifier

    /** [TO DO]
     *
     * sum total; if required
     * get best or worst results; if required
     *
    */

    poolResults.rolls = rollResults

    return poolResults
  }
}<|endoftext|>


<commit_before>/**
 * @module tmpl
 *
 * tmpl          - Root function, returns the template value, render with data
 * tmpl.hasExpr  - Test the existence of a expression inside a string
 * tmpl.loopKeys - Get the keys for an 'each' loop (used by `_each`)
 */
//#if 0 // only in the unprocessed source
/* eslint no-unused-vars: [2, {args: "after-used", varsIgnorePattern: "tmpl"}] */
/* global brackets, riot */
//#endif
//#define LIST_GETTERS 0

// IIFE for tmpl()
//#if ES6
export
//#endif
var tmpl = (function () {
  //
  // Closure data
  // --------------------------------------------------------------------------
  var _cache = {}

  //
  // Runtime Functions
  // --------------------------------------------------------------------------

  /**
   * The exposed tmpl function returns the template value from the cache, render with data.
   *
   * @param   {string} str  - Expression or template with zero or more expressions
   * @param   {Object} data - A Tag instance, for setting the context
   * @returns {*} Raw value of the expression or template to render
   * @private
   */
  function _tmpl (str, data) {
    if (!str) return str  // catch falsy values here

    //#if DEBUG
    /*eslint no-console: 0 */
    if (data && data._debug_) {
      data._debug_ = 0
      if (!_cache[str]) {
        _cache[str] = _create(str, 1)  // request debug output
        var rs = typeof riot === 'undefined'
          ? '(riot undefined)' : JSON.stringify(riot.settings)

        console.log('--- DEBUG' +
          '\n riot.settings: ' + rs + '\n data: ' + JSON.stringify(data))
      }
    }
    //#endif

    // At this point, the expressions must have been parsed, it only remains to construct
    // the function (if it is not in the cache) and call it to replace expressions with
    // their values. data (`this`) is a Tag instance, _logErr is the error handler.

    return (_cache[str] || (_cache[str] = _create(str))).call(data, _logErr)
  }

  /**
   * Checks for an expression within a string, using the current brackets.
   *
   * @param   {string } str - String where to search
   * @returns {boolean} `true` if the string contains an expression.
   * @function
   */
  _tmpl.hasExpr = brackets.hasExpr

  /**
   * Parses the `each` expression to detect how to map the collection data to the
   * children tags. Used by riot browser/tag/each.js
   *
   * {key, i in items} -> { key, pos, val }
   *
   * @param   {String} expr - string passed in the 'each' attribute
   * @returns {Object} The object needed to check how the items in the collection
   *   should be mapped to the children tags.
   * @function
   */
  _tmpl.loopKeys = brackets.loopKeys

  /**
   * Clears the internal cache of compiled expressions.
   *
   * @function
   */
  // istanbul ignore next
  _tmpl.clearCache = function () { _cache = {} }

  /**
   * Holds a custom function to handle evaluation errors.
   *
   * This property allows to detect errors _in the evaluation_, by setting its value to a
   * function that receives the generated Error object, augmented with an object `riotData`
   * containing the properties `tagName` and `_riot_id` of the context at error time.
   *
   * Other (usually fatal) errors, such as "Parse Error" generated by the Function
   * constructor, are not intercepted.
   *
   * If this property is not set, or set to falsy, as in previous versions the error
   * is silently ignored.
   *
   * @type {function}
   * @static
   */
  _tmpl.errorHandler = null

  /**
   * Output an error message through the `_tmpl.errorHandler` function and
   * the console object.
   * @param {Error}  err - The Error instance generated by the exception
   * @param {object} ctx - The context
   * @private
   */
  function _logErr (err, ctx) {
    // add some data to the Error object
    err.riotData = {
      tagName: ctx && ctx.__ && ctx.__.tagName,
      _riot_id: ctx && ctx._riot_id  //eslint-disable-line camelcase
    }

    // user error handler
    if (_tmpl.errorHandler) _tmpl.errorHandler(err)
    else if (
      typeof console !== 'undefined' &&
      typeof console.error === 'function'
    ) {
      if (err.riotData.tagName) {
        console.error('Riot template error thrown in the <%s> tag', err.riotData.tagName)
      }
      console.error(err)
    }
  }

  /**
   * Creates a function instance to get a value from the received template string.
   *
   * It'll halt the app if the expression has errors (Parse Error or SyntaxError).
   *
   * @param {string} str - The template. Can include zero or more expressions
   * @returns {Function} An instance of Function with the compiled template.
   * @private
   */
  function _create (str) {
    var expr = _getTmpl(str)

    if (expr.slice(0, 11) !== 'try{return ') expr = 'return ' + expr

//#if DEBUG
    if (arguments.length > 1) console.log('--- getter:\n    `' + expr + '`\n---')
//#elif LIST_GETTERS
    //console.log(' In: `%s`\nOUT: `%s`', str, expr)
//#endif
/*#if CSP
    return safeEval.func('E', expr + ';')
//#else */
    // Now, we can create the function to return by calling the Function constructor.
    // The parameter `E` is the error handler for runtime only.
    return new Function('E', expr + ';')    // eslint-disable-line no-new-func
//#endif
  }

  //
  // Compilation
  // --------------------------------------------------------------------------

  // Regexes for `_getTmpl` and `_parseExpr`
  var
    CH_IDEXPR = String.fromCharCode(0x2057),
    RE_CSNAME = /^(?:(-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*)|\u2057(\d+)~):/,
    RE_QBLOCK = RegExp(brackets.S_QBLOCKS, 'g'),
    RE_DQUOTE = /\u2057/g,
    RE_QBMARK = /\u2057(\d+)~/g     // string or regex marker, $1: array index

  /**
   * Parses an expression or template with zero or more expressions enclosed with
   * the current brackets.
   *
   * @param   {string} str - Raw template string, without comments
   * @returns {string} Processed template, ready for evaluation.
   * @private
   */
  function _getTmpl (str) {
    var
      qstr = [],                      // hidden qblocks
      expr,
      parts = brackets.split(str.replace(RE_DQUOTE, '"'), 1)  // get text/expr parts

    // We can have almost anything as expressions, except comments... hope
    if (parts.length > 2 || parts[0]) {
      var i, j, list = []

      for (i = j = 0; i < parts.length; ++i) {

        expr = parts[i]

        if (expr && (expr = i & 1               // every odd element is an expression

            ? _parseExpr(expr, 1, qstr)         // mode 1 convert falsy values to "",
                                                // except zero
            : '"' + expr                        // ttext: convert to js literal string
                .replace(/\\/g, '\\\\')         // this is html, preserve backslashes
                .replace(/\r\n?|\n/g, '\\n')    // normalize eols
                .replace(/"/g, '\\"') +         // escape inner double quotes
              '"'                               // enclose in double quotes

          )) list[j++] = expr

      }

      expr = j < 2 ? list[0]                    // optimize code for 0-1 parts
           : '[' + list.join(',') + '].join("")'

    } else {

      expr = _parseExpr(parts[1], 0, qstr)      // single expressions as raw value
    }

    // Restore quoted strings and regexes
    if (qstr[0]) {
      expr = expr.replace(RE_QBMARK, function (_, pos) {
        return qstr[pos]
          .replace(/\r/g, '\\r')
          .replace(/\n/g, '\\n')
      })
    }
    return expr
  }

  var
    RE_BREND = {
      '(': /[()]/g,
      '[': /[[\]]/g,
      '{': /[{}]/g
    }

  /**
   * Parses an individual expression `{expression}` or shorthand `{name: expression, ...}`
   *
   * For shorthand names, riot supports a limited subset of the full w3c/html specs of
   * non-quoted identifiers (closer to CSS1 that CSS2).
   *
   * The regex used for recognition is `-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*`.
   *
   * This regex accepts almost all ISO-8859-1 alphanumeric characters within an html
   * identifier. Doesn't works with escaped codepoints, but you can use Unicode code points
   * beyond `\u00FF` by quoting the names (not recommended).
   *
   * @param   {string} expr   - The expression, without brackets
   * @param   {number} asText - 0: raw value, 1: falsy as "", except 0
   * @param   {Array}  qstr   - Where to store hidden quoted strings and regexes
   * @returns {string} Code to evaluate the expression.
   * @see {@link http://www.w3.org/TR/CSS21/grammar.html#scanner}
   *      {@link http://www.w3.org/TR/CSS21/syndata.html#tokenization}
   * @private
   */
  function _parseExpr (expr, asText, qstr) {

    // Replace non-empty qstrings with a marker that includes its index into the array
    // of replaced qstrings (by hiding regexes and strings here we avoid complications
    // through all the code without affecting the logic).
    //
    // Also, converts whitespace into compacted spaces and trims surrounding spaces
    // and some inner tokens, mainly brackets and separators.
    // We need convert embedded `\r` and `\n` as these chars break the evaluation.
    //
    // WARNING:
    //   Trim and compact is not strictly necessary, but it allows optimized regexes.
    //   Do not touch the next block until you know how/which regexes are affected.

    expr = expr
          .replace(RE_QBLOCK, function (s, div) {   // hide strings & regexes
            return s.length > 2 && !div ? CH_IDEXPR + (qstr.push(s) - 1) + '~' : s
          })
          .replace(/\s+/g, ' ').trim()
          .replace(/\ ?([[\({},?\.:])\ ?/g, '$1')

    if (expr) {
      var
        list = [],
        cnt = 0,
        match

      // Try to match the first name in the possible shorthand list
      while (expr &&
            (match = expr.match(RE_CSNAME)) &&
            !match.index                          // index > 0 means error
        ) {
        var
          key,
          jsb,
          re = /,|([[{(])|$/g

        // Search the next unbracketed comma or the end of 'expr'.
        // If a openning js bracket is found ($1), skip the block,
        // if found the end of expr $1 will be empty and the while loop exits.

        expr = RegExp.rightContext                // before replace
        key  = match[2] ? qstr[match[2]].slice(1, -1).trim().replace(/\s+/g, ' ') : match[1]

        while (jsb = (match = re.exec(expr))[1]) skipBraces(jsb, re)

        jsb  = expr.slice(0, match.index)
        expr = RegExp.rightContext

        list[cnt++] = _wrapExpr(jsb, 1, key)
      }

      // For shorthands, the generated code returns an array with expression-name pairs
      expr = !cnt ? _wrapExpr(expr, asText)
           : cnt > 1 ? '[' + list.join(',') + '].join(" ").trim()' : list[0]
    }
    return expr

    // Skip bracketed block, uses the str value in the closure
    function skipBraces (ch, re) {
      var
        mm,
        lv = 1,
        ir = RE_BREND[ch]

      ir.lastIndex = re.lastIndex
      while (mm = ir.exec(expr)) {
        if (mm[0] === ch) ++lv
        else if (!--lv) break
      }
      re.lastIndex = lv ? expr.length : ir.lastIndex
    }
  }

  // Matches a varname, excludes object keys. $1: lookahead, $2: variable name
  // istanbul ignore next: not both
  var // eslint-disable-next-line max-len
    JS_CONTEXT = '"in this?this:' + (typeof window !== 'object' ? 'global' : 'window') + ').',
    JS_VARNAME = /[,{][\$\w]+(?=:)|(^ *|[^$\w\.{])(?!(?:typeof|true|false|null|undefined|in|instanceof|is(?:Finite|NaN)|void|NaN|new|Date|RegExp|Math)(?![$\w]))([$_A-Za-z][$\w]*)/g,
    JS_NOPROPS = /^(?=(\.[$\w]+))\1(?:[^.[(]|$)/

  /**
   * Generates code to evaluate an expression avoiding breaking on undefined vars.
   *
   * This function include a try..catch block only if needed, if this block is not included,
   * the generated code has no return statement.
   *
   * This `isFinite`, `isNaN`, `Date`, `RegExp`, and `Math` keywords are not wrapped
   * for context detection (defaults to the global object).
   *
   * @param   {string}  expr   - Normalized expression, without brackets
   * @param   {boolean} asText - If trueish, the output is converted to text, not raw values
   * @param   {string}  [key]  - For shorthands, the key name
   * @returns {string}  Compiled expression.
   * @private
   */
  function _wrapExpr (expr, asText, key) {
    var tb

    expr = expr.replace(JS_VARNAME, function (match, p, mvar, pos, s) {
      if (mvar) {
        pos = tb ? 0 : pos + match.length         // check only if needed

        // this, window, and global needs try block too
        if (mvar !== 'this' && mvar !== 'global' && mvar !== 'window') {
          match = p + '("' + mvar + JS_CONTEXT + mvar
          if (pos) tb = (s = s[pos]) === '.' || s === '(' || s === '['
        } else if (pos) {
          tb = !JS_NOPROPS.test(s.slice(pos))     // needs try..catch block?
        }
      }
      return match
    })

    if (tb) {
      expr = 'try{return ' + expr + '}catch(e){E(e,this)}'
    }

    if (key) {  // shorthands
      // w/try : function(){try{return expr}catch(e){E(e,this)}}.call(this)?"name":""
      // no try: (expr)?"name":""
      // ==> 'return [' + expr_list.join(',') + '].join(" ").trim()'
      expr = (tb
          ? 'function(){' + expr + '}.call(this)' : '(' + expr + ')'
        ) + '?"' + key + '":""'

    } else if (asText) {
      // w/try : function(v){try{v=expr}catch(e){E(e,this)};return v||v===0?v:""}.call(this)
      // no try: function(v){return (v=(expr))||v===0?v:""}.call(this)
      // ==> 'return [' + text_and_expr_list.join(',') + '].join("")'
      expr = 'function(v){' + (tb
          ? expr.replace('return ', 'v=') : 'v=(' + expr + ')'
        ) + ';return v||v===0?v:""}.call(this)'
    }
    // else if (!asText)
    //  no try: return expr
    //  w/try : try{return expr}catch(e){E(e,this)}   // returns undefined if error

    return expr
  }

  //#if !NODE
  _tmpl.version = brackets.version = 'WIP'
  //#endif

  return _tmpl

})()
<commit_msg>Log which expression broken along with data<commit_after>/**
 * @module tmpl
 *
 * tmpl          - Root function, returns the template value, render with data
 * tmpl.hasExpr  - Test the existence of a expression inside a string
 * tmpl.loopKeys - Get the keys for an 'each' loop (used by `_each`)
 */
//#if 0 // only in the unprocessed source
/* eslint no-unused-vars: [2, {args: "after-used", varsIgnorePattern: "tmpl"}] */
/* global brackets, riot */
//#endif
//#define LIST_GETTERS 0

// IIFE for tmpl()
//#if ES6
export
//#endif
var tmpl = (function () {
  //
  // Closure data
  // --------------------------------------------------------------------------
  var _cache = {}

  //
  // Runtime Functions
  // --------------------------------------------------------------------------

  /**
   * The exposed tmpl function returns the template value from the cache, render with data.
   *
   * @param   {string} str  - Expression or template with zero or more expressions
   * @param   {Object} data - A Tag instance, for setting the context
   * @returns {*} Raw value of the expression or template to render
   * @private
   */
  function _tmpl (str, data) {
    if (!str) return str  // catch falsy values here

    //#if DEBUG
    /*eslint no-console: 0 */
    if (data && data._debug_) {
      data._debug_ = 0
      if (!_cache[str]) {
        _cache[str] = _create(str, 1)  // request debug output
        var rs = typeof riot === 'undefined'
          ? '(riot undefined)' : JSON.stringify(riot.settings)

        console.log('--- DEBUG' +
          '\n riot.settings: ' + rs + '\n data: ' + JSON.stringify(data))
      }
    }
    //#endif

    // At this point, the expressions must have been parsed, it only remains to construct
    // the function (if it is not in the cache) and call it to replace expressions with
    // their values. data (`this`) is a Tag instance, _logErr is the error handler.

    return (_cache[str] || (_cache[str] = _create(str))).call(
      data, _logErr.bind({
        data: data,
        tmpl: str
      })
    )
  }

  /**
   * Checks for an expression within a string, using the current brackets.
   *
   * @param   {string } str - String where to search
   * @returns {boolean} `true` if the string contains an expression.
   * @function
   */
  _tmpl.hasExpr = brackets.hasExpr

  /**
   * Parses the `each` expression to detect how to map the collection data to the
   * children tags. Used by riot browser/tag/each.js
   *
   * {key, i in items} -> { key, pos, val }
   *
   * @param   {String} expr - string passed in the 'each' attribute
   * @returns {Object} The object needed to check how the items in the collection
   *   should be mapped to the children tags.
   * @function
   */
  _tmpl.loopKeys = brackets.loopKeys

  /**
   * Clears the internal cache of compiled expressions.
   *
   * @function
   */
  // istanbul ignore next
  _tmpl.clearCache = function () { _cache = {} }

  /**
   * Holds a custom function to handle evaluation errors.
   *
   * This property allows to detect errors _in the evaluation_, by setting its value to a
   * function that receives the generated Error object, augmented with an object `riotData`
   * containing the properties `tagName` and `_riot_id` of the context at error time.
   *
   * Other (usually fatal) errors, such as "Parse Error" generated by the Function
   * constructor, are not intercepted.
   *
   * If this property is not set, or set to falsy, as in previous versions the error
   * is silently ignored.
   *
   * @type {function}
   * @static
   */
  _tmpl.errorHandler = null

  /**
   * Output an error message through the `_tmpl.errorHandler` function and
   * the console object.
   * @param {Error}  err - The Error instance generated by the exception
   * @param {object} ctx - The context
   * @private
   */
  function _logErr (err, ctx) {
    // add some data to the Error object
    err.riotData = {
      tagName: ctx && ctx.__ && ctx.__.tagName,
      _riot_id: ctx && ctx._riot_id  //eslint-disable-line camelcase
    }

    // user error handler
    if (_tmpl.errorHandler) _tmpl.errorHandler(err)
    else if (
      typeof console !== 'undefined' &&
      typeof console.error === 'function'
    ) {
      console.error(err.message)
      console.log('<%s> %s', err.riotData.tagName || 'Unknown tag', this.tmpl) // eslint-disable-line
      console.log(this.data) // eslint-disable-line
    }
  }

  /**
   * Creates a function instance to get a value from the received template string.
   *
   * It'll halt the app if the expression has errors (Parse Error or SyntaxError).
   *
   * @param {string} str - The template. Can include zero or more expressions
   * @returns {Function} An instance of Function with the compiled template.
   * @private
   */
  function _create (str) {
    var expr = _getTmpl(str)

    if (expr.slice(0, 11) !== 'try{return ') expr = 'return ' + expr

//#if DEBUG
    if (arguments.length > 1) console.log('--- getter:\n    `' + expr + '`\n---')
//#elif LIST_GETTERS
    //console.log(' In: `%s`\nOUT: `%s`', str, expr)
//#endif
/*#if CSP
    return safeEval.func('E', expr + ';')
//#else */
    // Now, we can create the function to return by calling the Function constructor.
    // The parameter `E` is the error handler for runtime only.
    return new Function('E', expr + ';')    // eslint-disable-line no-new-func
//#endif
  }

  //
  // Compilation
  // --------------------------------------------------------------------------

  // Regexes for `_getTmpl` and `_parseExpr`
  var
    CH_IDEXPR = String.fromCharCode(0x2057),
    RE_CSNAME = /^(?:(-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*)|\u2057(\d+)~):/,
    RE_QBLOCK = RegExp(brackets.S_QBLOCKS, 'g'),
    RE_DQUOTE = /\u2057/g,
    RE_QBMARK = /\u2057(\d+)~/g     // string or regex marker, $1: array index

  /**
   * Parses an expression or template with zero or more expressions enclosed with
   * the current brackets.
   *
   * @param   {string} str - Raw template string, without comments
   * @returns {string} Processed template, ready for evaluation.
   * @private
   */
  function _getTmpl (str) {
    var
      qstr = [],                      // hidden qblocks
      expr,
      parts = brackets.split(str.replace(RE_DQUOTE, '"'), 1)  // get text/expr parts

    // We can have almost anything as expressions, except comments... hope
    if (parts.length > 2 || parts[0]) {
      var i, j, list = []

      for (i = j = 0; i < parts.length; ++i) {

        expr = parts[i]

        if (expr && (expr = i & 1               // every odd element is an expression

            ? _parseExpr(expr, 1, qstr)         // mode 1 convert falsy values to "",
                                                // except zero
            : '"' + expr                        // ttext: convert to js literal string
                .replace(/\\/g, '\\\\')         // this is html, preserve backslashes
                .replace(/\r\n?|\n/g, '\\n')    // normalize eols
                .replace(/"/g, '\\"') +         // escape inner double quotes
              '"'                               // enclose in double quotes

          )) list[j++] = expr

      }

      expr = j < 2 ? list[0]                    // optimize code for 0-1 parts
           : '[' + list.join(',') + '].join("")'

    } else {

      expr = _parseExpr(parts[1], 0, qstr)      // single expressions as raw value
    }

    // Restore quoted strings and regexes
    if (qstr[0]) {
      expr = expr.replace(RE_QBMARK, function (_, pos) {
        return qstr[pos]
          .replace(/\r/g, '\\r')
          .replace(/\n/g, '\\n')
      })
    }
    return expr
  }

  var
    RE_BREND = {
      '(': /[()]/g,
      '[': /[[\]]/g,
      '{': /[{}]/g
    }

  /**
   * Parses an individual expression `{expression}` or shorthand `{name: expression, ...}`
   *
   * For shorthand names, riot supports a limited subset of the full w3c/html specs of
   * non-quoted identifiers (closer to CSS1 that CSS2).
   *
   * The regex used for recognition is `-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*`.
   *
   * This regex accepts almost all ISO-8859-1 alphanumeric characters within an html
   * identifier. Doesn't works with escaped codepoints, but you can use Unicode code points
   * beyond `\u00FF` by quoting the names (not recommended).
   *
   * @param   {string} expr   - The expression, without brackets
   * @param   {number} asText - 0: raw value, 1: falsy as "", except 0
   * @param   {Array}  qstr   - Where to store hidden quoted strings and regexes
   * @returns {string} Code to evaluate the expression.
   * @see {@link http://www.w3.org/TR/CSS21/grammar.html#scanner}
   *      {@link http://www.w3.org/TR/CSS21/syndata.html#tokenization}
   * @private
   */
  function _parseExpr (expr, asText, qstr) {

    // Replace non-empty qstrings with a marker that includes its index into the array
    // of replaced qstrings (by hiding regexes and strings here we avoid complications
    // through all the code without affecting the logic).
    //
    // Also, converts whitespace into compacted spaces and trims surrounding spaces
    // and some inner tokens, mainly brackets and separators.
    // We need convert embedded `\r` and `\n` as these chars break the evaluation.
    //
    // WARNING:
    //   Trim and compact is not strictly necessary, but it allows optimized regexes.
    //   Do not touch the next block until you know how/which regexes are affected.

    expr = expr
          .replace(RE_QBLOCK, function (s, div) {   // hide strings & regexes
            return s.length > 2 && !div ? CH_IDEXPR + (qstr.push(s) - 1) + '~' : s
          })
          .replace(/\s+/g, ' ').trim()
          .replace(/\ ?([[\({},?\.:])\ ?/g, '$1')

    if (expr) {
      var
        list = [],
        cnt = 0,
        match

      // Try to match the first name in the possible shorthand list
      while (expr &&
            (match = expr.match(RE_CSNAME)) &&
            !match.index                          // index > 0 means error
        ) {
        var
          key,
          jsb,
          re = /,|([[{(])|$/g

        // Search the next unbracketed comma or the end of 'expr'.
        // If a openning js bracket is found ($1), skip the block,
        // if found the end of expr $1 will be empty and the while loop exits.

        expr = RegExp.rightContext                // before replace
        key  = match[2] ? qstr[match[2]].slice(1, -1).trim().replace(/\s+/g, ' ') : match[1]

        while (jsb = (match = re.exec(expr))[1]) skipBraces(jsb, re)

        jsb  = expr.slice(0, match.index)
        expr = RegExp.rightContext

        list[cnt++] = _wrapExpr(jsb, 1, key)
      }

      // For shorthands, the generated code returns an array with expression-name pairs
      expr = !cnt ? _wrapExpr(expr, asText)
           : cnt > 1 ? '[' + list.join(',') + '].join(" ").trim()' : list[0]
    }
    return expr

    // Skip bracketed block, uses the str value in the closure
    function skipBraces (ch, re) {
      var
        mm,
        lv = 1,
        ir = RE_BREND[ch]

      ir.lastIndex = re.lastIndex
      while (mm = ir.exec(expr)) {
        if (mm[0] === ch) ++lv
        else if (!--lv) break
      }
      re.lastIndex = lv ? expr.length : ir.lastIndex
    }
  }

  // Matches a varname, excludes object keys. $1: lookahead, $2: variable name
  // istanbul ignore next: not both
  var // eslint-disable-next-line max-len
    JS_CONTEXT = '"in this?this:' + (typeof window !== 'object' ? 'global' : 'window') + ').',
    JS_VARNAME = /[,{][\$\w]+(?=:)|(^ *|[^$\w\.{])(?!(?:typeof|true|false|null|undefined|in|instanceof|is(?:Finite|NaN)|void|NaN|new|Date|RegExp|Math)(?![$\w]))([$_A-Za-z][$\w]*)/g,
    JS_NOPROPS = /^(?=(\.[$\w]+))\1(?:[^.[(]|$)/

  /**
   * Generates code to evaluate an expression avoiding breaking on undefined vars.
   *
   * This function include a try..catch block only if needed, if this block is not included,
   * the generated code has no return statement.
   *
   * This `isFinite`, `isNaN`, `Date`, `RegExp`, and `Math` keywords are not wrapped
   * for context detection (defaults to the global object).
   *
   * @param   {string}  expr   - Normalized expression, without brackets
   * @param   {boolean} asText - If trueish, the output is converted to text, not raw values
   * @param   {string}  [key]  - For shorthands, the key name
   * @returns {string}  Compiled expression.
   * @private
   */
  function _wrapExpr (expr, asText, key) {
    var tb

    expr = expr.replace(JS_VARNAME, function (match, p, mvar, pos, s) {
      if (mvar) {
        pos = tb ? 0 : pos + match.length         // check only if needed

        // this, window, and global needs try block too
        if (mvar !== 'this' && mvar !== 'global' && mvar !== 'window') {
          match = p + '("' + mvar + JS_CONTEXT + mvar
          if (pos) tb = (s = s[pos]) === '.' || s === '(' || s === '['
        } else if (pos) {
          tb = !JS_NOPROPS.test(s.slice(pos))     // needs try..catch block?
        }
      }
      return match
    })

    if (tb) {
      expr = 'try{return ' + expr + '}catch(e){E(e,this)}'
    }

    if (key) {  // shorthands
      // w/try : function(){try{return expr}catch(e){E(e,this)}}.call(this)?"name":""
      // no try: (expr)?"name":""
      // ==> 'return [' + expr_list.join(',') + '].join(" ").trim()'
      expr = (tb
          ? 'function(){' + expr + '}.call(this)' : '(' + expr + ')'
        ) + '?"' + key + '":""'

    } else if (asText) {
      // w/try : function(v){try{v=expr}catch(e){E(e,this)};return v||v===0?v:""}.call(this)
      // no try: function(v){return (v=(expr))||v===0?v:""}.call(this)
      // ==> 'return [' + text_and_expr_list.join(',') + '].join("")'
      expr = 'function(v){' + (tb
          ? expr.replace('return ', 'v=') : 'v=(' + expr + ')'
        ) + ';return v||v===0?v:""}.call(this)'
    }
    // else if (!asText)
    //  no try: return expr
    //  w/try : try{return expr}catch(e){E(e,this)}   // returns undefined if error

    return expr
  }

  //#if !NODE
  _tmpl.version = brackets.version = 'WIP'
  //#endif

  return _tmpl

})()
<|endoftext|>


<commit_before>function transformState(activity, lastBuildStatus) {
    var state = '';
    if (lastBuildStatus == 'Success') {
        state = 'healthy';
    } else if (lastBuildStatus == 'Failure') {
        state = 'sick';
    } else if (lastBuildStatus == 'Sleeping') {
        state = 'waiting';
    } else if (lastBuildStatus == 'Unknown') {
        state = 'unknown';
    }
    if ((state == 'unknown') && activity == "Building") {
        state = 'healthy-building';
    } else if ((state != 'unknown') && activity == "Building") {
        state = state + '-building';
    }
    return state;
}

function updateCache(pipelines, hiddenPrefix, defautHiddenSteps, cache, asynCall) {
    $.each(pipelines, function(pipelineName, pipeline) {
        var hiddenSteps = pipeline['hiddenSteps'];
        var cctrayUrl = pipeline['cctrayUrl'];
        var guiURL = pipeline['guiUrl'];
        var guiURL = pipeline['visibleWaitingSteps'];
        $.ajax({
                    type: 'GET',
                    url: cctrayUrl,
                    success: function (response) {
                        var newProjectCache = new Array();
                        $(response).find('Project').each(function (project) {
                            var name = $(this).attr('name');
                            var activity = $(this).attr('activity');
                            var lastBuildStatus = $(this).attr('lastBuildStatus');
                            var newState = transformState(activity, lastBuildStatus);
                            var cacheEntry = [];
                            //var keyName = pipeline['displayName'] + '-' + name;
                            cacheEntry['stepName'] = name;
                            cacheEntry['pipelineName'] = pipelineName;
                            cacheEntry['state'] = newState;
                            cacheEntry['visible'] = ($.inArray(name, hiddenSteps) == -1) &&
                                                    ($.inArray(name, defautHiddenSteps) == -1) &&
                                                    !(name.startsWith(hiddenPrefix)) &&
                                                    ($.inArray(name, visibleWaitingSteps) != -1);
                            cacheEntry['guiURL'] = guiURL;
                            newProjectCache.push(cacheEntry);
                        });
                        cache[pipelineName] = newProjectCache;
                    },
                    error: function (response) {
                        var newProjectCache = new Array();
                        var cacheEntry = [];
                        cacheEntry['stepName'] = '';
                        cacheEntry['pipelineName'] = pipelineName;
                        cacheEntry['state'] = 'sick';
                        cacheEntry['visible'] = true;
                        cacheEntry['guiURL'] = guiURL;
                        newProjectCache.push(cacheEntry);
                        cache[pipelineName] = newProjectCache;
                    }
                    ,
                    dataType: 'xml',
                    crossDomain: true,
                    async: asynCall
                }
        )
        ;
    });
}<commit_msg>fix state transformation<commit_after>function transformState(activity, lastBuildStatus) {
    var state = '';
    if (lastBuildStatus == 'Success') {
        state = 'healthy';
    } else if (lastBuildStatus == 'Failure') {
        state = 'sick';
    } else if (activity == 'Sleeping') {
        state = 'waiting';
    } else if (lastBuildStatus == 'Unknown') {
        state = 'unknown';
    }
    if ((state == 'unknown') && activity == "Building") {
        state = 'healthy-building';
    } else if ((state != 'unknown') && activity == "Building") {
        state = state + '-building';
    }
    return state;
}

function updateCache(pipelines, hiddenPrefix, defautHiddenSteps, cache, asynCall) {
    $.each(pipelines, function(pipelineName, pipeline) {
        var hiddenSteps = pipeline['hiddenSteps'];
        var cctrayUrl = pipeline['cctrayUrl'];
        var guiURL = pipeline['guiUrl'];
        var guiURL = pipeline['visibleWaitingSteps'];
        $.ajax({
                    type: 'GET',
                    url: cctrayUrl,
                    success: function (response) {
                        var newProjectCache = new Array();
                        $(response).find('Project').each(function (project) {
                            var name = $(this).attr('name');
                            var activity = $(this).attr('activity');
                            var lastBuildStatus = $(this).attr('lastBuildStatus');
                            var newState = transformState(activity, lastBuildStatus);
                            var cacheEntry = [];
                            //var keyName = pipeline['displayName'] + '-' + name;
                            cacheEntry['stepName'] = name;
                            cacheEntry['pipelineName'] = pipelineName;
                            cacheEntry['state'] = newState;
                            cacheEntry['visible'] = ($.inArray(name, hiddenSteps) == -1) &&
                                                    ($.inArray(name, defautHiddenSteps) == -1) &&
                                                    !(name.startsWith(hiddenPrefix)) &&
                                                    ($.inArray(name, visibleWaitingSteps) != -1);
                            cacheEntry['guiURL'] = guiURL;
                            newProjectCache.push(cacheEntry);
                        });
                        cache[pipelineName] = newProjectCache;
                    },
                    error: function (response) {
                        var newProjectCache = new Array();
                        var cacheEntry = [];
                        cacheEntry['stepName'] = '';
                        cacheEntry['pipelineName'] = pipelineName;
                        cacheEntry['state'] = 'sick';
                        cacheEntry['visible'] = true;
                        cacheEntry['guiURL'] = guiURL;
                        newProjectCache.push(cacheEntry);
                        cache[pipelineName] = newProjectCache;
                    }
                    ,
                    dataType: 'xml',
                    crossDomain: true,
                    async: asynCall
                }
        )
        ;
    });
}<|endoftext|>


<commit_before>'use strict'

void (function () {
  const remote = require('remote')
  const Tray = remote.require('tray')
  const Menu = remote.require('menu')
  const MenuItem = remote.require('menu-item')
  const dialog = remote.require('dialog')
  const ipc = require('ipc')
  const grunt = require('./lib/Grunt')

  // Set up tray menu.
  let tray = new Tray('grunt.png')
  let trayMenu = new Menu()

  build()

  function build () {
    trayMenu.append(new MenuItem({
      label: window.localStorage.getItem('current'),
      click: function () {
        dialog.showOpenDialog({ properties: ['openDirectory']}, function (dir) {
          if (dir !== undefined) {
            window.localStorage.setItem('current', dir)
            // Rebuild menu
            trayMenu = new Menu()
            build()
          }
        })
      }
    }))

    trayMenu.append(new MenuItem({type: 'separator'}))

    grunt.getTasks()
      .then(function (tasks) {
        for (let task of tasks) {
          let item = {
            label: task,
            type: 'checkbox',
            click: function () {
              grunt.runTask(task, function () {
                // Rebuild menu
                trayMenu = new Menu()
                build()
              })
            }
          }

          if (global.processes[task]) {
            item.checked = true
          }

          trayMenu.append(new MenuItem(item))
        }

        trayMenu.append(new MenuItem({type: 'separator'}))

        trayMenu.append(new MenuItem({
          label: 'Quit',
          click: function () {
            ipc.send('app-quit')
          }
        }))

        tray.setContextMenu(trayMenu)
      })
  }
})()
<commit_msg>fixed path<commit_after>'use strict'

void (function () {
  const remote = require('remote')
  const Tray = remote.require('tray')
  const Menu = remote.require('menu')
  const MenuItem = remote.require('menu-item')
  const dialog = remote.require('dialog')
  const ipc = require('ipc')
  const grunt = require('./lib/Grunt')

  // Set up tray menu.
  let tray = new Tray(__dirname + '/grunt.png')
  let trayMenu = new Menu()

  build()

  function build () {
    trayMenu.append(new MenuItem({
      label: window.localStorage.getItem('current'),
      click: function () {
        dialog.showOpenDialog({ properties: ['openDirectory']}, function (dir) {
          if (dir !== undefined) {
            window.localStorage.setItem('current', dir)
            // Rebuild menu
            trayMenu = new Menu()
            build()
          }
        })
      }
    }))

    trayMenu.append(new MenuItem({type: 'separator'}))

    grunt.getTasks()
      .then(function (tasks) {
        for (let task of tasks) {
          let item = {
            label: task,
            type: 'checkbox',
            click: function () {
              grunt.runTask(task, function () {
                // Rebuild menu
                trayMenu = new Menu()
                build()
              })
            }
          }

          if (global.processes[task]) {
            item.checked = true
          }

          trayMenu.append(new MenuItem(item))
        }

        trayMenu.append(new MenuItem({type: 'separator'}))

        trayMenu.append(new MenuItem({
          label: 'Quit',
          click: function () {
            ipc.send('app-quit')
          }
        }))

        tray.setContextMenu(trayMenu)
      })
  }
})()
<|endoftext|>


<commit_before>var grid = grid || {};

grid.Cell = Backbone.Model.extend({
  defaults: function() {
    return {
      value: '',
      row: '',
      column: '',
      group: '',
      possible: [1,2,3,4,5,6,7,8,9],
    }
  },
});

grid.CellCollection = Backbone.Collection.extend({
  model: grid.Cell
});

grid.CellView = Backbone.View.extend({
  tagName: 'td',
  template: _.template($('#cell-template').html()),
  events: {
    'click ': 'toggleSelected',
  },

  initialize: function() {
    this.listenTo(this.model, 'change', this.render);
  },

  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    this.input = this.$('.edit');
    return this;
  },

  toggleSelected: function() {
    console.info('clicked on: ' + this.model.get('row') + ',' + this.model.get('column'));
  },
});

grid.AppView = Backbone.View.extend({
  el: '#gridapp',

  initialize: function() {
    var rowTemplate = _.template('<tr id="grid_row_<%= row %>">
');
    this.cells = new grid.CellCollection();
    var cells = this.cells;
    _.times(9, function(row) {
      $('#grid').append(rowTemplate({row: row}));
      _.times(9, function(column) {
        var cell = new grid.Cell({
          row: row,
          column: column,
          group: (Math.floor(column / 3)) + (Math.floor(row / 3) * 3),
        });
        cells.add(cell);
        var view = new grid.CellView({model: cell});
        $('#grid_row_' + row).append(view.render().el);
      });
    });
  },
});

$(function() {
  App = new grid.AppView();
});
<commit_msg>cell selection<commit_after>var grid = grid || {};

grid.Cell = Backbone.Model.extend({
  defaults: function() {
    return {
      value: '',
      row: '',
      column: '',
      group: '',
      selected: false,
      possible: [1,2,3,4,5,6,7,8,9],
    }
  },
});

grid.CellCollection = Backbone.Collection.extend({
  model: grid.Cell
});

grid.CellView = Backbone.View.extend({
  tagName: 'td',
  template: _.template($('#cell-template').html()),
  events: {
    'click ': 'select',
  },

  initialize: function() {
    this.listenTo(this.model, 'change', this.render);
  },

  render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    if (this.model.get('selected')) {
      this.$el.addClass('selected');
    } else {
      this.$el.removeClass('selected');
    }
    return this;
  },

  select: function() {
    App.cells.forEach(function(cell) {
      cell.set('selected', false)
    });
    this.model.set('selected', true);
  },
});

grid.AppView = Backbone.View.extend({
  el: '#gridapp',

  initialize: function() {
    var rowTemplate = _.template('<tr id="grid_row_<%= row %>">
');
    this.cells = new grid.CellCollection();
    var cells = this.cells;
    _.times(9, function(row) {
      $('#grid').append(rowTemplate({row: row}));
      _.times(9, function(column) {
        var cell = new grid.Cell({
          row: row,
          column: column,
          group: (Math.floor(column / 3)) + (Math.floor(row / 3) * 3),
        });
        cells.add(cell);
        var view = new grid.CellView({model: cell});
        $('#grid_row_' + row).append(view.render().el);
      });
    });
  },
});

$(function() {
  App = new grid.AppView();
});
<|endoftext|>