<commit_before>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

// Import Style
import styles from './App.css';
import { createStyleSheet, createStyleManager } from 'jss-theme-reactor';;
import { create as createJss } from 'jss';
import preset from 'jss-preset-default';

// Import Components
import Helmet from 'react-helmet';
import customPropTypes from 'material-ui/utils/customPropTypes';
import DevTools from './components/DevTools';
import Header from './components/Header/Header';
import Footer from './components/Footer/Footer';
import ButtonAppBar from './components/ButtonAppBar/ButtonAppBar';
import Search from './components/Search/Search';
import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid';

// Import Actions
import { toggleAddPost, fetchCurrentUser } from './AppActions';
import { switchLanguage } from '../../modules/Intl/IntlActions';
import ImageDialog from '../Results/components/ImageDialog/ImageDialog';

// Creating style sheet
const styleSheet = createStyleSheet('InteractiveGrid', () => {
  return {
    root: {
      flexGrow: 1,
      marginTop: '30px',
    },
    demo: {
      height: 240,
    },
    paper: {
      padding: 12,
      height: '100%',
    },
    control: {
      padding: 12,
    },
  };
});

export class App extends Component {
  constructor(props, context) {
    super(props);
    this.state = { isMounted: false,
                   isAuthenticated: false,
                   user: undefined};

    this.styleManager = createStyleManager({
        jss: createJss(preset()),
        theme: props.theme,
      });

  }

  componentDidMount() {
    this.setState({isMounted: true}); // eslint-disable-line

  }

  toggleAddPostSection = () => {
    this.props.dispatch(toggleAddPost());

  };

  render() {
      let classes = this.styleManager.render(styleSheet);

    return (

        {this.state.isMounted && !window.devToolsExtension && process.env.NODE_ENV === 'development' && <DevTools />}
          <Helmet
            title="Sim Meme"
            titleTemplate="%s - Sim Meme"
            meta={[
              { charset: 'utf-8' },
              {
                'http-equiv': 'X-UA-Compatible',
                content: 'IE=edge',
              },
              {
                name: 'viewport',
                content: 'width=device-width, initial-scale=1',
              },
            ]}
          />
          <ImageDialog/>
          <ButtonAppBar isAuthenticated={this.props.isAuthenticated} user={this.props.user} dispatch={this.props.dispatch}/>
          <Grid container className={classes.root} justify='center'>
            <Grid item xs={10}>
              <Search />
            </Grid>
          </Grid>
            {this.props.children}

    );
  }
}

// App.contextTypes = {
//   //styleManager: customPropTypes.muiRequired,
// };

App.propTypes = {
  children: PropTypes.object.isRequired,
  dispatch: PropTypes.func.isRequired,
  intl: PropTypes.object.isRequired,
  user: PropTypes.object,
  isAuthenticated: PropTypes.bool,

};

// Retrieve data from store as props
function mapStateToProps(store) {
  return {
    intl: store.intl,
    isAuthenticated: store.app.isAuthenticated,
    user: store.app.user,
  };
}

export default connect(mapStateToProps)(App);

//  this.props.dispatch(switchLanguage(lang))}
//   intl={this.props.intl}
//   toggleAddPost={this.toggleAddPostSection}
// />
<commit_msg>xMerge branch 'master' of https://github.com/eantler/simmeme-client<commit_after>import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

// Import Style
import styles from './App.css';
import { createStyleSheet, createStyleManager } from 'jss-theme-reactor';;
import { create as createJss } from 'jss';
import preset from 'jss-preset-default';

// Import Components
import Helmet from 'react-helmet';
import DevTools from './components/DevTools';
import Header from './components/Header/Header';
import Footer from './components/Footer/Footer';
import ButtonAppBar from './components/ButtonAppBar/ButtonAppBar';
import Search from './components/Search/Search';
import Paper from 'material-ui/Paper';
import Grid from 'material-ui/Grid';

// Import Actions
import { toggleAddPost, fetchCurrentUser } from './AppActions';
import { switchLanguage } from '../../modules/Intl/IntlActions';
import ImageDialog from '../Results/components/ImageDialog/ImageDialog';

// Creating style sheet
const styleSheet = createStyleSheet('InteractiveGrid', () => {
  return {
    root: {
      flexGrow: 1,
      marginTop: '30px',
    },
    demo: {
      height: 240,
    },
    paper: {
      padding: 12,
      height: '100%',
    },
    control: {
      padding: 12,
    },
  };
});

export class App extends Component {
  constructor(props, context) {
    super(props);
    this.state = { isMounted: false,
                   isAuthenticated: false,
                   user: undefined};

    this.styleManager = createStyleManager({
        jss: createJss(preset()),
        theme: props.theme,
      });

  }

  componentDidMount() {
    this.setState({isMounted: true}); // eslint-disable-line

  }

  toggleAddPostSection = () => {
    this.props.dispatch(toggleAddPost());

  };

  render() {
      let classes = this.styleManager.render(styleSheet);

    return (

        {this.state.isMounted && !window.devToolsExtension && process.env.NODE_ENV === 'development' && <DevTools />}
          <Helmet
            title="Sim Meme"
            titleTemplate="%s - Sim Meme"
            meta={[
              { charset: 'utf-8' },
              {
                'http-equiv': 'X-UA-Compatible',
                content: 'IE=edge',
              },
              {
                name: 'viewport',
                content: 'width=device-width, initial-scale=1',
              },
            ]}
          />
          <ImageDialog/>
          <ButtonAppBar isAuthenticated={this.props.isAuthenticated} user={this.props.user} dispatch={this.props.dispatch}/>
          <Grid container className={classes.root} justify='center'>
            <Grid item xs={10}>
              <Search />
            </Grid>
          </Grid>
            {this.props.children}

    );
  }
}

// App.contextTypes = {
//   //styleManager: customPropTypes.muiRequired,
// };

App.propTypes = {
  children: PropTypes.object.isRequired,
  dispatch: PropTypes.func.isRequired,
  intl: PropTypes.object.isRequired,
  user: PropTypes.object,
  isAuthenticated: PropTypes.bool,

};

// Retrieve data from store as props
function mapStateToProps(store) {
  return {
    intl: store.intl,
    isAuthenticated: store.app.isAuthenticated,
    user: store.app.user,
  };
}

export default connect(mapStateToProps)(App);

//  this.props.dispatch(switchLanguage(lang))}
//   intl={this.props.intl}
//   toggleAddPost={this.toggleAddPostSection}
// />
<|endoftext|>


<commit_before>import React from 'react';
import { render } from 'react-testing-library';

import Alert from './Alert';

describe('Alert component', () => {
    const text = 'Panda';
    const learnMoreText = 'Learn more';
    const { container } = render(<Alert learnMore="https://protonmail.com">{text}</Alert>);
    const { firstChild } = container;

    it('renders children and should contain "Learn more" link', () => {
        expect(firstChild.textContent).toBe(`${text}${learnMoreText}`);
    });

    it('has default class', () => {
        expect(firstChild).toHaveClass('block-info');
    });

    it('should have error class for warning type', () => {
        const { container } = render(<Alert type="warning">{text}</Alert>);
        expect(container.firstChild).toHaveClass('block-info-error');
    });
});
<commit_msg>Fix failing tests<commit_after>import React from 'react';
import { render } from 'react-testing-library';

import Alert from './Alert';

describe('Alert component', () => {
    const text = 'Panda';
    const learnMoreText = 'Learn more';
    const { container } = render(<Alert learnMore="https://protonmail.com">{text}</Alert>);
    const { firstChild } = container;

    it('renders children and should contain "Learn more" link', () => {
        expect(firstChild.textContent).toBe(`${text}${learnMoreText}`);
    });

    it('has default class', () => {
        expect(firstChild).toHaveClass('mb1 block-info-standard');
    });

    it('should have error class for warning type', () => {
        const { container } = render(<Alert type="warning">{text}</Alert>);
        expect(container.firstChild).toHaveClass('mb1 block-info-standard-warning');
    });
});
<|endoftext|>


<commit_before>var get = Ember.get;

require("ember-data/system/model/model");

DS.Model.reopenClass({
  attributes: Ember.computed(function() {
    var map = Ember.Map.create();

    this.eachComputedProperty(function(name, meta) {
      if (meta.isAttribute) {
        Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + this.toString(), name !== 'id');

        meta.name = name;
        map.set(name, meta);
      }
    });

    return map;
  })
});

var AttributeChange = DS.AttributeChange = function(options) {
  this.reference = options.reference;
  this.store = options.store;
  this.name = options.name;
  this.oldValue = options.oldValue;
};

AttributeChange.createChange = function(options) {
  return new AttributeChange(options);
};

AttributeChange.prototype = {
  sync: function() {
    this.store.recordAttributeDidChange(this.reference, this.name, this.value, this.oldValue);

    // TODO: Use this object in the commit process
    this.destroy();
  },

  destroy: function() {
    delete this.store.recordForReference(this.reference)._changesToSync[this.name];
  }
};

DS.Model.reopen({
  eachAttribute: function(callback, binding) {
    get(this.constructor, 'attributes').forEach(function(name, meta) {
      callback.call(binding, name, meta);
    }, binding);
  },

  attributeWillChange: Ember.beforeObserver(function(record, key) {
    var reference = get(record, '_reference'),
        store = get(record, 'store');

    record.send('willSetProperty', { reference: reference, store: store, name: key });
  }),

  attributeDidChange: Ember.observer(function(record, key) {
    record.send('didSetProperty', { name: key });
  })
});

function getAttr(record, options, key) {
  var attributes = get(record, 'data').attributes;
  var value = attributes[key];

  if (value === undefined) {
    value = options.defaultValue;
  }

  return value;
}

DS.attr = function(type, options) {
  options = options || {};

  var meta = {
    type: type,
    isAttribute: true,
    options: options
  };

  return Ember.computed(function(key, value, oldValue) {
    var data;

    if (arguments.length > 1) {
      Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + this.constructor.toString(), key !== 'id');
    } else {
      value = getAttr(this, options, key);
    }

    return value;
  // `data` is never set directly. However, it may be
  // invalidated from the state manager's setData
  // event.
  }).property('data').meta(meta);
};

<commit_msg>Remove unused var declaration<commit_after>var get = Ember.get;

require("ember-data/system/model/model");

DS.Model.reopenClass({
  attributes: Ember.computed(function() {
    var map = Ember.Map.create();

    this.eachComputedProperty(function(name, meta) {
      if (meta.isAttribute) {
        Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + this.toString(), name !== 'id');

        meta.name = name;
        map.set(name, meta);
      }
    });

    return map;
  })
});

var AttributeChange = DS.AttributeChange = function(options) {
  this.reference = options.reference;
  this.store = options.store;
  this.name = options.name;
  this.oldValue = options.oldValue;
};

AttributeChange.createChange = function(options) {
  return new AttributeChange(options);
};

AttributeChange.prototype = {
  sync: function() {
    this.store.recordAttributeDidChange(this.reference, this.name, this.value, this.oldValue);

    // TODO: Use this object in the commit process
    this.destroy();
  },

  destroy: function() {
    delete this.store.recordForReference(this.reference)._changesToSync[this.name];
  }
};

DS.Model.reopen({
  eachAttribute: function(callback, binding) {
    get(this.constructor, 'attributes').forEach(function(name, meta) {
      callback.call(binding, name, meta);
    }, binding);
  },

  attributeWillChange: Ember.beforeObserver(function(record, key) {
    var reference = get(record, '_reference'),
        store = get(record, 'store');

    record.send('willSetProperty', { reference: reference, store: store, name: key });
  }),

  attributeDidChange: Ember.observer(function(record, key) {
    record.send('didSetProperty', { name: key });
  })
});

function getAttr(record, options, key) {
  var attributes = get(record, 'data').attributes;
  var value = attributes[key];

  if (value === undefined) {
    value = options.defaultValue;
  }

  return value;
}

DS.attr = function(type, options) {
  options = options || {};

  var meta = {
    type: type,
    isAttribute: true,
    options: options
  };

  return Ember.computed(function(key, value, oldValue) {
    if (arguments.length > 1) {
      Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('<type>')` from " + this.constructor.toString(), key !== 'id');
    } else {
      value = getAttr(this, options, key);
    }

    return value;
  // `data` is never set directly. However, it may be
  // invalidated from the state manager's setData
  // event.
  }).property('data').meta(meta);
};

<|endoftext|>


<commit_before>var playing;
var round;

function rand(max) {
	return Math.floor(Math.random() * max);
}

document.querySelector('#play').onclick = function () {
	var tbody = document.querySelector('tbody');
	for (var i = tbody.rows.length - 1; i >= 0; i--) {
		var name = tbody.rows[i].cells[1].firstChild.value;
		if (!name) {
			tbody.rows[i].remove();
		} else {
			tbody.rows[i].cells[1].textContent = name;
		}
	}
	playing = rand(tbody.rows.length);
	document.querySelector('tbody').rows[playing].cells[0].textContent = '➜';
	document.querySelector('table').rows[0].cells[0].textContent = '';
	play();
	document.querySelector('#play').onclick = roll;
};

document.querySelector('#dices').onclick = function (event) {
	if (round != 3 && event.target.tagName == 'A') {
		event.target.classList.toggle('unpinned');
	}
}

document.querySelector('table').onclick = function (event) {
	if (getComputedStyle(event.target).cursor == 'pointer') {
		var picked = document.querySelector('.picked');
		if (picked) {
			picked.classList.remove('picked');
		}
		event.target.classList.add('picked');
		setUnpinned(event.target);
	}
};

function diceValue(dice) {
	return dice.textContent.charCodeAt(0) - '⚀'.charCodeAt(0) + 1;
}

function setUnpinned(td) {
	var index = Array.from(td.parentElement.children).indexOf(td);
	var kind = document.querySelector('table').rows[0].cells[index].textContent;
	switch (kind) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
			var dices = document.querySelectorAll('#dices a');
			for (var i=0; i < dices.length; i++) {
				dices[i].classList.toggle('unpinned', diceValue(dices[i]) != kind);
			}
			return;
		case 'MŘ': return setUnpinnedSet(new Set([1, 2, 3, 4, 5]));
		case 'VŘ': return setUnpinnedSet(new Set([2, 3, 4, 5, 6]));
		case '3+2': return setUnpinnedMin(3);
		case '4+1': return setUnpinnedMin(4);
	}
}

function setUnpinnedSet(need) {
	var dices = document.querySelectorAll('#dices a');
	for (var i=0; i < dices.length; i++) {
		dices[i].classList.toggle('unpinned', !need.delete(diceValue(dices[i])));
	}
	if (round == 3 && need.size) {
		for (var i=0; i < dices.length; i++) {
			dices[i].classList.add('unpinned');
		}
	}
}

function setUnpinnedMin(min) {
	var dices = document.querySelectorAll('#dices a');
	var counts = {};
	for (var i=0; i < dices.length; i++) {
		counts[diceValue(dices[i])] = (counts[diceValue(dices[i])] || 0) + 1;
	}
	var values = Object.values(counts);
	if (round == 3) {
		var pinned = (values.length == 1 || values.length == 2 && (values[0] == min || values[1] == min));
		for (var i=0; i < dices.length; i++) {
			dices[i].classList.toggle('unpinned', !pinned);
		}
	} else {
		for (var i=0; i < dices.length; i++) {
			dices[i].classList.toggle('unpinned', counts[diceValue(dices[i])] < min - 1 || min == 4 && values.length == 1 && i == dices.length - 1);
		}
	}
}

function play() {
	var dices = document.querySelectorAll('#dices a');
	for (var i=0; i < dices.length; i++) {
		dices[i].classList.add('unpinned');
	}
	round = 0;
	document.querySelector('tbody').rows[playing].classList.add('playing');
	roll();
}

function roll() {
	var unpinned = document.querySelectorAll('#dices a.unpinned');
	var picked = document.querySelector('.picked');
	if (round == 3 || picked && !unpinned.length) {
		if (round < 3) {
			compute();
		}
		play();
	} else if (!unpinned.length) {
		alert('Vyberte kostky, kterými chcete hodit.');
	} else if (round == 2 && !picked) {
		alert('Vyberte kombinaci, kterou chcete hodit.');
	} else {
		for (var i=0; i < unpinned.length; i++) {
			unpinned[i].textContent = String.fromCharCode('⚀'.charCodeAt(0) + rand(6));
			unpinned[i].classList.remove('unpinned');
			unpinned[i].style.transform = 'rotate(' + (Math.random() * 30 - 15) + 'deg)';
		}
		round++;
		if (picked) {
			setUnpinned(picked);
		}
		if (round == 3) {
			compute();
		}
	}
}

function compute() {
	var dices = document.querySelectorAll('#dices a');
	var score = 0;
	for (var i = 0; i < dices.length; i++) {
		if (!dices[i].classList.contains('unpinned')) {
			score += diceValue(dices[i]);
		}
	}
	document.querySelector('.picked').textContent += score;
	var total = document.querySelector('.playing th:last-child');
	total.textContent = +total.textContent + score;
	document.querySelector('.picked').classList.add('played');
	document.querySelector('.picked').classList.remove('picked');
	document.querySelector('.playing').classList.remove('playing');
	document.querySelector('tbody').rows[playing].cells[0].textContent = '';
	playing = (playing + 1) % document.querySelector('tbody').rows.length;
	var row = document.querySelector('tbody').rows[playing];
	if (row.querySelectorAll('td.played').length == row.querySelectorAll('td').length) {
		end();
	} else {
		document.querySelector('tbody').rows[playing].cells[0].textContent = '➜';
	}
}

function end() {
	document.querySelector('#play').remove();
	var rows = document.querySelector('tbody').rows;
	var max = 0;
	for (var i = 0; i < rows.length; i++) {
		max = Math.max(max, rows[i].cells[rows[i].cells.length - 1].textContent);
	}
	for (var i = 0; i < rows.length; i++) {
		if (max == rows[i].cells[rows[i].cells.length - 1].textContent) {
			document.querySelector('tbody').rows[i].cells[0].textContent = '➜';
		}
	}
}
<commit_msg>Vrchcaby: Recompute pinning without unpinned<commit_after>var playing;
var round;

function rand(max) {
	return Math.floor(Math.random() * max);
}

document.querySelector('#play').onclick = function () {
	var tbody = document.querySelector('tbody');
	for (var i = tbody.rows.length - 1; i >= 0; i--) {
		var name = tbody.rows[i].cells[1].firstChild.value;
		if (!name) {
			tbody.rows[i].remove();
		} else {
			tbody.rows[i].cells[1].textContent = name;
		}
	}
	playing = rand(tbody.rows.length);
	document.querySelector('tbody').rows[playing].cells[0].textContent = '➜';
	document.querySelector('table').rows[0].cells[0].textContent = '';
	play();
	document.querySelector('#play').onclick = roll;
};

document.querySelector('#dices').onclick = function (event) {
	if (round != 3 && event.target.tagName == 'A') {
		event.target.classList.toggle('unpinned');
	}
}

document.querySelector('table').onclick = function (event) {
	if (getComputedStyle(event.target).cursor == 'pointer') {
		var picked = document.querySelector('.picked');
		if (picked) {
			picked.classList.remove('picked');
		}
		event.target.classList.add('picked');
		setUnpinned(event.target);
	}
};

function diceValue(dice) {
	return dice.textContent.charCodeAt(0) - '⚀'.charCodeAt(0) + 1;
}

function setUnpinned(td) {
	var index = Array.from(td.parentElement.children).indexOf(td);
	var kind = document.querySelector('table').rows[0].cells[index].textContent;
	switch (kind) {
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
			var dices = document.querySelectorAll('#dices a');
			for (var i=0; i < dices.length; i++) {
				dices[i].classList.toggle('unpinned', diceValue(dices[i]) != kind);
			}
			return;
		case 'MŘ': return setUnpinnedSet(new Set([1, 2, 3, 4, 5]));
		case 'VŘ': return setUnpinnedSet(new Set([2, 3, 4, 5, 6]));
		case '3+2': return setUnpinnedMin(3);
		case '4+1': return setUnpinnedMin(4);
	}
}

function setUnpinnedSet(need) {
	var dices = document.querySelectorAll('#dices a');
	for (var i=0; i < dices.length; i++) {
		dices[i].classList.toggle('unpinned', !need.delete(diceValue(dices[i])));
	}
	if (round == 3 && need.size) {
		for (var i=0; i < dices.length; i++) {
			dices[i].classList.add('unpinned');
		}
	}
}

function setUnpinnedMin(min) {
	var dices = document.querySelectorAll('#dices a');
	var counts = {};
	for (var i=0; i < dices.length; i++) {
		counts[diceValue(dices[i])] = (counts[diceValue(dices[i])] || 0) + 1;
	}
	var values = Object.values(counts);
	if (round == 3) {
		var pinned = (values.length == 1 || values.length == 2 && (values[0] == min || values[1] == min));
		for (var i=0; i < dices.length; i++) {
			dices[i].classList.toggle('unpinned', !pinned);
		}
	} else {
		for (var i=0; i < dices.length; i++) {
			dices[i].classList.toggle('unpinned', counts[diceValue(dices[i])] < min - 1 || min == 4 && values.length == 1 && i == dices.length - 1);
		}
	}
}

function play() {
	var dices = document.querySelectorAll('#dices a');
	for (var i=0; i < dices.length; i++) {
		dices[i].classList.add('unpinned');
	}
	round = 0;
	document.querySelector('tbody').rows[playing].classList.add('playing');
	roll();
}

function roll() {
	var unpinned = document.querySelectorAll('#dices a.unpinned');
	var picked = document.querySelector('.picked');
	if (round == 3 || picked && !unpinned.length) {
		if (round < 3) {
			round = 3;
			setUnpinned(picked);
			compute();
		}
		play();
	} else if (!unpinned.length) {
		alert('Vyberte kostky, kterými chcete hodit.');
	} else if (round == 2 && !picked) {
		alert('Vyberte kombinaci, kterou chcete hodit.');
	} else {
		for (var i=0; i < unpinned.length; i++) {
			unpinned[i].textContent = String.fromCharCode('⚀'.charCodeAt(0) + rand(6));
			unpinned[i].classList.remove('unpinned');
			unpinned[i].style.transform = 'rotate(' + (Math.random() * 30 - 15) + 'deg)';
		}
		round++;
		if (picked) {
			setUnpinned(picked);
		}
		if (round == 3) {
			compute();
		}
	}
}

function compute() {
	var dices = document.querySelectorAll('#dices a');
	var score = 0;
	for (var i = 0; i < dices.length; i++) {
		if (!dices[i].classList.contains('unpinned')) {
			score += diceValue(dices[i]);
		}
	}
	document.querySelector('.picked').textContent += score;
	var total = document.querySelector('.playing th:last-child');
	total.textContent = +total.textContent + score;
	document.querySelector('.picked').classList.add('played');
	document.querySelector('.picked').classList.remove('picked');
	document.querySelector('.playing').classList.remove('playing');
	document.querySelector('tbody').rows[playing].cells[0].textContent = '';
	playing = (playing + 1) % document.querySelector('tbody').rows.length;
	var row = document.querySelector('tbody').rows[playing];
	if (row.querySelectorAll('td.played').length == row.querySelectorAll('td').length) {
		end();
	} else {
		document.querySelector('tbody').rows[playing].cells[0].textContent = '➜';
	}
}

function end() {
	document.querySelector('#play').remove();
	var rows = document.querySelector('tbody').rows;
	var max = 0;
	for (var i = 0; i < rows.length; i++) {
		max = Math.max(max, rows[i].cells[rows[i].cells.length - 1].textContent);
	}
	for (var i = 0; i < rows.length; i++) {
		if (max == rows[i].cells[rows[i].cells.length - 1].textContent) {
			document.querySelector('tbody').rows[i].cells[0].textContent = '➜';
		}
	}
}
<|endoftext|>


<commit_before>function Action() {
    this.connect();
}

Action.prototype.connect = function() {
    this.semaphore = new SemaphoreMock();
    this.initObservers();
    this.semaphore.connect();
    this.street = "";
};

Action.prototype.disconnect = function() {
    navigator.vibrate(0); // cancel vibration
    this.semaphore.disconnect();
    document.location.href = 'index.html';
};

Action.prototype.tapScreen = function() {

    var that = this;

    util.doubleTapHandler(function(isDoubleTap) {
        if (isDoubleTap) {
            util.playSound('res/audios/disconnected.mp3', 2);
            that.disconnect();
        } else {
            if (that.isStreetShowing()) {
                that.hideStreetName();
            } else {
                that.showStreetName();
            }
        }
    });
};

Action.prototype.isStreetShowing = function() {
    return document.getElementById("extraInfoDiv").style.display === 'block';
};

Action.prototype.showStreetName = function() {

    var that = this;

    var onStartVoice = function() {
        document.getElementById("signsDiv").style.display = 'none';
        document.getElementById("extraInfoDiv").style.display = 'block';
        document.getElementById("streetName").textContent = that.streetName;

        console.log(document.getElementById("audio").duration);

        audio.addEventListener('loadedmetadata', function() {
            setTimeout(function() {
                that.hideStreetName();
            }, Math.round(util.getCurrentSoundDuration()) * 1000);
        });
    };

    switch (this.streetName) {
        case 'Av. Brasil':
            util.playSound('res/audios/av_brasil.mp3', 1, onStartVoice);
            break;
        case 'Av. Nove de Abril':
            util.playSound('res/audios/av_nove_abril.mp3', 1, onStartVoice);
            break;
        case 'Av. Pe. Jaime':
            util.playSound('res/audios/av_pe_jaime.mp3', 1, onStartVoice);
            break;
    };
};

Action.prototype.hideStreetName = function() {
    document.getElementById("signsDiv").style.display = 'block';
    document.getElementById("extraInfoDiv").style.display = 'none';
    document.getElementById("streetName").textContent = '';
};

Action.prototype.initObservers = function() {

    var that = this;

    document.addEventListener("semaphoreStatus", function(e) {
        console.log(e);
        var semaphoreStatus = e.detail;

        if (semaphoreStatus === 'stop') {
            document.getElementById("sign").src = "res/images/stop.png";
            document.body.style.background = 'red';

            if (util.getCurrentSoundSource().indexOf('dangerous_crossing.mp3') > -1) {
                util.playSound('res/audios/stop.mp3', 1);
            } else {
                util.playSound('res/audios/stop.mp3', 2);
            }
            navigator.vibrate(1000);
        } else {
            document.getElementById("sign").src = "res/images/go.png";

            if (that.semaphore.getTimeLeft() >= 1 && that.semaphore.getTimeLeft() <= 5) {
                util.playSound('res/audios/dangerous_crossing.mp3', 2);
                navigator.vibrate(1000);
            } else {
                util.playSound('res/audios/go.mp3', 2);
                navigator.vibrate([500, 100, 500]); // 500 on; 100 off; 500 on;
            }
            document.body.style.background = 'green';
        }
    });

    document.addEventListener("timeLeft", function(e) {
        console.log(e);

        document.getElementById("timeLeft").textContent = e.detail;

        switch (e.detail) {
            case 5:
                util.playSound('res/audios/time_left_5.mp3', 0);
                break;
            case 10:
                util.playSound('res/audios/time_left_10.mp3', 0);
                break;
            case 15:
                util.playSound('res/audios/time_left_15.mp3', 0);
                break;
        };
    });

    document.addEventListener("streetName", function(e) {
        that.streetName = e.detail;
    });

    /*
    Don't works on Tizen platform :(

    Object.observe(this.semaphore, function(changes) {

        changes.forEach(function(change, index) {
            if (change.name === 'timeLeft') {
                var timeLeft = change.object.timeLeft;

                timeLeft = timeLeft < 0 ? 0 : timeLeft;

                document.getElementById("timeLeft").innerHTML = timeLeft;
            }

            if (change.name === 'semaphoreStatus') {
                var semaphoreStatus = change.object.semaphoreStatus;

                if (semaphoreStatus === 'stop') {
                    document.body.style.background = 'red';
                } else {
                    document.body.style.background = 'green';
                }
            }
        });
    });
*/
};

var action = new Action();<commit_msg>Adding yellow screen on dangerous situation<commit_after>function Action() {
    this.connect();
}

Action.prototype.connect = function() {
    this.semaphore = new SemaphoreMock();
    this.initObservers();
    this.semaphore.connect();
    this.street = "";
};

Action.prototype.disconnect = function() {
    navigator.vibrate(0); // cancel vibration
    this.semaphore.disconnect();
    document.location.href = 'index.html';
};

Action.prototype.tapScreen = function() {

    var that = this;

    util.doubleTapHandler(function(isDoubleTap) {
        if (isDoubleTap) {
            util.playSound('res/audios/disconnected.mp3', 2);
            that.disconnect();
        } else {
            if (that.isStreetShowing()) {
                that.hideStreetName();
            } else {
                that.showStreetName();
            }
        }
    });
};

Action.prototype.isStreetShowing = function() {
    return document.getElementById("extraInfoDiv").style.display === 'block';
};

Action.prototype.showStreetName = function() {

    var that = this;

    var onStartVoice = function() {
        document.getElementById("signsDiv").style.display = 'none';
        document.getElementById("extraInfoDiv").style.display = 'block';
        document.getElementById("streetName").textContent = that.streetName;

        console.log(document.getElementById("audio").duration);

        audio.addEventListener('loadedmetadata', function() {
            setTimeout(function() {
                that.hideStreetName();
            }, Math.round(util.getCurrentSoundDuration()) * 1000);
        });
    };

    switch (this.streetName) {
        case 'Av. Brasil':
            util.playSound('res/audios/av_brasil.mp3', 1, onStartVoice);
            break;
        case 'Av. Nove de Abril':
            util.playSound('res/audios/av_nove_abril.mp3', 1, onStartVoice);
            break;
        case 'Av. Pe. Jaime':
            util.playSound('res/audios/av_pe_jaime.mp3', 1, onStartVoice);
            break;
    };
};

Action.prototype.hideStreetName = function() {
    document.getElementById("signsDiv").style.display = 'block';
    document.getElementById("extraInfoDiv").style.display = 'none';
    document.getElementById("streetName").textContent = '';
};

Action.prototype.setStatusToStop = function() {
    document.getElementById("sign").src = "res/images/stop.png";
    document.body.style.background = 'red';

    // If is on dangerous crossing alert, wait the alert finish to alert stop status.
    if (util.getCurrentSoundSource().indexOf('dangerous_crossing.mp3') > -1) {
        util.playSound('res/audios/stop.mp3', 1);
    } else {
        util.playSound('res/audios/stop.mp3', 2);
    }

    navigator.vibrate(1000);
};

Action.prototype.setStatusToGo = function() {
    document.body.style.background = 'green';
    document.getElementById("sign").src = "res/images/go.png";
    util.playSound('res/audios/go.mp3', 2);
    navigator.vibrate([500, 100, 500]); // 500 on; 100 off; 500 on;
};

Action.prototype.setStatusToDangerousCrossing = function() {
    document.body.style.background = 'yellow';
    util.playSound('res/audios/dangerous_crossing.mp3', 2);
    navigator.vibrate(1000);
    document.getElementById("sign").src = "res/images/stop.png";
};

Action.prototype.initObservers = function() {

    var that = this;

    document.addEventListener("semaphoreStatus", function(e) {
        console.log(e);
        var semaphoreStatus = e.detail;

        if (semaphoreStatus === 'stop') {
            that.setStatusToStop();
        } else {
            if (that.semaphore.getTimeLeft() >= 1 && that.semaphore.getTimeLeft() <= 5) {
                that.setStatusToDangerousCrossing();
            } else {
                that.setStatusToGo();
            }
        }
    });

    document.addEventListener("timeLeft", function(e) {
        console.log(e);

        document.getElementById("timeLeft").textContent = e.detail;

        switch (e.detail) {
            case 5:
                util.playSound('res/audios/time_left_5.mp3', 0);
                break;
            case 10:
                util.playSound('res/audios/time_left_10.mp3', 0);
                break;
            case 15:
                util.playSound('res/audios/time_left_15.mp3', 0);
                break;
        };
    });

    document.addEventListener("streetName", function(e) {
        that.streetName = e.detail;
    });

    /*
    Don't works on Tizen platform :(

    Object.observe(this.semaphore, function(changes) {

        changes.forEach(function(change, index) {
            if (change.name === 'timeLeft') {
                var timeLeft = change.object.timeLeft;

                timeLeft = timeLeft < 0 ? 0 : timeLeft;

                document.getElementById("timeLeft").innerHTML = timeLeft;
            }

            if (change.name === 'semaphoreStatus') {
                var semaphoreStatus = change.object.semaphoreStatus;

                if (semaphoreStatus === 'stop') {
                    document.body.style.background = 'red';
                } else {
                    document.body.style.background = 'green';
                }
            }
        });
    });
*/
};

var action = new Action();<|endoftext|>


<commit_before>import { Marker } from '../../model'

class FindAndReplaceManager {

  constructor(context) {
    if (!context.editorSession) {
      throw new Error('EditorSession required.')
    }

    this.editorSession = context.editorSession
    this.editorSession.onRender('document', this._onDocumentChanged, this)

    this.doc = this.editorSession.getDocument()
    this.context = Object.assign({}, context, {
      // for convenienve we provide access to the doc directly
      doc: this.doc
    })

    this._state = {
      disabled: true,
      findString: '',
      replaceString: '',
      // Consists a sequence of property selections
      matches: [],
      selectedMatch: undefined
    }

    // Set to indicate the desire to scroll to the selected match
    this._requestLookupMatch = false
    // Set to indicate the desire to focus and select the search string
    this._requestFocusSearchString = false
  }

  dispose() {
    this.editorSession.off(this)
  }

  /*
    NOTE: We remember findString and replaceString for the next search action
  */
  _resetState() {
    this._state.disabled = true
    this._state.matches = []
    this._state.selectedMatch = undefined
  }

  /*
    Derive command state for FindAndReplaceTool
  */
  getCommandState() {
    let state = this._state
    let commandState = {
      disabled: state.disabled,
      findString: state.findString,
      replaceString: state.replaceString,
      // Used to display '4 of 10' etc.
      totalMatches: state.matches.length,
      selectedMatch: state.selectedMatch + 1
    }
    return commandState
  }

  enable() {
    this._state.disabled = false
    this._requestFocusSearchString = true
    // Attempts to start a find immediately
    this.startFind(this._state.findString)
  }

  disable() {
    this._state.disabled = true
    this._resetState()
    this._propagateUpdate()
  }

  _onDocumentChanged() {
    if (!this._state.disabled) {
      this._computeMatches()
      this._state.selectedMatch = 0
      this._updateMarkers()
    }
  }

  /*
    Start find and replace workflow
  */
  startFind(findString) {
    this._state.findString = findString
    this._computeMatches()
    let closestMatch = this._getClosestMatch()
    this._state.selectedMatch = closestMatch > 0 ? closestMatch : 0
    this._requestLookupMatch = true
    this._setSelection()
    this._propagateUpdate()

  }

  setReplaceString(replaceString) {
    // NOTE: We don't trigger any updates here
    this._state.replaceString = replaceString
  }

  /*
    Find next match.
  */
  findNext() {
    let index = this._state.selectedMatch
    let totalMatches = this._state.matches.length
    if (totalMatches === 0) return
    this._state.selectedMatch = (index + 1) % totalMatches
    this._requestLookupMatch = true
    this._setSelection()
    this._propagateUpdate()
  }

  /*
    Find previous match
  */
  findPrevious() {
    let index = this._state.selectedMatch
    let totalMatches = this._state.matches.length
    if (totalMatches === 0) return
    this._state.selectedMatch = index > 0 ? index - 1 : totalMatches - 1
    this._requestLookupMatch = true
    this._setSelection()
    this._propagateUpdate()
  }

  _setSelection() {
    let match = this._state.matches[this._state.selectedMatch]
    if (!match) return
    // NOTE: We need to make sure no additional flow is triggered when
    // setting the selection. We trigger a flow at the very end (_propagateUpdate)
    let sel = match.getSelection()
    // HACK: we need to manually set the container id for now
    let surface = this.editorSession.getFocusedSurface()
    sel.containerId = surface.getContainerId()
    this.editorSession.setSelection(sel, 'skipFlow')
  }

  /*
    Replace next occurence
  */
  replaceNext() {
    let index = this._state.selectedMatch
    let match = this._state.matches[index]
    let totalMatches = this._state.matches.length
    if(match !== undefined) {
      this.editorSession.transaction((tx, args) => {
        tx.setSelection(match.getSelection())
        tx.insertText(this._state.replaceString)
        return args
      })
      this._computeMatches()
      if(index + 1 < totalMatches) {
        this._state.selectedMatch = index
      }
      this._requestLookupMatch = true
      this._setSelection()
      this._propagateUpdate()
    }
  }

  /*
    Replace all occurences
  */
  replaceAll() {
    // Reverse matches order,
    // so the replace operations later are side effect free.
    let matches = this._state.matches.reverse()

    this.editorSession.transaction((tx, args) => {
      matches.forEach(match => {
        tx.setSelection(match.getSelection())
        tx.insertText(this._state.replaceString)
      })
      return args
    })

    this._computeMatches()
  }

  /*
    Get closest match to current cursor position
  */
  _getClosestMatch() {
    let doc = this.editorSession.getDocument()
    let nodeIds = Object.keys(doc.getNodes())
    let sel = this.editorSession.getSelection()
    let closest = 0

    if(!sel.isNull()) {
      let startOffset = sel.start.offset
      let selStartNode = sel.start.path[0]
      let selStartNodePos = nodeIds.indexOf(selStartNode)
      let matches = this._state.matches

      closest = matches.findIndex(match => {
        let markerSel = match.getSelection()
        let markerStartOffset = markerSel.start.offset
        let markerStartNode = markerSel.start.path[0]
        let markerStartNodePos = nodeIds.indexOf(markerStartNode)
        if(selStartNodePos > markerStartNodePos) {
          return false
        } else if (selStartNodePos < markerStartNodePos) {
          return true
        } else {
          if(startOffset <= markerStartOffset) {
            return true
          } else {
            return false
          }
        }
      })
    }

    return closest
  }

  _computeMatches() {
    let currentMatches = this._state.matches
    let currentTotal = currentMatches === undefined ? 0 : currentMatches.length

    this._state.matches = this._findAllMatches()

    // Preserve selection in case of the same number of matches
    // If the number of matches did changed we will set first selection
    // If there are no matches we should remove index
    let newMatches = this._state.matches

    if(newMatches.length !== currentTotal) {
      this._state.selectedMatch = newMatches.length > 0 ? 0 : undefined
    }
  }

  /*
    Returns all matches
  */
  _findAllMatches() {
    const doc = this.doc
    const nodes = doc.getNodes()
    const pattern = this._state.findString

    let matches = []
    if (pattern) {
      Object.keys(nodes).forEach((nodeId) => {
        let node = doc.get(nodeId)
        if(node.isText()) {
          let found = this._findInTextProperty({
            path: [node.id, 'content'],
            findString: pattern
          })
          matches = matches.concat(found)
        }
      })
    }
    return matches
  }

  /*
    Find all matches for a given search string in a text property
    Method returns an array of matches, each match is represented as
    a PropertySelection
  */
  _findInTextProperty({path, findString}) {
    const doc = this.doc
    const text = doc.get(path)

    // Case-insensitive search for multiple matches
    let matcher = new RegExp(findString, 'ig')
    let matches = []
    let match

    while ((match = matcher.exec(text))) {
      let marker = new Marker(doc, {
        type: 'match',
        start: {
          path,
          offset: match.index
        },
        end: {
          offset: matcher.lastIndex
        }
      })
      matches.push(marker)
    }
    return matches
  }

  _propagateUpdate() {
    // HACK: we make commandStates dirty in order to trigger re-evaluation
    this._updateMarkers()
    this.editorSession._setDirty('commandStates')
    this.editorSession.startFlow()
  }

  _updateMarkers() {
    const state = this._state
    const editorSession = this.editorSession
    const markersManager = editorSession.markersManager
    state.matches.forEach((m, idx) => {
      m.type = (idx === state.selectedMatch) ? 'selected-match' : 'match'
    })
    // console.log('setting find-and-replace markers', state.matches)
    markersManager.setMarkers('find-and-replace', state.matches)
  }

}

export default FindAndReplaceManager
<commit_msg>Cleanup.<commit_after>import { Marker } from '../../model'

class FindAndReplaceManager {

  constructor(context) {
    if (!context.editorSession) {
      throw new Error('EditorSession required.')
    }

    this.editorSession = context.editorSession
    this.editorSession.onRender('document', this._onDocumentChanged, this)

    this.doc = this.editorSession.getDocument()
    this.context = Object.assign({}, context, {
      // for convenienve we provide access to the doc directly
      doc: this.doc
    })

    this._state = {
      disabled: true,
      findString: '',
      replaceString: '',
      // Consists a sequence of property selections
      matches: [],
      selectedMatch: undefined
    }

    // Set to indicate the desire to scroll to the selected match
    this._requestLookupMatch = false
    // Set to indicate the desire to focus and select the search string
    this._requestFocusSearchString = false
  }

  dispose() {
    this.editorSession.off(this)
  }

  /*
    NOTE: We remember findString and replaceString for the next search action
  */
  _resetState() {
    this._state.disabled = true
    this._state.matches = []
    this._state.selectedMatch = undefined
  }

  /*
    Derive command state for FindAndReplaceTool
  */
  getCommandState() {
    let state = this._state
    let commandState = {
      disabled: state.disabled,
      findString: state.findString,
      replaceString: state.replaceString,
      // Used to display '4 of 10' etc.
      totalMatches: state.matches.length,
      selectedMatch: state.selectedMatch + 1
    }
    return commandState
  }

  enable() {
    this._state.disabled = false
    this._requestFocusSearchString = true
    // Attempts to start a find immediately
    this.startFind(this._state.findString)
  }

  disable() {
    this._state.disabled = true
    this._resetState()
    this._propagateUpdate()
  }

  _onDocumentChanged() {
    if (!this._state.disabled) {
      this._computeMatches()
      this._state.selectedMatch = 0
      this._updateMarkers()
    }
  }

  /*
    Start find and replace workflow
  */
  startFind(findString) {
    this._state.findString = findString
    this._computeMatches()
    let closestMatch = this._getClosestMatch()
    this._state.selectedMatch = closestMatch > 0 ? closestMatch : 0
    this._requestLookupMatch = true
    this._setSelection()
    this._propagateUpdate()

  }

  setReplaceString(replaceString) {
    // NOTE: We don't trigger any updates here
    this._state.replaceString = replaceString
  }

  /*
    Find next match.
  */
  findNext() {
    let index = this._state.selectedMatch
    let totalMatches = this._state.matches.length
    if (totalMatches === 0) return
    this._state.selectedMatch = (index + 1) % totalMatches
    this._requestLookupMatch = true
    this._setSelection()
    this._propagateUpdate()
  }

  /*
    Find previous match
  */
  findPrevious() {
    let index = this._state.selectedMatch
    let totalMatches = this._state.matches.length
    if (totalMatches === 0) return
    this._state.selectedMatch = index > 0 ? index - 1 : totalMatches - 1
    this._requestLookupMatch = true
    this._setSelection()
    this._propagateUpdate()
  }

  _setSelection() {
    let match = this._state.matches[this._state.selectedMatch]
    if (!match) return
    // NOTE: We need to make sure no additional flow is triggered when
    // setting the selection. We trigger a flow at the very end (_propagateUpdate)
    let sel = match.getSelection()
    this.editorSession.setSelection(sel, 'skipFlow')
  }

  /*
    Replace next occurence
  */
  replaceNext() {
    let index = this._state.selectedMatch
    let match = this._state.matches[index]
    let totalMatches = this._state.matches.length
    if(match !== undefined) {
      this.editorSession.transaction((tx, args) => {
        tx.setSelection(match.getSelection())
        tx.insertText(this._state.replaceString)
        return args
      })
      this._computeMatches()
      if(index + 1 < totalMatches) {
        this._state.selectedMatch = index
      }
      this._requestLookupMatch = true
      this._setSelection()
      this._propagateUpdate()
    }
  }

  /*
    Replace all occurences
  */
  replaceAll() {
    // Reverse matches order,
    // so the replace operations later are side effect free.
    let matches = this._state.matches.reverse()

    this.editorSession.transaction((tx, args) => {
      matches.forEach(match => {
        tx.setSelection(match.getSelection())
        tx.insertText(this._state.replaceString)
      })
      return args
    })

    this._computeMatches()
  }

  /*
    Get closest match to current cursor position
  */
  _getClosestMatch() {
    let doc = this.editorSession.getDocument()
    let nodeIds = Object.keys(doc.getNodes())
    let sel = this.editorSession.getSelection()
    let closest = 0

    if(!sel.isNull()) {
      let startOffset = sel.start.offset
      let selStartNode = sel.start.path[0]
      let selStartNodePos = nodeIds.indexOf(selStartNode)
      let matches = this._state.matches

      closest = matches.findIndex(match => {
        let markerSel = match.getSelection()
        let markerStartOffset = markerSel.start.offset
        let markerStartNode = markerSel.start.path[0]
        let markerStartNodePos = nodeIds.indexOf(markerStartNode)
        if(selStartNodePos > markerStartNodePos) {
          return false
        } else if (selStartNodePos < markerStartNodePos) {
          return true
        } else {
          if(startOffset <= markerStartOffset) {
            return true
          } else {
            return false
          }
        }
      })
    }

    return closest
  }

  _computeMatches() {
    let currentMatches = this._state.matches
    let currentTotal = currentMatches === undefined ? 0 : currentMatches.length

    this._state.matches = this._findAllMatches()

    // Preserve selection in case of the same number of matches
    // If the number of matches did changed we will set first selection
    // If there are no matches we should remove index
    let newMatches = this._state.matches

    if(newMatches.length !== currentTotal) {
      this._state.selectedMatch = newMatches.length > 0 ? 0 : undefined
    }
  }

  /*
    Returns all matches
  */
  _findAllMatches() {
    const doc = this.doc
    const nodes = doc.getNodes()
    const pattern = this._state.findString

    let matches = []
    if (pattern) {
      Object.keys(nodes).forEach((nodeId) => {
        let node = doc.get(nodeId)
        if(node.isText()) {
          let found = this._findInTextProperty({
            path: [node.id, 'content'],
            findString: pattern
          })
          matches = matches.concat(found)
        }
      })
    }
    return matches
  }

  /*
    Find all matches for a given search string in a text property
    Method returns an array of matches, each match is represented as
    a PropertySelection
  */
  _findInTextProperty({path, findString}) {
    const doc = this.doc
    const text = doc.get(path)

    // Case-insensitive search for multiple matches
    let matcher = new RegExp(findString, 'ig')
    let matches = []
    let match

    while ((match = matcher.exec(text))) {
      let marker = new Marker(doc, {
        type: 'match',
        start: {
          path,
          offset: match.index
        },
        end: {
          offset: matcher.lastIndex
        }
      })
      matches.push(marker)
    }
    return matches
  }

  _propagateUpdate() {
    // HACK: we make commandStates dirty in order to trigger re-evaluation
    this._updateMarkers()
    this.editorSession._setDirty('commandStates')
    this.editorSession.startFlow()
  }

  _updateMarkers() {
    const state = this._state
    const editorSession = this.editorSession
    const markersManager = editorSession.markersManager
    state.matches.forEach((m, idx) => {
      m.type = (idx === state.selectedMatch) ? 'selected-match' : 'match'
    })
    // console.log('setting find-and-replace markers', state.matches)
    markersManager.setMarkers('find-and-replace', state.matches)
  }

}

export default FindAndReplaceManager
<|endoftext|>


<commit_before>
const RG = require('./rg');

RG.Factory = require('./factory');
RG.Factory.Battle = require('./factory.battle');
const OW = require('./overworld.map');

const debug = require('debug')('bitn:GameMaster');

/* GameMaster objects reacts to various events caused by player and other
 * actors, and shapes the game world based on them. For example,
 * GameMaster can:
 *   - start battles on the area player entered
 *   - spawn special events and actors
 *   - spawn special items etc.
 */
const GameMaster = function(game) {
    this.player = null;
    this.game = game;
    this.fact = new RG.Factory.Battle(game);

    // Lookup table for battles by level ID
    this.battles = {};

    this.battlesDone = {};

    this.setPool = pool => {this.pool = pool;};
    this.setGame = game => {this.game = game;};

    this.setPlayer = player => {
        this.player = player;
    };
    this.setWorld = world => {this.world = world;};

    this.hasNotify = true;
    this.notify = (evtName, args) => {
        if (evtName === RG.EVT_LEVEL_CHANGED) {
            debug('EVT_LEVEL_CHANGED');
            const {actor} = args;
            if (actor.isPlayer()) {
                if (!actor.has('InBattle')) {
                    this.addPlayerToBattle(args);
                }
                else {
                    this.removePlayerFromBattle(args);
                }
            }
        }
        else if (evtName === RG.EVT_TILE_CHANGED) {
            debug('EVT_TILE_CHANGED');
            // Should spawn battle etc event
            if (!this.player) {
                debug('\tBut player is NULL for the moment');
                return;
            }
            debug('\tPlayer not null. Creating battle');
            const level = this.player.getLevel();
            const id = level.getID();

            const ow = this.game.getOverWorld();
            let maxDanger = 4;
            let armySize = 20;
            const battleConf = {};
            let levelType = 'forest';
            if (ow) {
                const world = this.game.getCurrentWorld();
                const area = world.getAreas()[0];
                const xy = area.findTileXYById(id);
                // TODO use actual starting position
                const startX = 2;
                const startY = area.getMaxY() - 1;
                const dX = Math.abs(startX - xy[0]);
                const dY = Math.abs(startY - xy[1]);
                maxDanger += dX + dY;
                armySize += 10 * dY + 5 * dX;
                console.log('armySize will be ' + armySize);

                const owPos = this.game.getPlayerOwPos();
                const biome = ow.getBiome(owPos[0], owPos[1]);
                levelType = this.biomeToLevelType(biome);
            }
            battleConf.maxDanger = maxDanger;
            battleConf.armySize = armySize;
            battleConf.levelType = levelType;

            if (!this.battles.hasOwnProperty(id)) {
                const battle = this.fact.createBattle(level, battleConf);
                this.battles[id] = battle;
                this.game.addBattle(this.battles[id]);
            }
        }
        else if (evtName === RG.EVT_BATTLE_OVER) {
            const {battle} = args;
            debug(`EVT_BATTLE_OVER: ${battle.getName()}`);
            const id = battle.getLevel().getID();

            debug(`1. battlesDone for ${id}: ${this.battlesDone[id]}`);
            if (!this.battlesDone[id] && battle) {
                debug(`2. battlesDone for ${id}: ${this.battlesDone[id]}`);
                this.battlesDone[id] = true;
                debug(`3. battlesDone for ${id}: ${this.battlesDone[id]}`);
                this.addBadgesForActors(battle);
                this.moveActorsOutOfBattle(battle);
                const bName = battle.getName();
                RG.gameMsg(`Battle ${bName} is over!`);
            }
            else {
                const json = JSON.stringify(args);
                RG.err('Game.Master', 'notify',
                    `Args ${json} does not contain "battle"`);
            }
            debug('GameMaster registered battle over');
            // TODO delete the battle (but keep the level)
        }
    };
    RG.POOL.listenEvent(RG.EVT_LEVEL_CHANGED, this);
    RG.POOL.listenEvent(RG.EVT_TILE_CHANGED, this);
    RG.POOL.listenEvent(RG.EVT_BATTLE_OVER, this);

    /* Adds player to the battle level. */
    this.addPlayerToBattle = function(args) {
        const {actor, target, src} = args;
        const srcID = src.getID();
        if (this.battles.hasOwnProperty(srcID)) {
            const battle = this.battles[srcID];
            const battleLevel = battle.getLevel();
            if (battleLevel.getID() === target.getID()) {
                if (this.actorCanEnter(actor, battle)) {
                    // Entered a battle
                    const comp = new RG.Component.InBattle();
                    comp.setData({name: battle.getName()});
                    actor.add(comp);
                    // Get army selection object
                    const obj = this.getSelArmyObject(actor, battle);
                    actor.getBrain().setSelectionObject(obj);
                }
                else if (battle.isOver()) {
                    RG.gameMsg('Looks like the battle is already fought..');
                }
                else {
                    RG.gameMsg('You cannot join the fight anymore, deserter.');
                }
            }
        }

    };

    /* Returns true if the actor can still enter the battle as an army member.
     * */
    this.actorCanEnter = (actor, battle) => {
        if (battle.isOver()) {return false;}
        if (this.actorDesertedBattle(actor, battle)) {return false;}
        return true;
    };

    /* Removes the player from a battle. */
    this.removePlayerFromBattle = function(args) {
        const {actor, target, src} = args;
        const areaID = target.getID();
        const srcID = src.getID();
        const battle = this.battles[areaID];
        const battleLevID = battle.getLevel().getID();

        const inBattleComp = actor.get('InBattle');
        const battleData = inBattleComp.getData();

        if (srcID !== battleLevID) {
            const msg = `Level ID mismatch: ${srcID} !== ${battleLevID}`;
            RG.err('GameMaster', 'removePlayerFromBattle', msg);
        }

        // Mark player as deserter, TODO add confirm object
        if (!battle.isOver() && battleData.army) {
            const badge = new RG.Component.BattleBadge();
            badge.setData({status: 'Fled', name: battle.getName(),
                army: battleData.army});
            actor.add(badge);
            actor.remove('InBattle');
            actor.add(new RG.Component.BattleOver());
        }
    };

    /* Adds BattleBadges after a battle is over. */
    this.addBadgesForActors = battle => {
        const armies = battle.getArmies();
        armies.forEach(army => {
            const actors = army.getActors();
            const ids = actors.map(actor => actor.getID());

            actors.forEach(actor => {
                if (!this.actorDesertedBattle(actor, battle)) {
                    const badge = new RG.Component.BattleBadge();
                    const battleData = {
                        name: battle.getName(),
                        army: army.getName(),
                        allies: ids,
                        status: army.isDefeated() ? 'Lost' : 'Won'
                    };
                    badge.setData(battleData);
                    actor.add(badge);

                    actor.remove('InBattle');
                    actor.add(new RG.Component.BattleOver());
                }
            });
        });
    };

    this.actorDesertedBattle = (actor, battle) => {
        const badgeList = actor.getList('BattleBadge');
        const badge = badgeList.find(b => (
            b.getData().name === battle.getName()
        ));
        if (badge) {return true;}
        return false;
    };

    /* Moves actors out of the battle level into the parent level of the battle
     * (at the moment this is always Area.Tile level. */
    this.moveActorsOutOfBattle = battle => {
        const level = battle.getLevel();
        const conns = level.getConnections();

        if (!conns || conns.length === 0) {
            RG.err('Game.Master', 'moveActorsOutOfBattle',
                'No exit connnection in level');
        }

        const exit = conns[0];
        const targetLevel = exit.getTargetLevel();

        const armies = battle.getArmies();
        armies.forEach(army => {
            const actors = army.getActors();
            actors.forEach(actor => {
                if (!actor.isPlayer()) {
                    if (level.removeActor(actor)) {
                        debug(`Rm actor ${actor.getID()},${actor.getName()}`);
                        targetLevel.addActorToFreeCell(actor);
                    }
                    else {
                        const json = JSON.stringify(actor.toJSON());
                        RG.err('Game.Master', 'moveActorsOutOfBattle',
                            `level.removeActor failed for actor ${json}`);
                    }
                }
                else {
                    const selObj = this.getSelLeaveBattle(actor, level);
                    actor.getBrain().setSelectionObject(selObj);
                }
            });
        });

    };

    /* Returns the selection object for player to select an army. */
    this.getSelArmyObject = function(player, battle) {
        return {
            showMenu: () => true,
            getMenu: () => {
                RG.gameMsg('Please select an army to join:');
                const armies = battle.getArmies();
                const menuObj = {};
                armies.forEach((army, i) => {
                    menuObj[i] = ' Army ' + army.getName();
                });
                menuObj['Any other key'] = 'Take no side';
                return menuObj;
            },
            select: code => {
                const selection = RG.codeToIndex(code);
                const armies = battle.getArmies();
                if (selection < armies.length) {
                    const army = armies[selection];
                    return () => {
                        const battleLevel = battle.getLevel();
                        let armyActors = army.getActors();
                        const nActors = armyActors.length;
                        const pIndex = RG.RAND.getUniformInt(0, nActors);
                        const replacedActor = armyActors[pIndex];
                        const [pX, pY] = replacedActor.getXY();

                        // Remove substituted actor from army/level
                        replacedActor.get('Action').disable();
                        army.removeActor(replacedActor);
                        battleLevel.removeActor(replacedActor);

                        armyActors = army.getActors();
                        army.addActor(player);

                        player.get('InBattle').updateData({army: army.getName});
                        armyActors.forEach(actor => {
                            actor.addFriend(player);
                        });

                        armies.forEach(enemyArmy => {
                            if (enemyArmy !== army) {
                                const enemies = enemyArmy.getActors();
                                enemies.forEach(enemy => {
                                    enemy.addEnemy(player);
                                });
                            }
                        });

                        if (!battleLevel.moveActorTo(player, pX, pY)) {
                            RG.err('GameMaster', 'getSelArmyObject',
                                `Could not move player to ${pX},${pY}`);
                        }
                    };
                }
                return null;
            }
        };
    };

    this.getSelLeaveBattle = function(player, level) {
        const selObj = function() {
            this.showMenu = () => true;
            this.getMenu = () => {
                RG.gameMsg('Battle is over! Do you want to leave battle?');
                return {
                    0: 'Leave immediately',
                    1: 'Stay behind to scavenge the bodies of the dead.'
                };
            };
            this.select = code => {
                const selection = RG.codeToIndex(code);
                if (selection === 0) {
                    return () => {
                        const exit = level.getConnections()[0];
                        if (!exit.useStairs(player)) {
                            RG.err('GameMaster', 'moveActorsOutOfBattle',
                                'Cannot move player via useStairs');
                        }
                        else {
                            const name = player.getName();
                            RG.gameMsg(`${name} leaves the battlefield`);
                        }
                    };
                }
                if (selection === 1) {
                    // TODO add some dishonor for the player or some necromancy
                    // effect etc
                    return null;
                }
                return this;
            };
        };
        return new selObj();
    };

    /* Serializes the object into JSON. */
    this.toJSON = function() {
        const keys = Object.keys(this.battles);
        const battles = {};
        keys.forEach(id => {
            battles[id] = this.battles[id].toJSON();
        });
        return {
            battles,
            battlesDone: this.battlesDone
        };
    };

    this.biomeToLevelType = function(biome) {
        switch (biome) {
            case OW.BIOME.ARCTIC: return 'arctic';
            case OW.BIOME.TUNDRA: return 'arctic';
            case OW.BIOME.ALPINE: return 'mountain';
            case OW.BIOME.TAIGA: return 'forest';
            default: return 'forest';
        }
    };

    this.getBattleLevels = function() {
        const levels = [];
        Object.values(this.battles).forEach(battle => {
            levels.push(battle.getLevel());
        });
        return levels;

    };
};

module.exports = GameMaster;
<commit_msg>Adjusted the scaling of army size.<commit_after>
const RG = require('./rg');

RG.Factory = require('./factory');
RG.Factory.Battle = require('./factory.battle');
const OW = require('./overworld.map');

const debug = require('debug')('bitn:GameMaster');

/* GameMaster objects reacts to various events caused by player and other
 * actors, and shapes the game world based on them. For example,
 * GameMaster can:
 *   - start battles on the area player entered
 *   - spawn special events and actors
 *   - spawn special items etc.
 */
const GameMaster = function(game) {
    this.player = null;
    this.game = game;
    this.fact = new RG.Factory.Battle(game);

    // Lookup table for battles by level ID
    this.battles = {};

    this.battlesDone = {};

    this.setPool = pool => {this.pool = pool;};
    this.setGame = game => {this.game = game;};

    this.setPlayer = player => {
        this.player = player;
    };
    this.setWorld = world => {this.world = world;};

    this.hasNotify = true;
    this.notify = (evtName, args) => {
        if (evtName === RG.EVT_LEVEL_CHANGED) {
            debug('EVT_LEVEL_CHANGED');
            const {actor} = args;
            if (actor.isPlayer()) {
                if (!actor.has('InBattle')) {
                    this.addPlayerToBattle(args);
                }
                else {
                    this.removePlayerFromBattle(args);
                }
            }
        }
        else if (evtName === RG.EVT_TILE_CHANGED) {
            debug('EVT_TILE_CHANGED');
            // Should spawn battle etc event
            if (!this.player) {
                debug('\tBut player is NULL for the moment');
                return;
            }
            debug('\tPlayer not null. Creating battle');
            const level = this.player.getLevel();
            const id = level.getID();

            const ow = this.game.getOverWorld();
            let maxDanger = 4;
            let armySize = 20;
            const battleConf = {};
            let levelType = 'forest';
            if (ow) {
                const world = this.game.getCurrentWorld();
                const area = world.getAreas()[0];
                const xy = area.findTileXYById(id);
                // TODO use actual starting position
                const startX = 2;
                const startY = area.getMaxY() - 1;
                const dX = Math.abs(startX - xy[0]);
                const dY = Math.abs(startY - xy[1]);
                maxDanger += dX + dY;
                armySize += 20 * dY + 10 * dX;

                const msg = `dx,dy: ${dX},${dY} armySize ${armySize}`;
                console.log(`${msg} , danger: ${maxDanger}`);

                const owPos = this.game.getPlayerOwPos();
                const biome = ow.getBiome(owPos[0], owPos[1]);
                levelType = this.biomeToLevelType(biome);
            }
            battleConf.maxDanger = maxDanger;
            battleConf.armySize = armySize;
            battleConf.levelType = levelType;

            if (!this.battles.hasOwnProperty(id)) {
                const battle = this.fact.createBattle(level, battleConf);
                this.battles[id] = battle;
                this.game.addBattle(this.battles[id]);
            }
        }
        else if (evtName === RG.EVT_BATTLE_OVER) {
            const {battle} = args;
            debug(`EVT_BATTLE_OVER: ${battle.getName()}`);
            const id = battle.getLevel().getID();

            debug(`1. battlesDone for ${id}: ${this.battlesDone[id]}`);
            if (!this.battlesDone[id] && battle) {
                debug(`2. battlesDone for ${id}: ${this.battlesDone[id]}`);
                this.battlesDone[id] = true;
                debug(`3. battlesDone for ${id}: ${this.battlesDone[id]}`);
                this.addBadgesForActors(battle);
                this.moveActorsOutOfBattle(battle);
                const bName = battle.getName();
                RG.gameMsg(`Battle ${bName} is over!`);
            }
            else {
                const json = JSON.stringify(args);
                RG.err('Game.Master', 'notify',
                    `Args ${json} does not contain "battle"`);
            }
            debug('GameMaster registered battle over');
            // TODO delete the battle (but keep the level)
        }
    };
    RG.POOL.listenEvent(RG.EVT_LEVEL_CHANGED, this);
    RG.POOL.listenEvent(RG.EVT_TILE_CHANGED, this);
    RG.POOL.listenEvent(RG.EVT_BATTLE_OVER, this);

    /* Adds player to the battle level. */
    this.addPlayerToBattle = function(args) {
        const {actor, target, src} = args;
        const srcID = src.getID();
        if (this.battles.hasOwnProperty(srcID)) {
            const battle = this.battles[srcID];
            const battleLevel = battle.getLevel();
            if (battleLevel.getID() === target.getID()) {
                if (this.actorCanEnter(actor, battle)) {
                    // Entered a battle
                    const comp = new RG.Component.InBattle();
                    comp.setData({name: battle.getName()});
                    actor.add(comp);
                    // Get army selection object
                    const obj = this.getSelArmyObject(actor, battle);
                    actor.getBrain().setSelectionObject(obj);
                }
                else if (battle.isOver()) {
                    RG.gameMsg('Looks like the battle is already fought..');
                }
                else {
                    RG.gameMsg('You cannot join the fight anymore, deserter.');
                }
            }
        }

    };

    /* Returns true if the actor can still enter the battle as an army member.
     * */
    this.actorCanEnter = (actor, battle) => {
        if (battle.isOver()) {return false;}
        if (this.actorDesertedBattle(actor, battle)) {return false;}
        return true;
    };

    /* Removes the player from a battle. */
    this.removePlayerFromBattle = function(args) {
        const {actor, target, src} = args;
        const areaID = target.getID();
        const srcID = src.getID();
        const battle = this.battles[areaID];
        const battleLevID = battle.getLevel().getID();

        const inBattleComp = actor.get('InBattle');
        const battleData = inBattleComp.getData();

        if (srcID !== battleLevID) {
            const msg = `Level ID mismatch: ${srcID} !== ${battleLevID}`;
            RG.err('GameMaster', 'removePlayerFromBattle', msg);
        }

        // Mark player as deserter, TODO add confirm object
        if (!battle.isOver() && battleData.army) {
            const badge = new RG.Component.BattleBadge();
            badge.setData({status: 'Fled', name: battle.getName(),
                army: battleData.army});
            actor.add(badge);
            actor.remove('InBattle');
            actor.add(new RG.Component.BattleOver());
        }
    };

    /* Adds BattleBadges after a battle is over. */
    this.addBadgesForActors = battle => {
        const armies = battle.getArmies();
        armies.forEach(army => {
            const actors = army.getActors();
            const ids = actors.map(actor => actor.getID());

            actors.forEach(actor => {
                if (!this.actorDesertedBattle(actor, battle)) {
                    const badge = new RG.Component.BattleBadge();
                    const battleData = {
                        name: battle.getName(),
                        army: army.getName(),
                        allies: ids,
                        status: army.isDefeated() ? 'Lost' : 'Won'
                    };
                    badge.setData(battleData);
                    actor.add(badge);

                    actor.remove('InBattle');
                    actor.add(new RG.Component.BattleOver());
                }
            });
        });
    };

    this.actorDesertedBattle = (actor, battle) => {
        const badgeList = actor.getList('BattleBadge');
        const badge = badgeList.find(b => (
            b.getData().name === battle.getName()
        ));
        if (badge) {return true;}
        return false;
    };

    /* Moves actors out of the battle level into the parent level of the battle
     * (at the moment this is always Area.Tile level. */
    this.moveActorsOutOfBattle = battle => {
        const level = battle.getLevel();
        const conns = level.getConnections();

        if (!conns || conns.length === 0) {
            RG.err('Game.Master', 'moveActorsOutOfBattle',
                'No exit connnection in level');
        }

        const exit = conns[0];
        const targetLevel = exit.getTargetLevel();

        const armies = battle.getArmies();
        armies.forEach(army => {
            const actors = army.getActors();
            actors.forEach(actor => {
                if (!actor.isPlayer()) {
                    if (level.removeActor(actor)) {
                        debug(`Rm actor ${actor.getID()},${actor.getName()}`);
                        targetLevel.addActorToFreeCell(actor);
                    }
                    else {
                        const json = JSON.stringify(actor.toJSON());
                        RG.err('Game.Master', 'moveActorsOutOfBattle',
                            `level.removeActor failed for actor ${json}`);
                    }
                }
                else {
                    const selObj = this.getSelLeaveBattle(actor, level);
                    actor.getBrain().setSelectionObject(selObj);
                }
            });
        });

    };

    /* Returns the selection object for player to select an army. */
    this.getSelArmyObject = function(player, battle) {
        return {
            showMenu: () => true,
            getMenu: () => {
                RG.gameMsg('Please select an army to join:');
                const armies = battle.getArmies();
                const menuObj = {};
                armies.forEach((army, i) => {
                    menuObj[i] = ' Army ' + army.getName();
                });
                menuObj['Any other key'] = 'Take no side';
                return menuObj;
            },
            select: code => {
                const selection = RG.codeToIndex(code);
                const armies = battle.getArmies();
                if (selection < armies.length) {
                    const army = armies[selection];
                    return () => {
                        const battleLevel = battle.getLevel();
                        let armyActors = army.getActors();
                        const nActors = armyActors.length;
                        const pIndex = RG.RAND.getUniformInt(0, nActors);
                        const replacedActor = armyActors[pIndex];
                        const [pX, pY] = replacedActor.getXY();

                        // Remove substituted actor from army/level
                        replacedActor.get('Action').disable();
                        army.removeActor(replacedActor);
                        battleLevel.removeActor(replacedActor);

                        armyActors = army.getActors();
                        army.addActor(player);

                        player.get('InBattle').updateData({army: army.getName});
                        armyActors.forEach(actor => {
                            actor.addFriend(player);
                        });

                        armies.forEach(enemyArmy => {
                            if (enemyArmy !== army) {
                                const enemies = enemyArmy.getActors();
                                enemies.forEach(enemy => {
                                    enemy.addEnemy(player);
                                });
                            }
                        });

                        if (!battleLevel.moveActorTo(player, pX, pY)) {
                            RG.err('GameMaster', 'getSelArmyObject',
                                `Could not move player to ${pX},${pY}`);
                        }
                    };
                }
                return null;
            }
        };
    };

    this.getSelLeaveBattle = function(player, level) {
        const selObj = function() {
            this.showMenu = () => true;
            this.getMenu = () => {
                RG.gameMsg('Battle is over! Do you want to leave battle?');
                return {
                    0: 'Leave immediately',
                    1: 'Stay behind to scavenge the bodies of the dead.'
                };
            };
            this.select = code => {
                const selection = RG.codeToIndex(code);
                if (selection === 0) {
                    return () => {
                        const exit = level.getConnections()[0];
                        if (!exit.useStairs(player)) {
                            RG.err('GameMaster', 'moveActorsOutOfBattle',
                                'Cannot move player via useStairs');
                        }
                        else {
                            const name = player.getName();
                            RG.gameMsg(`${name} leaves the battlefield`);
                        }
                    };
                }
                if (selection === 1) {
                    // TODO add some dishonor for the player or some necromancy
                    // effect etc
                    return null;
                }
                return this;
            };
        };
        return new selObj();
    };

    /* Serializes the object into JSON. */
    this.toJSON = function() {
        const keys = Object.keys(this.battles);
        const battles = {};
        keys.forEach(id => {
            battles[id] = this.battles[id].toJSON();
        });
        return {
            battles,
            battlesDone: this.battlesDone
        };
    };

    this.biomeToLevelType = function(biome) {
        switch (biome) {
            case OW.BIOME.ARCTIC: return 'arctic';
            case OW.BIOME.TUNDRA: return 'arctic';
            case OW.BIOME.ALPINE: return 'mountain';
            case OW.BIOME.TAIGA: return 'forest';
            default: return 'forest';
        }
    };

    this.getBattleLevels = function() {
        const levels = [];
        Object.values(this.battles).forEach(battle => {
            levels.push(battle.getLevel());
        });
        return levels;

    };
};

module.exports = GameMaster;
<|endoftext|>


<commit_before>Package.describe({
    summary: "Accounts Templates styled for Twitter Bootstrap.",
    version: "0.9.15",
    name: "splendido:accounts-templates-bootstrap",
    git: "https://github.com/splendido/accounts-templates-bootstrap.git",
});

Package.on_use(function(api, where) {
    api.versionsFrom("METEOR@0.9.2.2");

    api.use([
        "less",
        "templating",
    ], "client");

    api.use([
        "splendido:accounts-templates-core",
    ], ["client", "server"]);

    api.imply([
        "splendido:accounts-templates-core@0.9.15",
    ], ["client", "server"]);

    api.add_files([
        "lib/at_error.html",
        "lib/at_error.js",
        "lib/at_form.html",
        "lib/at_form.js",
        "lib/at_input.html",
        "lib/at_input.js",
        "lib/at_oauth.html",
        "lib/at_oauth.js",
        "lib/at_pwd_form.html",
        "lib/at_pwd_form.js",
        "lib/at_pwd_form_btn.html",
        "lib/at_pwd_form_btn.js",
        "lib/at_pwd_link.html",
        "lib/at_pwd_link.js",
        "lib/at_result.html",
        "lib/at_result.js",
        "lib/at_sep.html",
        "lib/at_sep.js",
        "lib/at_signin_link.html",
        "lib/at_signin_link.js",
        "lib/at_signup_link.html",
        "lib/at_signup_link.js",
        "lib/at_social.html",
        "lib/at_social.js",
        "lib/at_terms_link.html",
        "lib/at_terms_link.js",
        "lib/at_title.html",
        "lib/at_title.js",
        "lib/full_page_at_form.html",
        "lib/at_bootstrap.less"
    ], ["client"]);
});

Package.on_test(function(api) {
    api.use([
        "splendido:accounts-templates-bootstrap",
        "splendido:accounts-templates-core@0.9.15",
    ]);

    api.use([
        "accounts-password",
        "tinytest",
        "test-helpers"
    ], ["client", "server"]);

    api.add_files([
        "tests/tests.js"
    ], ["client", "server"]);
});<commit_msg>patch release - Bump to version 0.9.16<commit_after>Package.describe({
    summary: "Accounts Templates styled for Twitter Bootstrap.",
    version: "0.9.16",
    name: "splendido:accounts-templates-bootstrap",
    git: "https://github.com/splendido/accounts-templates-bootstrap.git",
});

Package.on_use(function(api, where) {
    api.versionsFrom("METEOR@0.9.2.2");

    api.use([
        "less",
        "templating",
    ], "client");

    api.use([
        "splendido:accounts-templates-core",
    ], ["client", "server"]);

    api.imply([
        "splendido:accounts-templates-core@0.9.16",
    ], ["client", "server"]);

    api.add_files([
        "lib/at_error.html",
        "lib/at_error.js",
        "lib/at_form.html",
        "lib/at_form.js",
        "lib/at_input.html",
        "lib/at_input.js",
        "lib/at_oauth.html",
        "lib/at_oauth.js",
        "lib/at_pwd_form.html",
        "lib/at_pwd_form.js",
        "lib/at_pwd_form_btn.html",
        "lib/at_pwd_form_btn.js",
        "lib/at_pwd_link.html",
        "lib/at_pwd_link.js",
        "lib/at_result.html",
        "lib/at_result.js",
        "lib/at_sep.html",
        "lib/at_sep.js",
        "lib/at_signin_link.html",
        "lib/at_signin_link.js",
        "lib/at_signup_link.html",
        "lib/at_signup_link.js",
        "lib/at_social.html",
        "lib/at_social.js",
        "lib/at_terms_link.html",
        "lib/at_terms_link.js",
        "lib/at_title.html",
        "lib/at_title.js",
        "lib/full_page_at_form.html",
        "lib/at_bootstrap.less"
    ], ["client"]);
});

Package.on_test(function(api) {
    api.use([
        "splendido:accounts-templates-bootstrap",
        "splendido:accounts-templates-core@0.9.16",
    ]);

    api.use([
        "accounts-password",
        "tinytest",
        "test-helpers"
    ], ["client", "server"]);

    api.add_files([
        "tests/tests.js"
    ], ["client", "server"]);
});<|endoftext|>


<commit_before>// Vendor
import React, { Component } from 'react';
import { Button } from 'react-bootstrap';
import { Grid, Row, Col} from 'react-bootstrap';
import { FormControl, FormGroup, ControlLabel } from 'react-bootstrap';
import reqwest from 'reqwest';
// Style
import '../App.css';
// Helper
// import { debounce } from '../utils/utils'

// ------------------------------------------------------
// Initialize
const remoteUrl = 'https://api.zbcai.xyz/url/create';
// const remoteUrl = 'http://localhost:8080/url/create';

class SaveUrlForm extends Component {
    constructor(props) {
        super(props);
        this.state = {
            saving: false,
            url: "",
            shorten: "",
            typing: false,
            errorMsg: ""
        };
    };

    handleInputChange = event => {
       this.setState({
           url: event.target.value,
           typing: true,
           saving: false
       });
    };

    postUrl = (url) => {
        reqwest({
            url: remoteUrl
            , method: 'post'
            , data: { url: url }
            , success: resp => {
                if (resp.success === true) {
                    let shortenUrl = resp.shorten;
                    this.setState({
                        shorten: shortenUrl,
                        saving: false,
                        errorMsg: ""
                    });
                }
            }, header: {
                'Content-Type': 'application/json',
            }
        });
    };

    handleSave = event => {
        this.setState({
            saving: true,
            typing: false
        });
        let urlToSave = this.state.url;
        if (this.validUrl(this.state.url) === false) {
            if (this.validUrl("http://" + this.state.url) === true) {
                urlToSave = "http://" + urlToSave;
            } else {
                this.setState({
                    errorMsg: "The url is not valid, please check again."
                });
                return;
            }
        }

        this.postUrl(urlToSave);
    };

    getValidationState() {
        const url = this.state.url;
        if (this.validUrl(url) === true) {
            return 'success';
        } else {
            return (this.validUrl("http://" + url)? 'success': 'error');
        }
    };

    validUrl(str) {
        let regexp = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
        return regexp.test(str);
    };

    render() {
        let inputPlaceHolder = "Type the url you want to save...";
        return (

                <Grid>
                    <Row className="su-form-group">
                        <Col xs={10} sm={10} md={11} >
                            <form>
                                <FormGroup
                                    controlId="formBasicText"
                                    validationState={this.getValidationState()}
                                >
                                    <ControlLabel className="app__form-validator">{ inputPlaceHolder }</ControlLabel>
                                    <FormControl
                                        type="text"
                                        value={this.state.url}
                                        placeholder="Enter url"
                                        onChange={this.handleInputChange}
                                    />
                                    <FormControl.Feedback />

                                </FormGroup>
                            </form>
                        </Col>
                        <Col xs={2} sm={2} md={1} >

                                    <Button bsStyle="primary" className="app__form__btn--save" onClick={this.handleSave} disabled={this.state.saving}>
                                        {(this.state.saving && this.state.errorMsg.length === 0)
                                            ? "Saving..."
                                            : "Save"
                                        }
                                    </Button>

                        </Col>
                    </Row>
                </Grid>

                    {this.state.errorMsg
                        ? {this.state.errorMsg}
                        :
                    }

                    {(!this.state.saving && this.state.shorten.length > 0 && !this.state.typing && this.state.errorMsg.length === 0)
                        ? It's done! The url is: {this.state.shorten}
                        :
                    }

        );
    }
}

export default SaveUrlForm
<commit_msg>feat(keybinding): Performed saving url when enter pressed<commit_after>// Vendor
import React, { Component } from 'react';
import { Button } from 'react-bootstrap';
import { Grid, Row, Col} from 'react-bootstrap';
import { FormControl, FormGroup, ControlLabel } from 'react-bootstrap';
import reqwest from 'reqwest';
// Style
import '../App.css';
// Helper
// import { debounce } from '../utils/utils'

// ------------------------------------------------------
// Initialize
const remoteUrl = 'https://api.zbcai.xyz/url/create';
// const remoteUrl = 'http://localhost:8080/url/create';

class SaveUrlForm extends Component {
    constructor(props) {
        super(props);
        this.state = {
            saving: false,
            url: "",
            shorten: "",
            typing: false,
            errorMsg: ""
        };
    };

    handleInputChange = event => {
       this.setState({
           url: event.target.value,
           typing: true,
           saving: false
       });
    };

    postUrl = (url) => {
        reqwest({
            url: remoteUrl
            , method: 'post'
            , data: { url: url }
            , success: resp => {
                if (resp.success === true) {
                    let shortenUrl = resp.shorten;
                    this.setState({
                        shorten: shortenUrl,
                        saving: false,
                        errorMsg: ""
                    });
                }
            }, header: {
                'Content-Type': 'application/json',
            }
        });
    };

    handleSave = () => {
        this.setState({
            saving: true,
            typing: false
        });
        let urlToSave = this.state.url;
        if (this.validUrl(this.state.url) === false) {
            if (this.validUrl("http://" + this.state.url) === true) {
                urlToSave = "http://" + urlToSave;
            } else {
                this.setState({
                    errorMsg: "The url is not valid, please check again."
                });
                return;
            }
        }

        this.postUrl(urlToSave);
    };

    handleSubmit = (event) => {
        event.preventDefault()
        this.handleSave()
    }

    getValidationState() {
        const url = this.state.url;
        if (this.validUrl(url) === true) {
            return 'success';
        } else {
            return (this.validUrl("http://" + url)? 'success': 'error');
        }
    }

    validUrl(str) {
        let regexp = /^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/i;
        return regexp.test(str);
    };

    render() {
        let inputPlaceHolder = "Type the url you want to save...";
        return (

                <Grid>
                    <Row className="su-form-group">
                        <Col xs={10} sm={10} md={11} >
                            <form onSubmit={this.handleSubmit}>
                                <FormGroup
                                    controlId="formBasicText"
                                    validationState={this.getValidationState()}
                                >
                                    <ControlLabel className="app__form-validator">{ inputPlaceHolder }</ControlLabel>
                                    <FormControl
                                        type="text"
                                        value={this.state.url}
                                        placeholder="Enter url"
                                        onChange={this.handleInputChange}
                                    />
                                    <FormControl.Feedback />

                                </FormGroup>
                            </form>
                        </Col>
                        <Col xs={2} sm={2} md={1} >

                                    <Button bsStyle="primary" className="app__form__btn--save" onClick={this.handleSave} disabled={this.state.saving}>
                                        {(this.state.saving && this.state.errorMsg.length === 0)
                                            ? "Saving..."
                                            : "Save"
                                        }
                                    </Button>

                        </Col>
                    </Row>
                </Grid>

                    {this.state.errorMsg
                        ? {this.state.errorMsg}
                        :
                    }

                    {(!this.state.saving && this.state.shorten.length > 0 && !this.state.typing && this.state.errorMsg.length === 0)
                        ? It's done! The url is: {this.state.shorten}
                        :
                    }

        );
    }
}

export default SaveUrlForm
<|endoftext|>