<commit_before>const request = require('./request');
const Promise = require('bluebird');
const fetchFiles = require('./fetchFiles');
const getCopyAndDownloadList = require('./getCopyAndDownloadList');
const compareWithCurrentVersion = require('./compareWithCurrentVersion');
const parseResponseToObject = require('./parseResponseToObject');
const urlJoin = require('url-join');
const updateCCSConfig = require('./updateCCSConfig');
const getContentUrl = require('./getContentUrl');
var initialized = false;
var ccs = JSON.parse(localStorage.ccs || JSON.stringify({}));
var _instanceOptions;
const defaultOptions = {
	entryFile: 'index.html',
	headers: {
		'User-Agent': 'Cordova-Code-Swap'
	},
	debug: false
};
var isLookingForUpdates = false;
var isDownloading = false;
var isInstalling = false;

/**
 * PUBLIC
 * Initialize the CCS instance
 * Switches to the last downloaded update if any
 * @return {Promise}
 */
function initialize(instanceOptions = {}) {
	return new Promise((resolve) => {
		if (!initialized) {
			_instanceOptions = Object.assign({}, { backupCount: 1 }, instanceOptions);
			initialized = true;
		}

		if (ccs.entryPoint && ccs.entryPoint !== window.location.href) {
			window.location.href = ccs.entryPoint;
		} else {
			resolve();
		}
	});
}

/**
 * PUBLIC
 * Looks for updates on the server
 * @param  {String} url     Url to the update server
 * @param  {Object} options Options to use when communicating with the server. See https://www.npmjs.com/package/request
 * @return {Promise}		Resolves with download function, rejects with error.
 */
function lookForUpdates(url, options = {}) {
	if (!initialized) {
		return Promise.reject(new Error('cordova-code-swap: .initialize() needs to be run before looking for updates. It should be the first thing to be run in the application.'));
	}

	if (isLookingForUpdates) {
		return Promise.reject(new Error('cordova-code-swap: .lookForUpdates is already running.'));
	}

	options = Object.assign({}, defaultOptions, options);
	const updateDeclaration = urlJoin(url, 'chcp.json');
	isLookingForUpdates = true;

	return request.get(updateDeclaration, { headers: options.headers })
		.then(parseResponseToObject)
		.then(updateInfo => compareWithCurrentVersion(ccs, updateInfo))
		.then(updateInfo => {
			updateInfo.content_url = getContentUrl(url, updateInfo);
			var downloadFunction = _download.bind(null, updateInfo, options);
			downloadFunction.updateInfo = updateInfo;
			isLookingForUpdates = false;
			return downloadFunction;
		})
		.catch(err => {
			isLookingForUpdates = false;
			throw err;
		});
}

/**
 * Get the update - this function is returned in the resolved promise of lookForUpdates
 * @param  {Object} updateInfo	The info received from the server
 * @param  {Object} options     Options to use when communicating with the server. See https://www.npmjs.com/package/request
 * @return {Promise}			Resolves with install function, rejects with error
 */
function _download(updateInfo, options, progressCallback) {
	if (isDownloading) {
		throw new Error('cordova-code-swap: A download is already in progress.');
	}

	// make a local copy of updateInfo so it can be mutated
	let updateInfoClone = Object.assign({}, updateInfo);
	isDownloading = true;

	var contentUrl = updateInfoClone.content_url;
	var manifestUrl = urlJoin(contentUrl, 'chcp.manifest');
	return request.get(manifestUrl, { headers: options.headers })
		.then(parseResponseToObject)
		.then(serverManifest => {
			updateInfoClone.manifest = serverManifest;
			return getCopyAndDownloadList(ccs.manifest, serverManifest);
		})
		.then(fetchList => fetchFiles(ccs, fetchList, updateInfoClone, options, progressCallback))
		.then(() => {
			ccs.pendingInstallation = {};
			ccs.pendingInstallation.updateInfo = updateInfoClone;
			ccs.pendingInstallation.options = options;
			localStorage.ccs = JSON.stringify(ccs);

			isDownloading = false;
			return _install.bind(null, updateInfoClone, options);
		})
		.catch(err => {
			ccs.pendingInstallation = false;
			isDownloading = false;
			localStorage.ccs = JSON.stringify(ccs);
			throw err;
		});
}

/**
 * Install the update - this function is returned in the resolved promise of _download
 * @param  {Object} updateInfo The info received from the server
 * @param  {Object} options    Name of the entry point when redirecting to this update
 * @return {Promise}
 */
function _install(updateInfo, options) {
	if (isInstalling) {
		Promise.reject('cordova-code-swap: An installation is already in progress');
	}
	const deleteBackups = require('./deleteBackups');
	isInstalling = true;

	// create new config with settings needed to load the newly installed version
	ccs = updateCCSConfig(ccs, updateInfo, options);

	// find obsolete backups
	let sortedBackups = ccs.backups.sort((b1, b2) => b1.timestamp || 0 < b2.timestamp || 0);
	let backupsToDelete = sortedBackups.slice(_instanceOptions.backupCount, sortedBackups.length);

	// update the current the backup list
	ccs.backups = sortedBackups.slice(0, _instanceOptions.backupCount);

	return Promise.resolve()
		.then(() => options.debug ? null : deleteBackups(backupsToDelete))
		.then(() => { localStorage.ccs = JSON.stringify(ccs); })
		.then(
			() => { isInstalling = false; },
			err => { isInstalling = false; throw err; }
		)
		.then(() => options.debug ? new Promise(() => window.location.reload()) : initialize());
}

/**
 * PUBLIC
 * Install a previously downloaded update that has not been installed. See documentation.
 * @return {Promise}
 */
function install() {
	if (ccs.pendingInstallation) {
		return _install(ccs.pendingInstallation.updateInfo, ccs.pendingInstallation.options);
	} else {
		return Promise.reject(new Error('cordova-code-swap: Tried to install update, but no updates have been previously downloaded.'));
	}
}

module.exports = { initialize, lookForUpdates, install };
<commit_msg>Does not try to access localstorage until initialize is called. Renamed local variables. ccs.install() can not be called until ccs.initialize() has been called.<commit_after>const request = require('./request');
const Promise = require('bluebird');
const fetchFiles = require('./fetchFiles');
const getCopyAndDownloadList = require('./getCopyAndDownloadList');
const compareWithCurrentVersion = require('./compareWithCurrentVersion');
const parseResponseToObject = require('./parseResponseToObject');
const urlJoin = require('url-join');
const updateCCSConfig = require('./updateCCSConfig');
const getContentUrl = require('./getContentUrl');
var _initialized = false;
var _ccs;
var _instanceOptions;
const defaultOptions = {
	entryFile: 'index.html',
	headers: {
		'User-Agent': 'Cordova-Code-Swap'
	},
	debug: false
};
var isLookingForUpdates = false;
var isDownloading = false;
var isInstalling = false;

/**
 * PUBLIC
 * Initialize the CCS instance
 * Switches to the last downloaded update if any
 * @return {Promise}
 */
function initialize(instanceOptions = {}) {
	return new Promise((resolve) => {
		// fetch ccs config from localStorage if not fetched before
		_ccs = _ccs || JSON.parse(localStorage.ccs || JSON.stringify({}));

		if (!_initialized) {
			_instanceOptions = Object.assign({}, { backupCount: 1 }, instanceOptions);
			_initialized = true;
		}

		if (_ccs.entryPoint && _ccs.entryPoint !== window.location.href) {
			window.location.href = _ccs.entryPoint;
		} else {
			resolve();
		}
	});
}

/**
 * PUBLIC
 * Looks for updates on the server
 * @param  {String} url     Url to the update server
 * @param  {Object} options Options to use when communicating with the server. See https://www.npmjs.com/package/request
 * @return {Promise}		Resolves with download function, rejects with error.
 */
function lookForUpdates(url, options = {}) {
	if (!_initialized) {
		return Promise.reject(new Error('cordova-code-swap: .initialize() needs to be run before looking for updates. It should be the first thing to be run in the application.'));
	}

	if (isLookingForUpdates) {
		return Promise.reject(new Error('cordova-code-swap: .lookForUpdates is already running.'));
	}

	options = Object.assign({}, defaultOptions, options);
	const updateDeclaration = urlJoin(url, 'chcp.json');
	isLookingForUpdates = true;

	return request.get(updateDeclaration, { headers: options.headers })
		.then(parseResponseToObject)
		.then(updateInfo => compareWithCurrentVersion(_ccs, updateInfo))
		.then(updateInfo => {
			updateInfo.content_url = getContentUrl(url, updateInfo);
			var downloadFunction = _download.bind(null, updateInfo, options);
			downloadFunction.updateInfo = updateInfo;
			isLookingForUpdates = false;
			return downloadFunction;
		})
		.catch(err => {
			isLookingForUpdates = false;
			throw err;
		});
}

/**
 * Get the update - this function is returned in the resolved promise of lookForUpdates
 * @param  {Object} updateInfo	The info received from the server
 * @param  {Object} options     Options to use when communicating with the server. See https://www.npmjs.com/package/request
 * @return {Promise}			Resolves with install function, rejects with error
 */
function _download(updateInfo, options, progressCallback) {
	if (isDownloading) {
		throw new Error('cordova-code-swap: A download is already in progress.');
	}

	// make a local copy of updateInfo so it can be mutated
	let updateInfoClone = Object.assign({}, updateInfo);
	isDownloading = true;

	var contentUrl = updateInfoClone.content_url;
	var manifestUrl = urlJoin(contentUrl, 'chcp.manifest');
	return request.get(manifestUrl, { headers: options.headers })
		.then(parseResponseToObject)
		.then(serverManifest => {
			updateInfoClone.manifest = serverManifest;
			return getCopyAndDownloadList(_ccs.manifest, serverManifest);
		})
		.then(fetchList => fetchFiles(_ccs, fetchList, updateInfoClone, options, progressCallback))
		.then(() => {
			_ccs.pendingInstallation = {};
			_ccs.pendingInstallation.updateInfo = updateInfoClone;
			_ccs.pendingInstallation.options = options;
			localStorage.ccs = JSON.stringify(_ccs);

			isDownloading = false;
			return _install.bind(null, updateInfoClone, options);
		})
		.catch(err => {
			_ccs.pendingInstallation = false;
			isDownloading = false;
			localStorage.ccs = JSON.stringify(_ccs);
			throw err;
		});
}

/**
 * Install the update - this function is returned in the resolved promise of _download
 * @param  {Object} updateInfo The info received from the server
 * @param  {Object} options    Name of the entry point when redirecting to this update
 * @return {Promise}
 */
function _install(updateInfo, options) {
	if (isInstalling) {
		Promise.reject('cordova-code-swap: An installation is already in progress');
	}
	const deleteBackups = require('./deleteBackups');
	isInstalling = true;

	// create new config with settings needed to load the newly installed version
	_ccs = updateCCSConfig(_ccs, updateInfo, options);

	// find obsolete backups
	let sortedBackups = _ccs.backups.sort((b1, b2) => b1.timestamp || 0 < b2.timestamp || 0);
	let backupsToDelete = sortedBackups.slice(_instanceOptions.backupCount, sortedBackups.length);

	// update the current the backup list
	_ccs.backups = sortedBackups.slice(0, _instanceOptions.backupCount);

	return Promise.resolve()
		.then(() => options.debug ? null : deleteBackups(backupsToDelete))
		.then(() => { localStorage.ccs = JSON.stringify(_ccs); })
		.then(
			() => { isInstalling = false; },
			err => { isInstalling = false; throw err; }
		)
		.then(() => options.debug ? new Promise(() => window.location.reload()) : initialize());
}

/**
 * PUBLIC
 * Install a previously downloaded update that has not been installed. See documentation.
 * @return {Promise}
 */
function install() {
	if (!_initialized) {
		return Promise.reject(new Error('cordova-code-swap: .initialize() needs to be run before looking for updates. It should be the first thing to be run in the application.'));
	}
	if (_ccs.pendingInstallation) {
		return _install(_ccs.pendingInstallation.updateInfo, _ccs.pendingInstallation.options);
	} else {
		return Promise.reject(new Error('cordova-code-swap: Tried to install update, but no updates have been previously downloaded.'));
	}
}

module.exports = { initialize, lookForUpdates, install };
<|endoftext|>


<commit_before>import Synth from './WebSynth'

const win = window || {};

//TODO manage module.exports....etc...

win.WebSynth = Synth;

<commit_msg>index<commit_after>import WebSynth from './WebSynth'

const win = window || {};

win.WebSynth = WebSynth;

<|endoftext|>


<commit_before>import 'babel-polyfill';
import React from 'react';
import {render} from 'react-dom';
import {Router, browserHistory} from 'react-router';
import routes from './routes';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';

render(
  <Router routes={routes} history={browserHistory} />,
  document.getElementById('app')
);
<commit_msg>wrap entry point with Provider<commit_after>import 'babel-polyfill';
import React from 'react';
import {Provider} from 'react-redux';
import {render} from 'react-dom';
import {Router, browserHistory} from 'react-router';
import routes from './routes';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';

import configureStore from './store/configureStore';

const store = configureStore();

render(
  <Provider store={store}>
    <Router routes={routes} history={browserHistory} />
  </Provider>,
  document.getElementById('app')
);
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import Star from './star'

export { Star } from './star'

export default class Rater extends Component {
  constructor(props) {
    super(props)
    this.state = {
      lastRating: props.rating,
      rating: props.rating,
      isRating: false
    }
  }
  componentWillReceiveProps(nextProps) {
    this.setState({
      rating: nextProps.rating
    })
  }
  handleMouseEnter(e) {
    let { rating } = getRatingFromDOMEvent(e, this.props)
    if (rating > 0) {
      this.setState({
        rating: 0,
        isRating: true
      })
    }
  }
  handleMouseMove(e) {
    let { rating } = getRatingFromDOMEvent(e, this.props)
      , callback = this.props.onRate
    if (rating > 0) {
      this.setState({
        rating: rating,
        isRating: true
      })
      callback && callback(rating)
    }
  }
  handleMouseLeave() {
    let callback = this.props.onRate
      , state = this.state
    callback && callback(state.lastRating)
    this.setState({
      rating: state.lastRating,
      isRating: false
    })
  }
  handleClick(e) {
    let { index, rating } = getRatingFromDOMEvent(e, this.props)
      , lastRating = Number(this.state.lastRating)
      , callback = this.props.onRate
    if (rating < 0 || this.refs[`star-${index}`].props.isDisabled) {
      return
    }
    this.setState({
      rating,
      lastRating: rating
    })
    callback && callback(rating, lastRating)
  }
  render() {
    let total = Number(this.props.total)
      , limit = Number(this.props.limit)
      , rating = Number(this.state.rating)
      , interactive = this.props.interactive
      , children = Array.prototype.concat(this.props.children).filter(Boolean)
      , nodes
    limit = (this.props.limit === void 0)? total: limit
    nodes = Array(total).join(',').split(',').map((_, i) => {
      let starProps = {
        isActive: (!this.state.isRating && i < rating) ? true: false,
        willBeActive: (this.state.isRating && i < rating)? true: false,
        isDisabled: (i < limit) ? false: true,
        key: `star-${i}`,
        ref: `star-${i}`
      }
      if (children.length) {
        return React.cloneElement(children[i % children.length], starProps)
      } else {
        return (<Star {...starProps} />)
      }
    })
    if (interactive) {
      return (

{nodes}

      )
    } else {
      return (

{nodes}

      )
    }
  }
}

Rater.defaultProps = {
  total: 5,
  rating: 0,
  interactive: true
}

Rater.propTypes = {
  total: PropTypes.number,
  rating: PropTypes.number,
  limit: PropTypes.number,
  interactive: PropTypes.bool,
  onRate: PropTypes.func,
  children: PropTypes.any
}

function getRatingFromDOMEvent(e, props) {
  let allStars = Array.apply(null, e.currentTarget.childNodes)
    , star = findStarDOMNode(e.target, allStars, e.currentTarget)
    , index = allStars.indexOf(star)
    , rating = index + 1
    , limit = Number(props.limit)
  if (index < 0) {
    return {
      index,
      rating: -1
    }
  }
  limit = (props.limit === void 0)? props.total: limit
  rating = rating < limit? rating: limit
  return {
    index,
    rating: Number(rating)
  }
}

function findStarDOMNode(node, stars, container) {
  while(node !== container && stars.indexOf(node) === -1) {
    node = node.parentNode
  }
  return node
}
<commit_msg>Fixed unknown prop issue<commit_after>import React, { Component, PropTypes } from 'react'
import Star from './star'

export { Star } from './star'

export default class Rater extends Component {
  constructor(props) {
    super(props)
    this.state = {
      lastRating: props.rating,
      rating: props.rating,
      isRating: false
    }
  }
  componentWillReceiveProps(nextProps) {
    this.setState({
      rating: nextProps.rating
    })
  }
  handleMouseEnter(e) {
    let { rating } = getRatingFromDOMEvent(e, this.props)
    if (rating > 0) {
      this.setState({
        rating: 0,
        isRating: true
      })
    }
  }
  handleMouseMove(e) {
    let { rating } = getRatingFromDOMEvent(e, this.props)
      , callback = this.props.onRate
    if (rating > 0) {
      this.setState({
        rating: rating,
        isRating: true
      })
      callback && callback(rating)
    }
  }
  handleMouseLeave() {
    let callback = this.props.onRate
      , state = this.state
    callback && callback(state.lastRating)
    this.setState({
      rating: state.lastRating,
      isRating: false
    })
  }
  handleClick(e) {
    let { index, rating } = getRatingFromDOMEvent(e, this.props)
      , lastRating = Number(this.state.lastRating)
      , callback = this.props.onRate
    if (rating < 0 || this.refs[`star-${index}`].props.isDisabled) {
      return
    }
    this.setState({
      rating,
      lastRating: rating
    })
    callback && callback(rating, lastRating)
  }
  render() {
    let {total, limit, rating, interactive, children, ...others} = this.props
    total = Number(total)
    limit = Number(limit)
    rating = Number(this.state.rating)
    children = Array.prototype.concat(children).filter(Boolean)
    limit = (this.props.limit === void 0)? total: limit
    let nodes = Array(total).join(',').split(',').map((_, i) => {
      let starProps = {
        isActive: (!this.state.isRating && i < rating) ? true: false,
        willBeActive: (this.state.isRating && i < rating)? true: false,
        isDisabled: (i < limit) ? false: true,
        key: `star-${i}`,
        ref: `star-${i}`
      }
      if (children.length) {
        return React.cloneElement(children[i % children.length], starProps)
      } else {
        return (<Star {...starProps} />)
      }
    })
    if (interactive) {
      return (

{nodes}

      )
    } else {
      return (

{nodes}

      )
    }
  }
}

Rater.defaultProps = {
  total: 5,
  rating: 0,
  interactive: true
}

Rater.propTypes = {
  total: PropTypes.number,
  rating: PropTypes.number,
  limit: PropTypes.number,
  interactive: PropTypes.bool,
  onRate: PropTypes.func,
  children: PropTypes.any
}

function getRatingFromDOMEvent(e, props) {
  let allStars = Array.apply(null, e.currentTarget.childNodes)
    , star = findStarDOMNode(e.target, allStars, e.currentTarget)
    , index = allStars.indexOf(star)
    , rating = index + 1
    , limit = Number(props.limit)
  if (index < 0) {
    return {
      index,
      rating: -1
    }
  }
  limit = (props.limit === void 0)? props.total: limit
  rating = rating < limit? rating: limit
  return {
    index,
    rating: Number(rating)
  }
}

function findStarDOMNode(node, stars, container) {
  while(node !== container && stars.indexOf(node) === -1) {
    node = node.parentNode
  }
  return node
}
<|endoftext|>


<commit_before>// Module must be started with environment variables
//
//  accesskey="api.ai client access key"
//  subscriptionkey="api.ai subscription key"
//  slackkey="slack bot key"
//

'use strict';

const Botkit = require('botkit');

const apiai = require('apiai');
const uuid = require('node-uuid');

const http = require('http');

const Entities = require('html-entities').XmlEntities;
const decoder = new Entities();

const apiAiAccessToken = process.env.accesstoken;
const apiAiSubscriptionKey = process.env.subscriptionkey;
const slackBotKey = process.env.slackkey;

const apiAiService = apiai(apiAiAccessToken, apiAiSubscriptionKey);

var sessionIds = {};

const controller = Botkit.slackbot({
    debug: false
    //include "log: false" to disable logging
});

var bot = controller.spawn({
    token: slackBotKey
}).startRTM();

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

controller.hears(['.*'], ['bot_message'], function (bot, message) {

    try {
        if (message.type == 'message') {
            if (message.user == bot.identity.id) {
                // message from bot can be skipped
            }
            else if (message.text.indexOf("<@U") == 0 && message.text.indexOf(bot.identity.id) == -1) {
                // skip other users direct mentions
            }
            else if (message.text.includes("Sent text to")) {
                // skip sent text confirmations from Burner
                console.log('Skipping Burner response.');
            }
            else {

                var requestText = decoder.decode(message.text);
                requestText = requestText.replace("’", "'");

                var burnerMesageRegex = /Inbound message from \+(\d*):\s(.*)/;
                var returnNumber = '';
                var smsMessage;

                // Parse the SMS message and return number out of Burner's slackbot message
                if ((smsMessage = burnerMesageRegex.exec(requestText)) !== null) {
                    returnNumber = '@' + smsMessage[1];
                    requestText = smsMessage[2];

                    console.log('returnNumber', returnNumber);
                    console.log('requestText', requestText);
                }

                var channel = message.channel;
                var messageType = message.event;
                var botId = "<@" + bot.identity.id + ">";

                console.log(messageType);

                if (requestText.indexOf(botId) > -1) {
                    requestText = requestText.replace(botId, '');
                }

                if (!(channel in sessionIds)) {
                    sessionIds[channel] = uuid.v1();
                }

                var request = apiAiService.textRequest(requestText,
                    {
                        sessionId: sessionIds[channel]
                    });

                request.on('response', function (response) {
                    console.log(response);

                    if (isDefined(response.result)) {
                        // Preface the response with the appropriate Burner command and phone
                        // number for the response SMS message.
                        var responseText = '/burner text ' + returnNumber + ' ' + response.result.fulfillment.speech;
                        var action = response.result.action;

                        if (isDefined(responseText)) {
                            bot.reply(message, responseText, function (err, resp) {
                                console.log(err, resp);
                            });
                        }

                    }
                });

                request.on('error', function (error) {
                    console.error(error);
                });

                request.end();
            }
        }
    } catch (err) {
        console.error(err);
    }

});

//Create a server to prevent Heroku kills the bot
var server = http.createServer(function (req, res) {
    res.end()
});

//Lets start our server
server.listen((process.env.PORT || 5000), function () {
    console.log("Server listening");
});<commit_msg>Revert "Switch to new Burner Slackbot text message syntax"<commit_after>// Module must be started with environment variables
//
//  accesskey="api.ai client access key"
//  subscriptionkey="api.ai subscription key"
//  slackkey="slack bot key"
//

'use strict';

const Botkit = require('botkit');

const apiai = require('apiai');
const uuid = require('node-uuid');

const http = require('http');

const Entities = require('html-entities').XmlEntities;
const decoder = new Entities();

const apiAiAccessToken = process.env.accesstoken;
const apiAiSubscriptionKey = process.env.subscriptionkey;
const slackBotKey = process.env.slackkey;

const apiAiService = apiai(apiAiAccessToken, apiAiSubscriptionKey);

var sessionIds = {};

const controller = Botkit.slackbot({
    debug: false
    //include "log: false" to disable logging
});

var bot = controller.spawn({
    token: slackBotKey
}).startRTM();

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

controller.hears(['.*'], ['bot_message'], function (bot, message) {

    try {
        if (message.type == 'message') {
            if (message.user == bot.identity.id) {
                // message from bot can be skipped
            }
            else if (message.text.indexOf("<@U") == 0 && message.text.indexOf(bot.identity.id) == -1) {
                // skip other users direct mentions
            }
            else if (message.text.includes("Sent text to")) {
                // skip sent text confirmations from Burner
                console.log('Skipping Burner response.');
            }
            else {

                var requestText = decoder.decode(message.text);
                requestText = requestText.replace("’", "'");

                var burnerMesageRegex = /Inbound message from \+(\d*):\s(.*)/;
                var returnNumber = '';
                var smsMessage;

                // Parse the SMS message and return number out of Burner's slackbot message
                if ((smsMessage = burnerMesageRegex.exec(requestText)) !== null) {
                    returnNumber = '@' + smsMessage[1];
                    requestText = smsMessage[2];

                    console.log('returnNumber', returnNumber);
                    console.log('requestText', requestText);
                }

                var channel = message.channel;
                var messageType = message.event;
                var botId = "<@" + bot.identity.id + ">";

                console.log(messageType);

                if (requestText.indexOf(botId) > -1) {
                    requestText = requestText.replace(botId, '');
                }

                if (!(channel in sessionIds)) {
                    sessionIds[channel] = uuid.v1();
                }

                var request = apiAiService.textRequest(requestText,
                    {
                        sessionId: sessionIds[channel]
                    });

                request.on('response', function (response) {
                    console.log(response);

                    if (isDefined(response.result)) {
                        // Preface the response with the appropriate return SMS number.
                        var responseText = returnNumber + ' ' + response.result.fulfillment.speech;
                        var action = response.result.action;

                        if (isDefined(responseText)) {
                            bot.reply(message, responseText, function (err, resp) {
                                console.log(err, resp);
                            });
                        }

                    }
                });

                request.on('error', function (error) {
                    console.error(error);
                });

                request.end();
            }
        }
    } catch (err) {
        console.error(err);
    }

});

//Create a server to prevent Heroku kills the bot
var server = http.createServer(function (req, res) {
    res.end()
});

//Lets start our server
server.listen((process.env.PORT || 5000), function () {
    console.log("Server listening");
});<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';

import SearchBar from './components/SearchBar';
import Users from './components/Users';
import RepoRow from './components/RepoRow';
import Repos from './components/Repos';

import stateStore from './tempstore/stateStore';
import githubApi from './utility/GithubApi';

class GithubSearch extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            inputName: '',
            filterReposName: '',
            isBelow20: false,
            userInfo: {
                login: '',
                id: 0,
                avatar_url: ''
            },
            userRepos: [],
            stateIndex: 0
        }
        this.btnClick = this
            .btnClick
            .bind(this);
        //Event 1
        this.userNameChange = this
            .userNameChange
            .bind(this);
        this.checkboxChange = this
            .checkboxChange
            .bind(this);
        this.reposChange = this
            .reposChange
            .bind(this);

        //Event 2
        this.userInput = this
            .userInput
            .bind(this);
    }

    //Event 1
    userNameChange(e) {
        console.log(e.target.value);
        this.setState({
            inputName: e.target.value,
            stateIndex: this.state.stateIndex + 1
        });
    }

    checkboxChange(e) {
        console.log(e.target.checked);
        this.setState({
            isBelow20: e.target.checked,
            stateIndex: this.state.stateIndex + 1
        });
    }

    reposChange(e) {
        console.log(e.target.value);
        this.setState({
            filterReposName: e.target.value,
            stateIndex: this.state.stateIndex + 1
        });
    }
    //End Event 1
    btnClick(e) {
        githubApi
            .getGithubAll(this.state.inputName)
            .then((result) => {
                let [user,
                    repos] = result;
    console.log('ttt',user.data,result, repos);
                this.setState({
                    userInfo: {
                        login: user.data.login,
                        id: user.data.id,
                        avatar_url: user.data.avatar_url
                    },
                    userRepos: repos.data,
                    stateIndex: this.state.stateIndex + 1
                });

            });
    }

    //Event 2
    userInput(userName, filterRepoName, isBelow20) {
        this.setState({inputName: userName, filterRepoName: filterRepoName, isBelow20: isBelow20});
        console.log('userName:', userName);
        console.log('filterRepoName:', filterRepoName);
        console.log('isBelow20:', isBelow20);
    }
    //End Event 2

    render() {
        //myState.store.set(this.state.stateIndex, this.state);
        return (

                <fieldset>
                    <legend>Event 1</legend>
                    <SearchBar
                        btnClick={this.btnClick}
                        userNameChange={this.userNameChange}
                        checkboxChange={this.checkboxChange}
                        reposChange={this.reposChange}
                        inputName={this.state.inputName}
                        filterRepoName={this.state.filterReposName}
                        isBelow20={this.state.isBelow20}/>
                </fieldset>

                <fieldset>
                    <legend>Event 2</legend>
                    <SearchBar userInput={this.userInput} btnClick={this.btnClick}/>
                </fieldset>

                <Users userInfo={this.state.userInfo}/>

                <Repos
                    userRepos={this.state.userRepos}
                    filterRepoName
                    ={this.state.filterReposName}
                    isBelow20={this.state.isBelow20}/>

        )
    }
}

ReactDOM.render(
    <GithubSearch/>, document.getElementById('app'));<commit_msg>Delete index.js<commit_after><|endoftext|>


<commit_before>"use strict";

var File = require("src-dest");
var types = require("dis-isa");
var utils = require("belty");
var EventEmitter = require("events");
var Stream = require("stream");
var es = require("event-stream");
var loaderFactory = require("./loader/factory");
var bundlerFactory = require("./bundler/factory");
var Bundle = require("./bundle");
var Context = require("./context");
var bundleWriter = require("./bundle/writer");
var watch = require("./watch");
var logging = require("./logging");
var buildstats = require("../loggers/buildstats");

var logger = logging.create("bundler/build");
var id = 0;

class Bitbundler extends EventEmitter {
  constructor(options) {
    super();

    this.options = Object.assign({
      baseUrl: process.cwd(),
    }, options);

    configureNotifications(this, this.options.notifications);
    configureLogger(this, this.options.log);

    this.context = null;
    this.loader = loaderFactory(this.options);
    this.bundler = bundlerFactory(this.options);
  }

  baseUrl() {
    return this.options.baseUrl;
  }

  bundle(inputFiles) {
    logger.log("build-init");

    const {entrypoint, bundle} = createMainBundle(inputFiles);
    this.context = new Context().setBundle(bundle);

    return this.update(entrypoint).then((context) => {
      if (this.options.watch) {
        watch(this, this.options.watch);
      }

      if (this.options.multiprocess) {
        if (this.options.watch) {
          this.loader.pool.size(1);
        }
        else {
          this.loader.pool.stop();
        }
      }

      return context;
    });
  }

  update(inputFile) {
    logger.log("build-start");

    return this
      .buildBundles(inputFile)
      .then((context) => {
        logger.log("build-writing");
        return bundleWriter()(context);
      })
      .then((context) => {
        context.visitBundles((bundle) => logger.log("bundle", bundle));
        logger.log("build-success", context);
        logger.log("build-end");
        this.context = context;
        return context;
      })
      .catch((err) => {
        if (err) {
          process.stderr.write((err && err.stack ? err.stack : err) + "\n");
        }

        if (this.options.multiprocess) {
          this.loader.pool.stop();
        }

        logger.error("build-failure", err);
        logger.log("build-end");
        throw err;
      });
  }

  buildBundles(inputFile) {
    // There are two way in which buildBundles runs.
    // 1. When we first kick off the bundling process. In this case, inputFile
    //    will be an entrypoint.
    // 2. When there is an update from file watching. In this case, inputFile
    //    will be a file path string.
    // getTargetsToBundle helps us get the right thing to bundle.
    const targets = getTargetsToBundle(inputFile);
    const context = this.context;
    const loader = this.loader;
    const bundler = this.bundler;

    // Clear up cached items that need to be reprocessed
    targets
      .filter(target => types.isString(target) && loader.hasModule(target))
      .map(target => loader.getModule(target))
      .forEach(mod => loader.deleteModule(mod));

    return loader
      .fetch(targets)
      .then(() => {
        const cache = loader.getCache();
        const mainBundle = context.getBundles("main");
        const moduleIds = Object.keys(cache);

        const updatedContext = context
          .setBundle(mainBundle.setModules(moduleIds))
          .setCache(cache);

        return bundler.bundle(updatedContext);
      });
  }

  getLogger(name) {
    return logging.create(name);
  }
}

Bitbundler.bundle = function(inputFiles, settings) {
  return new Bitbundler(settings).bundle(inputFiles);
};

function configureNotifications(bitbundler, notifications) {
  if (!notifications) {
    return;
  }

  [].concat(notifications).forEach((notification) => {
    if (types.isFunction(notification)) {
      notification = notification(bitbundler) || {};
    }

    Object.keys(notification).forEach((notificationName) => {
      [].concat(notification[notificationName]).forEach((cb) => {
        bitbundler.on(notificationName, cb);
      });
    });
  });
}

function configureLogger(bitbundler, options) {
  if (options === true) {
    options = {
      level: "info"
    };
  }
  else if (types.isString(options)) {
    options = {
      level: options
    };
  }
  else if (options instanceof Stream) {
    options = {
      stream: options
    };
  }

  const loggerStream = logging.pipe(es.through(function(chunk) {
    chunk.name === "bundler/build" ?
      bitbundler.emit.apply(bitbundler, chunk.data) :
      bitbundler.emit(chunk.name, chunk);

    this.emit("data", chunk);
  }));

  if (options !== false) {
    loggerStream.pipe(options && options.stream ? options.stream : buildstats(options));
  }
}

// Creates the root bundle where all things start from. If there are multiple
// bundles that need to be generated, then bundle splitting is the tool for
// the job.
function createMainBundle(inputFiles) {
  const entrypoint = createEntrypoint(inputFiles);
  const entries = entrypoint.src.map(src => {
    return types.isString(src) ? src : (src.id || src.path || "@anonymous-" + id++);
  });

  return {
    entrypoint: entrypoint,
    bundle: new Bundle("main", { dest: entrypoint.dest, entries: entries }, true),
  };
}

// createEntrypoint converts input files that need to be bundled to an
// entrypoint object with file paths to be bundled. An entrypoint is an object
// that contains three main bits of information.
// 1. src - all the file paths and module names to be loaded. file paths can
//    be globs, which are automatically expanded.
// 2. dest - where the generated bundle is going to be written to.
// 3. cwd - current working directory file paths are relative to.
//
// The goal of this function is to generate an entrypoint from all the
// different ways in which users can define files to be bundled.
//
// Files can have a few different shapes to make the API simpler to use. But it
// certainly makes the logic here much more complex so that we can handle
// all the different cases correctly.
//
// - A file can be a string, which case it is just a path to a single file to
//   bundle.
//
// - An object, which has three main bits of information: 1. src files for
//   bundling, dest where the bundle is to be written, and cwd that is the
//   current working directory for the input files.
//   The src can look like:
//   - A a string or an array of string file paths.
//     {"src": string | [string]}
//   - An object with a content property. Content is string of javascript code.
//     Often, content comes with a "path" property as well to specify a fake
//     path that is for resolving dependencies relative to in the javascript
//     content string.
//     {"content": string | Buffer, "path": string}
//
// - An array that can be a combination of string paths and/or content objects
//   as described above.
//
// TODO: add tests for createEntrypoint.
//
function createEntrypoint(inputFile) {
  // Check if input is a single path.
  if (types.isString(inputFile)) {
    return new File({
      src: [inputFile],
    });
  }

  // If we have an array, if could either an array of strings and/or
  // content objects.
  else if (types.isArray(inputFile)) {
    return new File({
      src: inputFile.map(mapSource),
    });
  }

  // Check if we have an object, which contains a src property
  else if (types.isPlainObject(inputFile)) {
    let src;

    if (inputFile.content || inputFile.path) {
      src = [utils.pick(inputFile, ["content", "path"])];
    }
    else if (inputFile.src) {
      src = [].concat(inputFile.src).map(mapSource);
    }
    else {
      invalidFormatError();
    }

    return new File(Object.assign({
        src: src,
      }, utils.pick(inputFile, ["cwd", "dest"])
    ));
  }

  // Ok, we do not have a valid input format. Let's just throw an error.
  else {
    invalidFormatError();
  }

  // Maps and validates src data.
  function mapSource(src) {
    if (types.isPlainObject(src)) {
      return utils.pick(src, ["content", "path"]);
    }

    if (types.isString(src)) {
      return src;
    }

    throw new Error("Invalid format for input file to bundle.");
  }

  function invalidFormatError() {
    throw new Error("Invalid format for input file to bundle.");
  }
}

// getTargetsToBundle returns an array of file paths and module names to bundle.
function getTargetsToBundle(inputFile) {
  if (inputFile instanceof File) {
    return inputFile.src;
  }

  if (types.isString(inputFile)) {
    return [inputFile];
  }

  if (types.isArray(inputFile)) {
    return inputFile;
  }

  throw new Error("Invalid file to bundle. It must be either a file path (string) or an entrypoint.");
}

Bitbundler.dest = bundleWriter;
Bitbundler.watch = watch;
Bitbundler.Context = Context;
Bitbundler.File = File;
module.exports = Bitbundler;
<commit_msg>Moved the eception handling for process pools to the `bundle` function since that's where we are doing other process pool sizing. We want to the deal with process pool sizing during the initial bundle creation rather than bundle updates since bundle updates don't enefit from running updates in separate processes like the initial bundling build does.<commit_after>"use strict";

var File = require("src-dest");
var types = require("dis-isa");
var utils = require("belty");
var EventEmitter = require("events");
var Stream = require("stream");
var es = require("event-stream");
var loaderFactory = require("./loader/factory");
var bundlerFactory = require("./bundler/factory");
var Bundle = require("./bundle");
var Context = require("./context");
var bundleWriter = require("./bundle/writer");
var watch = require("./watch");
var logging = require("./logging");
var buildstats = require("../loggers/buildstats");

var logger = logging.create("bundler/build");
var id = 0;

class Bitbundler extends EventEmitter {
  constructor(options) {
    super();

    this.options = Object.assign({
      baseUrl: process.cwd(),
    }, options);

    configureNotifications(this, this.options.notifications);
    configureLogger(this, this.options.log);

    this.context = null;
    this.loader = loaderFactory(this.options);
    this.bundler = bundlerFactory(this.options);
  }

  baseUrl() {
    return this.options.baseUrl;
  }

  bundle(inputFiles) {
    logger.log("build-init");

    const {entrypoint, bundle} = createMainBundle(inputFiles);
    this.context = new Context().setBundle(bundle);

    return this
      .update(entrypoint)
      .then((context) => {
        if (this.options.watch) {
          watch(this, this.options.watch);
        }

        if (this.options.multiprocess) {
          if (this.options.watch) {
            this.loader.pool.size(1);
          }
          else {
            this.loader.pool.stop();
          }
        }

        return context;
      })
      .catch(ex => {
        if (this.options.multiprocess) {
          this.loader.pool.stop();
        }

        throw ex;
      });
  }

  update(inputFile) {
    logger.log("build-start");

    return this
      .buildBundles(inputFile)
      .then((context) => {
        logger.log("build-writing");
        return bundleWriter()(context);
      })
      .then((context) => {
        context.visitBundles((bundle) => logger.log("bundle", bundle));
        logger.log("build-success", context);
        logger.log("build-end");
        this.context = context;
        return context;
      })
      .catch((ex) => {
        if (ex) {
          process.stderr.write((ex && ex.stack ? ex.stack : ex) + "\n");
        }

        logger.error("build-failure", ex);
        logger.log("build-end");
        throw ex;
      });
  }

  buildBundles(inputFile) {
    // There are two way in which buildBundles runs.
    // 1. When we first kick off the bundling process. In this case, inputFile
    //    will be an entrypoint.
    // 2. When there is an update from file watching. In this case, inputFile
    //    will be a file path string.
    // getTargetsToBundle helps us get the right thing to bundle.
    const targets = getTargetsToBundle(inputFile);
    const context = this.context;
    const loader = this.loader;
    const bundler = this.bundler;

    // Clear up cached items that need to be reprocessed
    targets
      .filter(target => types.isString(target) && loader.hasModule(target))
      .map(target => loader.getModule(target))
      .forEach(mod => loader.deleteModule(mod));

    return loader
      .fetch(targets)
      .then(() => {
        const cache = loader.getCache();
        const mainBundle = context.getBundles("main");
        const moduleIds = Object.keys(cache);

        const updatedContext = context
          .setBundle(mainBundle.setModules(moduleIds))
          .setCache(cache);

        return bundler.bundle(updatedContext);
      });
  }

  getLogger(name) {
    return logging.create(name);
  }
}

Bitbundler.bundle = function(inputFiles, settings) {
  return new Bitbundler(settings).bundle(inputFiles);
};

function configureNotifications(bitbundler, notifications) {
  if (!notifications) {
    return;
  }

  [].concat(notifications).forEach((notification) => {
    if (types.isFunction(notification)) {
      notification = notification(bitbundler) || {};
    }

    Object.keys(notification).forEach((notificationName) => {
      [].concat(notification[notificationName]).forEach((cb) => {
        bitbundler.on(notificationName, cb);
      });
    });
  });
}

function configureLogger(bitbundler, options) {
  if (options === true) {
    options = {
      level: "info"
    };
  }
  else if (types.isString(options)) {
    options = {
      level: options
    };
  }
  else if (options instanceof Stream) {
    options = {
      stream: options
    };
  }

  const loggerStream = logging.pipe(es.through(function(chunk) {
    chunk.name === "bundler/build" ?
      bitbundler.emit.apply(bitbundler, chunk.data) :
      bitbundler.emit(chunk.name, chunk);

    this.emit("data", chunk);
  }));

  if (options !== false) {
    loggerStream.pipe(options && options.stream ? options.stream : buildstats(options));
  }
}

// Creates the root bundle where all things start from. If there are multiple
// bundles that need to be generated, then bundle splitting is the tool for
// the job.
function createMainBundle(inputFiles) {
  const entrypoint = createEntrypoint(inputFiles);
  const entries = entrypoint.src.map(src => {
    return types.isString(src) ? src : (src.id || src.path || "@anonymous-" + id++);
  });

  return {
    entrypoint: entrypoint,
    bundle: new Bundle("main", { dest: entrypoint.dest, entries: entries }, true),
  };
}

// createEntrypoint converts input files that need to be bundled to an
// entrypoint object with file paths to be bundled. An entrypoint is an object
// that contains three main bits of information.
// 1. src - all the file paths and module names to be loaded. file paths can
//    be globs, which are automatically expanded.
// 2. dest - where the generated bundle is going to be written to.
// 3. cwd - current working directory file paths are relative to.
//
// The goal of this function is to generate an entrypoint from all the
// different ways in which users can define files to be bundled.
//
// Files can have a few different shapes to make the API simpler to use. But it
// certainly makes the logic here much more complex so that we can handle
// all the different cases correctly.
//
// - A file can be a string, which case it is just a path to a single file to
//   bundle.
//
// - An object, which has three main bits of information: 1. src files for
//   bundling, dest where the bundle is to be written, and cwd that is the
//   current working directory for the input files.
//   The src can look like:
//   - A a string or an array of string file paths.
//     {"src": string | [string]}
//   - An object with a content property. Content is string of javascript code.
//     Often, content comes with a "path" property as well to specify a fake
//     path that is for resolving dependencies relative to in the javascript
//     content string.
//     {"content": string | Buffer, "path": string}
//
// - An array that can be a combination of string paths and/or content objects
//   as described above.
//
// TODO: add tests for createEntrypoint.
//
function createEntrypoint(inputFile) {
  // Check if input is a single path.
  if (types.isString(inputFile)) {
    return new File({
      src: [inputFile],
    });
  }

  // If we have an array, if could either an array of strings and/or
  // content objects.
  else if (types.isArray(inputFile)) {
    return new File({
      src: inputFile.map(mapSource),
    });
  }

  // Check if we have an object, which contains a src property
  else if (types.isPlainObject(inputFile)) {
    let src;

    if (inputFile.content || inputFile.path) {
      src = [utils.pick(inputFile, ["content", "path"])];
    }
    else if (inputFile.src) {
      src = [].concat(inputFile.src).map(mapSource);
    }
    else {
      invalidFormatError();
    }

    return new File(Object.assign({
        src: src,
      }, utils.pick(inputFile, ["cwd", "dest"])
    ));
  }

  // Ok, we do not have a valid input format. Let's just throw an error.
  else {
    invalidFormatError();
  }

  // Maps and validates src data.
  function mapSource(src) {
    if (types.isPlainObject(src)) {
      return utils.pick(src, ["content", "path"]);
    }

    if (types.isString(src)) {
      return src;
    }

    throw new Error("Invalid format for input file to bundle.");
  }

  function invalidFormatError() {
    throw new Error("Invalid format for input file to bundle.");
  }
}

// getTargetsToBundle returns an array of file paths and module names to bundle.
function getTargetsToBundle(inputFile) {
  if (inputFile instanceof File) {
    return inputFile.src;
  }

  if (types.isString(inputFile)) {
    return [inputFile];
  }

  if (types.isArray(inputFile)) {
    return inputFile;
  }

  throw new Error("Invalid file to bundle. It must be either a file path (string) or an entrypoint.");
}

Bitbundler.dest = bundleWriter;
Bitbundler.watch = watch;
Bitbundler.Context = Context;
Bitbundler.File = File;
module.exports = Bitbundler;
<|endoftext|>


<commit_before>import React, { Component } from "react";
import {
  Dimensions,
  Modal,
  DeviceEventEmitter,
  TouchableWithoutFeedback,
  KeyboardAvoidingView,
  Platform,
  PanResponder,
  Animated
} from "react-native";
import PropTypes from "prop-types";
import {
  View,
  initializeRegistryWithDefinitions,
  registerAnimation,
  createAnimation
} from "react-native-animatable";
import * as ANIMATION_DEFINITIONS from "./animations";

import styles from "./index.style.js";

// Override default animations
initializeRegistryWithDefinitions(ANIMATION_DEFINITIONS);

// Utility for creating custom animations
const makeAnimation = (name, obj) => {
  registerAnimation(name, createAnimation(obj));
};

const isObject = obj => {
  return obj !== null && typeof obj === "object";
};

class ReactNativeModal extends Component {
  static propTypes = {
    animationIn: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationInTiming: PropTypes.number,
    animationOut: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationOutTiming: PropTypes.number,
    avoidKeyboard: PropTypes.bool,
    backdropColor: PropTypes.string,
    backdropOpacity: PropTypes.number,
    backdropTransitionInTiming: PropTypes.number,
    backdropTransitionOutTiming: PropTypes.number,
    children: PropTypes.node.isRequired,
    isVisible: PropTypes.bool.isRequired,
    hideModalContentWhileAnimating: PropTypes.bool,
    onModalShow: PropTypes.func,
    onModalHide: PropTypes.func,
    onBackButtonPress: PropTypes.func,
    onBackdropPress: PropTypes.func,
    onSwipe: PropTypes.func,
    swipeThreshold: PropTypes.number,
    swipeDirection: PropTypes.oneOf(["up", "down", "left", "right"]),
    useNativeDriver: PropTypes.bool,
    style: PropTypes.any,
    scrollTo: PropTypes.func,
    scrollOffset: PropTypes.number,
    scrollOffsetMax: PropTypes.number
  };

  static defaultProps = {
    animationIn: "slideInUp",
    animationInTiming: 300,
    animationOut: "slideOutDown",
    animationOutTiming: 300,
    avoidKeyboard: false,
    backdropColor: "black",
    backdropOpacity: 0.7,
    backdropTransitionInTiming: 300,
    backdropTransitionOutTiming: 300,
    onModalShow: () => null,
    onModalHide: () => null,
    isVisible: false,
    hideModalContentWhileAnimating: false,
    onBackdropPress: () => null,
    onBackButtonPress: () => null,
    swipeThreshold: 100,
    useNativeDriver: false,
    scrollTo: null,
    scrollOffset: 0,
    scrollOffsetMax: 0
  };

  // We use an internal state for keeping track of the modal visibility: this allows us to keep
  // the modal visibile during the exit animation, even if the user has already change the
  // isVisible prop to false.
  // We store in the state the device width and height so that we can update the modal on
  // device rotation.
  state = {
    showContent: true,
    isVisible: false,
    deviceWidth: Dimensions.get("window").width,
    deviceHeight: Dimensions.get("window").height,
    isSwipeable: this.props.swipeDirection ? true : false,
    pan: null
  };

  transitionLock = null;
  inSwipeClosingState = false;

  constructor(props) {
    super(props);
    this.buildAnimations(props);
    if (this.state.isSwipeable) {
      this.state = { ...this.state, pan: new Animated.ValueXY() };
      this.buildPanResponder();
    }
    if (this.props.isVisible) {
      this.state = {
        ...this.state,
        isVisible: true,
        showContent: true
      };
    }
  }

  componentWillReceiveProps(nextProps) {
    if (!this.state.isVisible && nextProps.isVisible) {
      this.setState({ isVisible: true, showContent: true });
    }
    if (
      this.props.animationIn !== nextProps.animationIn ||
      this.props.animationOut !== nextProps.animationOut
    ) {
      this.buildAnimations(nextProps);
    }
    if (
      this.props.backdropOpacity !== nextProps.backdropOpacity &&
      this.backdropRef
    ) {
      this.backdropRef.transitionTo(
        { opacity: nextProps.backdropOpacity },
        this.props.backdropTransitionInTiming
      );
    }
  }

  componentDidMount() {
    if (this.state.isVisible) {
      this.open();
    }
    DeviceEventEmitter.addListener(
      "didUpdateDimensions",
      this.handleDimensionsUpdate
    );
  }

  componentWillUnmount() {
    DeviceEventEmitter.removeListener(
      "didUpdateDimensions",
      this.handleDimensionsUpdate
    );
  }

  componentDidUpdate(prevProps, prevState) {
    // On modal open request, we slide the view up and fade in the backdrop
    if (this.props.isVisible && !prevProps.isVisible) {
      this.open();
    } else if (!this.props.isVisible && prevProps.isVisible) {
      // On modal close request, we slide the view down and fade out the backdrop
      this._close();
    }
  }

  buildPanResponder = () => {
    let animEvt = null;

    if (
      this.props.swipeDirection === "right" ||
      this.props.swipeDirection === "left"
    ) {
      animEvt = Animated.event([null, { dx: this.state.pan.x }]);
    } else {
      animEvt = Animated.event([null, { dy: this.state.pan.y }]);
    }

    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => {
        if (this.props.scrollTo) {
          if (this.props.scrollOffset > 0) {
            return false; // user needs to be able to scroll content back up
          }
        }
        return true;
      },
      onPanResponderMove: (evt, gestureState) => {
        // Dim the background while swiping the modal
        const accDistance = this.getAccDistancePerDirection(gestureState);
        const newOpacityFactor = 1 - accDistance / this.state.deviceWidth;
        if (this.isSwipeDirectionAllowed(gestureState)) {
          this.backdropRef &&
            this.backdropRef.transitionTo({
              opacity: this.props.backdropOpacity * newOpacityFactor
            });
          animEvt(evt, gestureState);
        } else {
          if (this.props.scrollTo) {
            let offsetY = -gestureState.dy;
            if (offsetY > this.props.scrollOffsetMax) {
              offsetY -= (offsetY - this.props.scrollOffsetMax) / 2;
            }
            this.props.scrollTo({ y: offsetY, animated: false });
          }
        }
      },
      onPanResponderRelease: (evt, gestureState) => {
        // Call the onSwipe prop if the threshold has been exceeded
        const accDistance = this.getAccDistancePerDirection(gestureState);
        if (accDistance > this.props.swipeThreshold) {
          if (this.props.onSwipe) {
            this.inSwipeClosingState = true;
            this.props.onSwipe();
            return;
          }
        }
        //Reset backdrop opacity and modal position
        if (this.backdropRef) {
          this.backdropRef.transitionTo(
            { opacity: this.props.backdropOpacity },
            this.props.backdropTransitionInTiming
          );
        }
        Animated.spring(this.state.pan, {
          toValue: { x: 0, y: 0 },
          bounciness: 0
        }).start();
        if (this.props.scrollOffset > this.props.scrollOffsetMax) {
          this.props.scrollTo({
            y: this.props.scrollOffsetMax,
            animated: true
          });
        }
      }
    });
  };

  getAccDistancePerDirection = gestureState => {
    switch (this.props.swipeDirection) {
      case "up":
        return -gestureState.dy;
      case "down":
        return gestureState.dy;
      case "right":
        return gestureState.dx;
      case "left":
        return -gestureState.dx;
      default:
        return 0;
    }
  };

  isSwipeDirectionAllowed = ({ dy, dx }) => {
    const draggedDown = dy > 0;
    const draggedUp = dy < 0;
    const draggedLeft = dx < 0;
    const draggedRight = dx > 0;

    if (this.props.swipeDirection === "up" && draggedUp) {
      return true;
    } else if (this.props.swipeDirection === "down" && draggedDown) {
      return true;
    } else if (this.props.swipeDirection === "right" && draggedRight) {
      return true;
    } else if (this.props.swipeDirection === "left" && draggedLeft) {
      return true;
    }
    return false;
  };

  // User can define custom react-native-animatable animations, see PR #72
  buildAnimations = props => {
    let animationIn = props.animationIn;
    let animationOut = props.animationOut;

    if (isObject(animationIn)) {
      const animationName = JSON.stringify(animationIn);
      makeAnimation(animationName, animationIn);
      animationIn = animationName;
    }

    if (isObject(animationOut)) {
      const animationName = JSON.stringify(animationOut);
      makeAnimation(animationName, animationOut);
      animationOut = animationName;
    }

    this.animationIn = animationIn;
    this.animationOut = animationOut;
  };

  handleDimensionsUpdate = dimensionsUpdate => {
    // Here we update the device dimensions in the state if the layout changed (triggering a render)
    const deviceWidth = Dimensions.get("window").width;
    const deviceHeight = Dimensions.get("window").height;
    if (
      deviceWidth !== this.state.deviceWidth ||
      deviceHeight !== this.state.deviceHeight
    ) {
      this.setState({ deviceWidth, deviceHeight });
    }
  };

  open = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    if (this.backdropRef) {
      this.backdropRef.transitionTo(
        { opacity: this.props.backdropOpacity },
        this.props.backdropTransitionInTiming
      );
    }

    // This is for reset the pan position, if not modal get stuck
    // at the last release position when you try to open it.
    // Could certainly be improve - no idea for the moment.
    if (this.state.isSwipeable) {
      this.state.pan.setValue({ x: 0, y: 0 });
    }

    if (this.contentRef) {
      this.contentRef[this.animationIn](this.props.animationInTiming).then(
        () => {
          this.transitionLock = false;
          if (!this.props.isVisible) {
            this._close();
          } else {
            this.props.onModalShow();
          }
        }
      );
    }
  };

  _close = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    if (this.backdropRef) {
      this.backdropRef.transitionTo(
        { opacity: 0 },
        this.props.backdropTransitionOutTiming
      );
    }

    let animationOut = this.animationOut;

    if (this.inSwipeClosingState) {
      this.inSwipeClosingState = false;
      if (this.props.swipeDirection === "up") {
        animationOut = "slideOutUp";
      } else if (this.props.swipeDirection === "down") {
        animationOut = "slideOutDown";
      } else if (this.props.swipeDirection === "right") {
        animationOut = "slideOutRight";
      } else if (this.props.swipeDirection === "left") {
        animationOut = "slideOutLeft";
      }
    }

    if (this.contentRef) {
      this.contentRef[animationOut](this.props.animationOutTiming).then(() => {
        this.transitionLock = false;
        if (this.props.isVisible) {
          this.open();
        } else {
          this.setState(
            {
              showContent: false
            },
            () => {
              this.setState({
                isVisible: false
              });
            }
          );
          this.props.onModalHide();
        }
      });
    }
  };

  render() {
    const {
      animationIn,
      animationInTiming,
      animationOut,
      animationOutTiming,
      avoidKeyboard,
      backdropColor,
      backdropOpacity,
      backdropTransitionInTiming,
      backdropTransitionOutTiming,
      children,
      isVisible,
      onModalShow,
      onBackdropPress,
      onBackButtonPress,
      useNativeDriver,
      style,
      ...otherProps
    } = this.props;
    const { deviceWidth, deviceHeight } = this.state;

    const computedStyle = [
      { margin: deviceWidth * 0.05, transform: [{ translateY: 0 }] },
      styles.content,
      style
    ];

    let panHandlers = {};
    let panPosition = {};
    if (this.state.isSwipeable) {
      panHandlers = { ...this.panResponder.panHandlers };
      panPosition = this.state.pan.getLayout();
    }

    const _children =
      this.props.hideModalContentWhileAnimating &&
      this.props.useNativeDriver &&
      !this.state.showContent ? (
        <View />
      ) : (
        children
      );
    const containerView = (
      <View
        {...panHandlers}
        ref={ref => (this.contentRef = ref)}
        style={[panPosition, computedStyle]}
        pointerEvents="box-none"
        useNativeDriver={useNativeDriver}
        {...otherProps}
      >
        {_children}
      </View>
    );

    return (
      <Modal
        transparent={true}
        animationType={"none"}
        visible={this.state.isVisible}
        onRequestClose={onBackButtonPress}
        {...otherProps}
      >
        <TouchableWithoutFeedback onPress={onBackdropPress}>
          <View
            ref={ref => (this.backdropRef = ref)}
            useNativeDriver={useNativeDriver}
            style={[
              styles.backdrop,
              {
                backgroundColor: this.state.showContent
                  ? backdropColor
                  : "transparent",
                width: deviceWidth,
                height: deviceHeight
              }
            ]}
          />
        </TouchableWithoutFeedback>

        {avoidKeyboard && (
          <KeyboardAvoidingView
            behavior={Platform.OS === "ios" ? "padding" : null}
            pointerEvents="box-none"
            style={computedStyle.concat([{ margin: 0 }])}
          >
            {containerView}
          </KeyboardAvoidingView>
        )}

        {!avoidKeyboard && containerView}
      </Modal>
    );
  }
}

export default ReactNativeModal;
export { ReactNativeModal };
<commit_msg>Added rotation support on iOS.<commit_after>import React, { Component } from "react";
import {
  Dimensions,
  Modal,
  DeviceEventEmitter,
  TouchableWithoutFeedback,
  KeyboardAvoidingView,
  Platform,
  PanResponder,
  Animated
} from "react-native";
import PropTypes from "prop-types";
import {
  View,
  initializeRegistryWithDefinitions,
  registerAnimation,
  createAnimation
} from "react-native-animatable";
import * as ANIMATION_DEFINITIONS from "./animations";

import styles from "./index.style.js";

// Override default animations
initializeRegistryWithDefinitions(ANIMATION_DEFINITIONS);

// Utility for creating custom animations
const makeAnimation = (name, obj) => {
  registerAnimation(name, createAnimation(obj));
};

const isObject = obj => {
  return obj !== null && typeof obj === "object";
};

class ReactNativeModal extends Component {
  static propTypes = {
    animationIn: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationInTiming: PropTypes.number,
    animationOut: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    animationOutTiming: PropTypes.number,
    avoidKeyboard: PropTypes.bool,
    backdropColor: PropTypes.string,
    backdropOpacity: PropTypes.number,
    backdropTransitionInTiming: PropTypes.number,
    backdropTransitionOutTiming: PropTypes.number,
    children: PropTypes.node.isRequired,
    isVisible: PropTypes.bool.isRequired,
    hideModalContentWhileAnimating: PropTypes.bool,
    onModalShow: PropTypes.func,
    onModalHide: PropTypes.func,
    onBackButtonPress: PropTypes.func,
    onBackdropPress: PropTypes.func,
    onSwipe: PropTypes.func,
    swipeThreshold: PropTypes.number,
    swipeDirection: PropTypes.oneOf(["up", "down", "left", "right"]),
    useNativeDriver: PropTypes.bool,
    style: PropTypes.any,
    scrollTo: PropTypes.func,
    scrollOffset: PropTypes.number,
    scrollOffsetMax: PropTypes.number,
    supportedOrientations: PropTypes.oneOf(['portrait', 'portrait-upside-down', 'landscape', 'landscape-left', 'landscape-right'])
  };

  static defaultProps = {
    animationIn: "slideInUp",
    animationInTiming: 300,
    animationOut: "slideOutDown",
    animationOutTiming: 300,
    avoidKeyboard: false,
    backdropColor: "black",
    backdropOpacity: 0.7,
    backdropTransitionInTiming: 300,
    backdropTransitionOutTiming: 300,
    onModalShow: () => null,
    onModalHide: () => null,
    isVisible: false,
    hideModalContentWhileAnimating: false,
    onBackdropPress: () => null,
    onBackButtonPress: () => null,
    swipeThreshold: 100,
    useNativeDriver: false,
    scrollTo: null,
    scrollOffset: 0,
    scrollOffsetMax: 0,
    supportedOrientations: ['portrait', 'landscape']
  };

  // We use an internal state for keeping track of the modal visibility: this allows us to keep
  // the modal visibile during the exit animation, even if the user has already change the
  // isVisible prop to false.
  // We store in the state the device width and height so that we can update the modal on
  // device rotation.
  state = {
    showContent: true,
    isVisible: false,
    deviceWidth: Dimensions.get("window").width,
    deviceHeight: Dimensions.get("window").height,
    isSwipeable: this.props.swipeDirection ? true : false,
    pan: null
  };

  transitionLock = null;
  inSwipeClosingState = false;

  constructor(props) {
    super(props);
    this.buildAnimations(props);
    if (this.state.isSwipeable) {
      this.state = { ...this.state, pan: new Animated.ValueXY() };
      this.buildPanResponder();
    }
    if (this.props.isVisible) {
      this.state = {
        ...this.state,
        isVisible: true,
        showContent: true
      };
    }
  }

  componentWillReceiveProps(nextProps) {
    if (!this.state.isVisible && nextProps.isVisible) {
      this.setState({ isVisible: true, showContent: true });
    }
    if (
      this.props.animationIn !== nextProps.animationIn ||
      this.props.animationOut !== nextProps.animationOut
    ) {
      this.buildAnimations(nextProps);
    }
    if (
      this.props.backdropOpacity !== nextProps.backdropOpacity &&
      this.backdropRef
    ) {
      this.backdropRef.transitionTo(
        { opacity: nextProps.backdropOpacity },
        this.props.backdropTransitionInTiming
      );
    }
  }

  componentDidMount() {
    if (this.state.isVisible) {
      this.open();
    }
    DeviceEventEmitter.addListener(
      "didUpdateDimensions",
      this.handleDimensionsUpdate
    );
  }

  componentWillUnmount() {
    DeviceEventEmitter.removeListener(
      "didUpdateDimensions",
      this.handleDimensionsUpdate
    );
  }

  componentDidUpdate(prevProps, prevState) {
    // On modal open request, we slide the view up and fade in the backdrop
    if (this.props.isVisible && !prevProps.isVisible) {
      this.open();
    } else if (!this.props.isVisible && prevProps.isVisible) {
      // On modal close request, we slide the view down and fade out the backdrop
      this._close();
    }
  }

  buildPanResponder = () => {
    let animEvt = null;

    if (
      this.props.swipeDirection === "right" ||
      this.props.swipeDirection === "left"
    ) {
      animEvt = Animated.event([null, { dx: this.state.pan.x }]);
    } else {
      animEvt = Animated.event([null, { dy: this.state.pan.y }]);
    }

    this.panResponder = PanResponder.create({
      onStartShouldSetPanResponder: () => {
        if (this.props.scrollTo) {
          if (this.props.scrollOffset > 0) {
            return false; // user needs to be able to scroll content back up
          }
        }
        return true;
      },
      onPanResponderMove: (evt, gestureState) => {
        // Dim the background while swiping the modal
        const accDistance = this.getAccDistancePerDirection(gestureState);
        const newOpacityFactor = 1 - accDistance / this.state.deviceWidth;
        if (this.isSwipeDirectionAllowed(gestureState)) {
          this.backdropRef &&
            this.backdropRef.transitionTo({
              opacity: this.props.backdropOpacity * newOpacityFactor
            });
          animEvt(evt, gestureState);
        } else {
          if (this.props.scrollTo) {
            let offsetY = -gestureState.dy;
            if (offsetY > this.props.scrollOffsetMax) {
              offsetY -= (offsetY - this.props.scrollOffsetMax) / 2;
            }
            this.props.scrollTo({ y: offsetY, animated: false });
          }
        }
      },
      onPanResponderRelease: (evt, gestureState) => {
        // Call the onSwipe prop if the threshold has been exceeded
        const accDistance = this.getAccDistancePerDirection(gestureState);
        if (accDistance > this.props.swipeThreshold) {
          if (this.props.onSwipe) {
            this.inSwipeClosingState = true;
            this.props.onSwipe();
            return;
          }
        }
        //Reset backdrop opacity and modal position
        if (this.backdropRef) {
          this.backdropRef.transitionTo(
            { opacity: this.props.backdropOpacity },
            this.props.backdropTransitionInTiming
          );
        }
        Animated.spring(this.state.pan, {
          toValue: { x: 0, y: 0 },
          bounciness: 0
        }).start();
        if (this.props.scrollOffset > this.props.scrollOffsetMax) {
          this.props.scrollTo({
            y: this.props.scrollOffsetMax,
            animated: true
          });
        }
      }
    });
  };

  getAccDistancePerDirection = gestureState => {
    switch (this.props.swipeDirection) {
      case "up":
        return -gestureState.dy;
      case "down":
        return gestureState.dy;
      case "right":
        return gestureState.dx;
      case "left":
        return -gestureState.dx;
      default:
        return 0;
    }
  };

  isSwipeDirectionAllowed = ({ dy, dx }) => {
    const draggedDown = dy > 0;
    const draggedUp = dy < 0;
    const draggedLeft = dx < 0;
    const draggedRight = dx > 0;

    if (this.props.swipeDirection === "up" && draggedUp) {
      return true;
    } else if (this.props.swipeDirection === "down" && draggedDown) {
      return true;
    } else if (this.props.swipeDirection === "right" && draggedRight) {
      return true;
    } else if (this.props.swipeDirection === "left" && draggedLeft) {
      return true;
    }
    return false;
  };

  // User can define custom react-native-animatable animations, see PR #72
  buildAnimations = props => {
    let animationIn = props.animationIn;
    let animationOut = props.animationOut;

    if (isObject(animationIn)) {
      const animationName = JSON.stringify(animationIn);
      makeAnimation(animationName, animationIn);
      animationIn = animationName;
    }

    if (isObject(animationOut)) {
      const animationName = JSON.stringify(animationOut);
      makeAnimation(animationName, animationOut);
      animationOut = animationName;
    }

    this.animationIn = animationIn;
    this.animationOut = animationOut;
  };

  handleDimensionsUpdate = dimensionsUpdate => {
    // Here we update the device dimensions in the state if the layout changed (triggering a render)
    const deviceWidth = Dimensions.get("window").width;
    const deviceHeight = Dimensions.get("window").height;
    if (
      deviceWidth !== this.state.deviceWidth ||
      deviceHeight !== this.state.deviceHeight
    ) {
      this.setState({ deviceWidth, deviceHeight });
    }
  };

  open = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    if (this.backdropRef) {
      this.backdropRef.transitionTo(
        { opacity: this.props.backdropOpacity },
        this.props.backdropTransitionInTiming
      );
    }

    // This is for reset the pan position, if not modal get stuck
    // at the last release position when you try to open it.
    // Could certainly be improve - no idea for the moment.
    if (this.state.isSwipeable) {
      this.state.pan.setValue({ x: 0, y: 0 });
    }

    if (this.contentRef) {
      this.contentRef[this.animationIn](this.props.animationInTiming).then(
        () => {
          this.transitionLock = false;
          if (!this.props.isVisible) {
            this._close();
          } else {
            this.props.onModalShow();
          }
        }
      );
    }
  };

  _close = () => {
    if (this.transitionLock) return;
    this.transitionLock = true;
    if (this.backdropRef) {
      this.backdropRef.transitionTo(
        { opacity: 0 },
        this.props.backdropTransitionOutTiming
      );
    }

    let animationOut = this.animationOut;

    if (this.inSwipeClosingState) {
      this.inSwipeClosingState = false;
      if (this.props.swipeDirection === "up") {
        animationOut = "slideOutUp";
      } else if (this.props.swipeDirection === "down") {
        animationOut = "slideOutDown";
      } else if (this.props.swipeDirection === "right") {
        animationOut = "slideOutRight";
      } else if (this.props.swipeDirection === "left") {
        animationOut = "slideOutLeft";
      }
    }

    if (this.contentRef) {
      this.contentRef[animationOut](this.props.animationOutTiming).then(() => {
        this.transitionLock = false;
        if (this.props.isVisible) {
          this.open();
        } else {
          this.setState(
            {
              showContent: false
            },
            () => {
              this.setState({
                isVisible: false
              });
            }
          );
          this.props.onModalHide();
        }
      });
    }
  };

  render() {
    const {
      animationIn,
      animationInTiming,
      animationOut,
      animationOutTiming,
      avoidKeyboard,
      backdropColor,
      backdropOpacity,
      backdropTransitionInTiming,
      backdropTransitionOutTiming,
      children,
      isVisible,
      onModalShow,
      onBackdropPress,
      onBackButtonPress,
      useNativeDriver,
      style,
      ...otherProps
    } = this.props;
    const { deviceWidth, deviceHeight } = this.state;

    const computedStyle = [
      { margin: deviceWidth * 0.05, transform: [{ translateY: 0 }] },
      styles.content,
      style
    ];

    let panHandlers = {};
    let panPosition = {};
    if (this.state.isSwipeable) {
      panHandlers = { ...this.panResponder.panHandlers };
      panPosition = this.state.pan.getLayout();
    }

    const _children =
      this.props.hideModalContentWhileAnimating &&
      this.props.useNativeDriver &&
      !this.state.showContent ? (
        <View />
      ) : (
        children
      );
    const containerView = (
      <View
        {...panHandlers}
        ref={ref => (this.contentRef = ref)}
        style={[panPosition, computedStyle]}
        pointerEvents="box-none"
        useNativeDriver={useNativeDriver}
        {...otherProps}
      >
        {_children}
      </View>
    );

    return (
      <Modal
        transparent={true}
        animationType={"none"}
        visible={this.state.isVisible}
        onRequestClose={onBackButtonPress}
        {...otherProps}
      >
        <TouchableWithoutFeedback onPress={onBackdropPress}>
          <View
            ref={ref => (this.backdropRef = ref)}
            useNativeDriver={useNativeDriver}
            style={[
              styles.backdrop,
              {
                backgroundColor: this.state.showContent
                  ? backdropColor
                  : "transparent",
                width: deviceWidth,
                height: deviceHeight
              }
            ]}
          />
        </TouchableWithoutFeedback>

        {avoidKeyboard && (
          <KeyboardAvoidingView
            behavior={Platform.OS === "ios" ? "padding" : null}
            pointerEvents="box-none"
            style={computedStyle.concat([{ margin: 0 }])}
          >
            {containerView}
          </KeyboardAvoidingView>
        )}

        {!avoidKeyboard && containerView}
      </Modal>
    );
  }
}

export default ReactNativeModal;
export { ReactNativeModal };
<|endoftext|>