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

'use strict';

// MODULES //

var Readable = require( 'readable-stream' ).Readable;
var isPositiveNumber = require( '@stdlib/assert/is-positive-number' ).isPrimitive;
var isError = require( '@stdlib/assert/is-error' );
var copy = require( '@stdlib/utils/copy' );
var inherit = require( '@stdlib/utils/inherit' );
var setNonEnumerable = require( '@stdlib/utils/define-nonenumerable-property' );
var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' );
var setReadOnlyAccessor = require( '@stdlib/utils/define-read-only-accessor' );
var setReadWriteAccessor = require( '@stdlib/utils/define-read-write-accessor' );
var rchisquare = require( '@stdlib/random/base/chisquare' ).factory;
var string2buffer = require( '@stdlib/buffer/from-string' );
var DEFAULTS = require( './defaults.json' );
var validate = require( './validate.js' );
var debug = require( './debug.js' );

// FUNCTIONS //

/**
* Returns the PRNG seed.
*
* @private
* @returns {(PRNGSeedMT19937|null)} seed
*/
function getSeed() {
	return this._prng.seed; // eslint-disable-line no-invalid-this
}

/**
* Returns the PRNG seed length.
*
* @private
* @returns {(PositiveInteger|null)} seed length
*/
function getSeedLength() {
	return this._prng.seedLength; // eslint-disable-line no-invalid-this
}

/**
* Returns the PRNG state length.
*
* @private
* @returns {(PositiveInteger|null)} state length
*/
function getStateLength() {
	return this._prng.stateLength; // eslint-disable-line no-invalid-this
}

/**
* Returns the PRNG state size (in bytes).
*
* @private
* @returns {(PositiveInteger|null)} state size (in bytes)
*/
function getStateSize() {
	return this._prng.byteLength; // eslint-disable-line no-invalid-this
}

/**
* Returns the current PRNG state.
*
* @private
* @returns {(PRNGStateMT19937|null)} current state
*/
function getState() {
	return this._prng.state; // eslint-disable-line no-invalid-this
}

/**
* Sets the PRNG state.
*
* @private
* @param {PRNGStateMT19937} s - generator state
* @throws {Error} must provide a valid state
*/
function setState( s ) {
	this._prng.state = s; // eslint-disable-line no-invalid-this
}

/**
* Implements the `_read` method.
*
* @private
* @param {number} size - number (of bytes) to read
* @returns {void}
*/
function read() {
	/* eslint-disable no-invalid-this */
	var FLG;
	var r;

	if ( this._destroyed ) {
		return;
	}
	FLG = true;
	while ( FLG ) {
		this._i += 1;
		if ( this._i > this._iter ) {
			debug( 'Finished generating pseudorandom numbers.' );
			return this.push( null );
		}
		r = this._prng();

		debug( 'Generated a new pseudorandom number. Value: %d. Iter: %d.', r, this._i );

		if ( this._objectMode === false ) {
			r = r.toString();
			if ( this._i === 1 ) {
				r = string2buffer( r );
			} else {
				r = string2buffer( this._sep+r );
			}
		}
		FLG = this.push( r );
		if ( this._i%this._siter === 0 ) {
			this.emit( 'state', this.state );
		}
	}

	/* eslint-enable no-invalid-this */
}

/**
* Gracefully destroys a stream, providing backward compatibility.
*
* @private
* @param {(string|Object|Error)} [error] - error
* @returns {RandomStream} Stream instance
*/
function destroy( error ) {
	/* eslint-disable no-invalid-this */
	var self;
	if ( this._destroyed ) {
		debug( 'Attempted to destroy an already destroyed stream.' );
		return this;
	}
	self = this;
	this._destroyed = true;

	// TODO: replace with polyfill
	process.nextTick( close );

	return this;

	/**
	* Closes a stream.
	*
	* @private
	*/
	function close() {
		if ( error ) {
			debug( 'Stream was destroyed due to an error. Error: %s.', ( isError( error ) ) ? error.message : JSON.stringify( error ) );
			self.emit( 'error', error );
		}
		debug( 'Closing the stream...' );
		self.emit( 'close' );
	}

	/* eslint-enable no-invalid-this */
}

// MAIN //

/**
* Stream constructor for generating a stream of pseudorandom numbers drawn from a chi-square distribution.
*
* @constructor
* @param {PositiveNumber} k - degrees of freedom
* @param {Options} [options] - stream options
* @param {boolean} [options.objectMode=false] - specifies whether the stream should operate in object mode
* @param {(string|null)} [options.encoding=null] - specifies how `Buffer` objects should be decoded to strings
* @param {NonNegativeNumber} [options.highWaterMark] - specifies the maximum number of bytes to store in an internal buffer before ceasing to generate additional pseudorandom numbers
* @param {string} [options.sep='\n'] - separator used to join streamed data
* @param {NonNegativeInteger} [options.iter] - number of iterations
* @param {PRNG} [options.prng] - pseudorandom number generator which generates uniformly distributed pseudorandom numbers
* @param {PRNGSeedMT19937} [options.seed] - pseudorandom number generator seed
* @param {PRNGStateMT19937} [options.state] - pseudorandom number generator state
* @param {boolean} [options.copy=true] - boolean indicating whether to copy a provided pseudorandom number generator state
* @param {PositiveInteger} [options.siter] - number of iterations after which to emit the PRNG state
* @throws {TypeError} `k` must be a positive number
* @throws {TypeError} options argument must be an object
* @throws {TypeError} must provide valid options
* @throws {Error} must provide a valid state
* @returns {RandomStream} Stream instance
*
* @example
* var inspectStream = require( '@stdlib/streams/node/inspect-sink' );
*
* function log( chunk ) {
*    console.log( chunk.toString() );
* }
*
* var opts = {
*     'iter': 10
* };
*
* var stream = new RandomStream( 2.0, opts );
*
* stream.pipe( inspectStream( log )  );
*/
function RandomStream( k, options ) {
	var opts;
	var err;
	if ( !( this instanceof RandomStream ) ) {
		if ( arguments.length > 1 ) {
			return new RandomStream( k, options );
		}
		return new RandomStream( k );
	}
	if ( !isPositiveNumber( k ) ) {
		throw new TypeError( 'invalid argument. Second argument must be a positive number. Value: `'+k+'`.' );
	}
	opts = copy( DEFAULTS );
	if ( arguments.length > 1 ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	// Make the stream a readable stream:
	debug( 'Creating a readable stream configured with the following options: %s.', JSON.stringify( opts ) );
	Readable.call( this, opts );

	// Destruction state:
	setNonEnumerable( this, '_destroyed', false );

	// Cache whether the stream is operating in object mode:
	setNonEnumerableReadOnly( this, '_objectMode', opts.objectMode );

	// Cache the separator:
	setNonEnumerableReadOnly( this, '_sep', opts.sep );

	// Cache the total number of iterations:
	setNonEnumerableReadOnly( this, '_iter', opts.iter );

	// Cache the number of iterations after which to emit the underlying PRNG state:
	setNonEnumerableReadOnly( this, '_siter', opts.siter );

	// Initialize an iteration counter:
	setNonEnumerable( this, '_i', 0 );

	// Create the underlying PRNG:
	setNonEnumerableReadOnly( this, '_prng', rchisquare( k, opts ) );
	setNonEnumerableReadOnly( this, 'PRNG', this._prng.PRNG );

	return this;
}

/*
* Inherit from the `Readable` prototype.
*/
inherit( RandomStream, Readable );

/**
* PRNG seed.
*
* @name seed
* @memberof RandomStream.prototype
* @type {(PRNGSeedMT19937|null)}
*/
setReadOnlyAccessor( RandomStream.prototype, 'seed', getSeed );

/**
* PRNG seed length.
*
* @name seedLength
* @memberof RandomStream.prototype
* @type {(PositiveInteger|null)}
*/
setReadOnlyAccessor( RandomStream.prototype, 'seedLength', getSeedLength );

/**
* PRNG state getter/setter.
*
* @name state
* @memberof RandomStream.prototype
* @type {(PRNGStateMT19937|null)}
* @throws {Error} must provide a valid state
*/
setReadWriteAccessor( RandomStream.prototype, 'state', getState, setState );

/**
* PRNG state length.
*
* @name stateLength
* @memberof RandomStream.prototype
* @type {(PositiveInteger|null)}
*/
setReadOnlyAccessor( RandomStream.prototype, 'stateLength', getStateLength );

/**
* PRNG state size (in bytes).
*
* @name byteLength
* @memberof RandomStream.prototype
* @type {(PositiveInteger|null)}
*/
setReadOnlyAccessor( RandomStream.prototype, 'byteLength', getStateSize );

/**
* Implements the `_read` method.
*
* @private
* @name _read
* @memberof RandomStream.prototype
* @type {Function}
* @param {number} size - number (of bytes) to read
* @returns {void}
*/
setNonEnumerableReadOnly( RandomStream.prototype, '_read', read );

/**
* Gracefully destroys a stream, providing backward compatibility.
*
* @name destroy
* @memberof RandomStream.prototype
* @type {Function}
* @param {(string|Object|Error)} [error] - error
* @returns {RandomStream} Stream instance
*/
setNonEnumerableReadOnly( RandomStream.prototype, 'destroy', destroy );

// EXPORTS //

module.exports = RandomStream;
<commit_msg>Fix error message<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var Readable = require( 'readable-stream' ).Readable;
var isPositiveNumber = require( '@stdlib/assert/is-positive-number' ).isPrimitive;
var isError = require( '@stdlib/assert/is-error' );
var copy = require( '@stdlib/utils/copy' );
var inherit = require( '@stdlib/utils/inherit' );
var setNonEnumerable = require( '@stdlib/utils/define-nonenumerable-property' );
var setNonEnumerableReadOnly = require( '@stdlib/utils/define-nonenumerable-read-only-property' );
var setReadOnlyAccessor = require( '@stdlib/utils/define-read-only-accessor' );
var setReadWriteAccessor = require( '@stdlib/utils/define-read-write-accessor' );
var rchisquare = require( '@stdlib/random/base/chisquare' ).factory;
var string2buffer = require( '@stdlib/buffer/from-string' );
var DEFAULTS = require( './defaults.json' );
var validate = require( './validate.js' );
var debug = require( './debug.js' );

// FUNCTIONS //

/**
* Returns the PRNG seed.
*
* @private
* @returns {(PRNGSeedMT19937|null)} seed
*/
function getSeed() {
	return this._prng.seed; // eslint-disable-line no-invalid-this
}

/**
* Returns the PRNG seed length.
*
* @private
* @returns {(PositiveInteger|null)} seed length
*/
function getSeedLength() {
	return this._prng.seedLength; // eslint-disable-line no-invalid-this
}

/**
* Returns the PRNG state length.
*
* @private
* @returns {(PositiveInteger|null)} state length
*/
function getStateLength() {
	return this._prng.stateLength; // eslint-disable-line no-invalid-this
}

/**
* Returns the PRNG state size (in bytes).
*
* @private
* @returns {(PositiveInteger|null)} state size (in bytes)
*/
function getStateSize() {
	return this._prng.byteLength; // eslint-disable-line no-invalid-this
}

/**
* Returns the current PRNG state.
*
* @private
* @returns {(PRNGStateMT19937|null)} current state
*/
function getState() {
	return this._prng.state; // eslint-disable-line no-invalid-this
}

/**
* Sets the PRNG state.
*
* @private
* @param {PRNGStateMT19937} s - generator state
* @throws {Error} must provide a valid state
*/
function setState( s ) {
	this._prng.state = s; // eslint-disable-line no-invalid-this
}

/**
* Implements the `_read` method.
*
* @private
* @param {number} size - number (of bytes) to read
* @returns {void}
*/
function read() {
	/* eslint-disable no-invalid-this */
	var FLG;
	var r;

	if ( this._destroyed ) {
		return;
	}
	FLG = true;
	while ( FLG ) {
		this._i += 1;
		if ( this._i > this._iter ) {
			debug( 'Finished generating pseudorandom numbers.' );
			return this.push( null );
		}
		r = this._prng();

		debug( 'Generated a new pseudorandom number. Value: %d. Iter: %d.', r, this._i );

		if ( this._objectMode === false ) {
			r = r.toString();
			if ( this._i === 1 ) {
				r = string2buffer( r );
			} else {
				r = string2buffer( this._sep+r );
			}
		}
		FLG = this.push( r );
		if ( this._i%this._siter === 0 ) {
			this.emit( 'state', this.state );
		}
	}

	/* eslint-enable no-invalid-this */
}

/**
* Gracefully destroys a stream, providing backward compatibility.
*
* @private
* @param {(string|Object|Error)} [error] - error
* @returns {RandomStream} Stream instance
*/
function destroy( error ) {
	/* eslint-disable no-invalid-this */
	var self;
	if ( this._destroyed ) {
		debug( 'Attempted to destroy an already destroyed stream.' );
		return this;
	}
	self = this;
	this._destroyed = true;

	// TODO: replace with polyfill
	process.nextTick( close );

	return this;

	/**
	* Closes a stream.
	*
	* @private
	*/
	function close() {
		if ( error ) {
			debug( 'Stream was destroyed due to an error. Error: %s.', ( isError( error ) ) ? error.message : JSON.stringify( error ) );
			self.emit( 'error', error );
		}
		debug( 'Closing the stream...' );
		self.emit( 'close' );
	}

	/* eslint-enable no-invalid-this */
}

// MAIN //

/**
* Stream constructor for generating a stream of pseudorandom numbers drawn from a chi-square distribution.
*
* @constructor
* @param {PositiveNumber} k - degrees of freedom
* @param {Options} [options] - stream options
* @param {boolean} [options.objectMode=false] - specifies whether the stream should operate in object mode
* @param {(string|null)} [options.encoding=null] - specifies how `Buffer` objects should be decoded to strings
* @param {NonNegativeNumber} [options.highWaterMark] - specifies the maximum number of bytes to store in an internal buffer before ceasing to generate additional pseudorandom numbers
* @param {string} [options.sep='\n'] - separator used to join streamed data
* @param {NonNegativeInteger} [options.iter] - number of iterations
* @param {PRNG} [options.prng] - pseudorandom number generator which generates uniformly distributed pseudorandom numbers
* @param {PRNGSeedMT19937} [options.seed] - pseudorandom number generator seed
* @param {PRNGStateMT19937} [options.state] - pseudorandom number generator state
* @param {boolean} [options.copy=true] - boolean indicating whether to copy a provided pseudorandom number generator state
* @param {PositiveInteger} [options.siter] - number of iterations after which to emit the PRNG state
* @throws {TypeError} `k` must be a positive number
* @throws {TypeError} options argument must be an object
* @throws {TypeError} must provide valid options
* @throws {Error} must provide a valid state
* @returns {RandomStream} Stream instance
*
* @example
* var inspectStream = require( '@stdlib/streams/node/inspect-sink' );
*
* function log( chunk ) {
*    console.log( chunk.toString() );
* }
*
* var opts = {
*     'iter': 10
* };
*
* var stream = new RandomStream( 2.0, opts );
*
* stream.pipe( inspectStream( log )  );
*/
function RandomStream( k, options ) {
	var opts;
	var err;
	if ( !( this instanceof RandomStream ) ) {
		if ( arguments.length > 1 ) {
			return new RandomStream( k, options );
		}
		return new RandomStream( k );
	}
	if ( !isPositiveNumber( k ) ) {
		throw new TypeError( 'invalid argument. First argument must be a positive number. Value: `'+k+'`.' );
	}
	opts = copy( DEFAULTS );
	if ( arguments.length > 1 ) {
		err = validate( opts, options );
		if ( err ) {
			throw err;
		}
	}
	// Make the stream a readable stream:
	debug( 'Creating a readable stream configured with the following options: %s.', JSON.stringify( opts ) );
	Readable.call( this, opts );

	// Destruction state:
	setNonEnumerable( this, '_destroyed', false );

	// Cache whether the stream is operating in object mode:
	setNonEnumerableReadOnly( this, '_objectMode', opts.objectMode );

	// Cache the separator:
	setNonEnumerableReadOnly( this, '_sep', opts.sep );

	// Cache the total number of iterations:
	setNonEnumerableReadOnly( this, '_iter', opts.iter );

	// Cache the number of iterations after which to emit the underlying PRNG state:
	setNonEnumerableReadOnly( this, '_siter', opts.siter );

	// Initialize an iteration counter:
	setNonEnumerable( this, '_i', 0 );

	// Create the underlying PRNG:
	setNonEnumerableReadOnly( this, '_prng', rchisquare( k, opts ) );
	setNonEnumerableReadOnly( this, 'PRNG', this._prng.PRNG );

	return this;
}

/*
* Inherit from the `Readable` prototype.
*/
inherit( RandomStream, Readable );

/**
* PRNG seed.
*
* @name seed
* @memberof RandomStream.prototype
* @type {(PRNGSeedMT19937|null)}
*/
setReadOnlyAccessor( RandomStream.prototype, 'seed', getSeed );

/**
* PRNG seed length.
*
* @name seedLength
* @memberof RandomStream.prototype
* @type {(PositiveInteger|null)}
*/
setReadOnlyAccessor( RandomStream.prototype, 'seedLength', getSeedLength );

/**
* PRNG state getter/setter.
*
* @name state
* @memberof RandomStream.prototype
* @type {(PRNGStateMT19937|null)}
* @throws {Error} must provide a valid state
*/
setReadWriteAccessor( RandomStream.prototype, 'state', getState, setState );

/**
* PRNG state length.
*
* @name stateLength
* @memberof RandomStream.prototype
* @type {(PositiveInteger|null)}
*/
setReadOnlyAccessor( RandomStream.prototype, 'stateLength', getStateLength );

/**
* PRNG state size (in bytes).
*
* @name byteLength
* @memberof RandomStream.prototype
* @type {(PositiveInteger|null)}
*/
setReadOnlyAccessor( RandomStream.prototype, 'byteLength', getStateSize );

/**
* Implements the `_read` method.
*
* @private
* @name _read
* @memberof RandomStream.prototype
* @type {Function}
* @param {number} size - number (of bytes) to read
* @returns {void}
*/
setNonEnumerableReadOnly( RandomStream.prototype, '_read', read );

/**
* Gracefully destroys a stream, providing backward compatibility.
*
* @name destroy
* @memberof RandomStream.prototype
* @type {Function}
* @param {(string|Object|Error)} [error] - error
* @returns {RandomStream} Stream instance
*/
setNonEnumerableReadOnly( RandomStream.prototype, 'destroy', destroy );

// EXPORTS //

module.exports = RandomStream;
<|endoftext|>


<commit_before>import * as React from 'react';
import { Motion } from 'react-motion';
import { Modal } from 'react-native';
import spring from './spring';

class SharedElementMotion extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.animate = this.animate.bind(this);
        this.reset = this.reset.bind(this);
        this.state = {
            url: this.getStateNavigator().stateContext.url,
            sharedElements: [], animatedElements: {}, force: 1,
        };
    }
    static contextTypes = {
        stateNavigator: React.PropTypes.object,
        getSharedElements: React.PropTypes.func
    }
    getStateNavigator() {
        return this.props.stateNavigator || this.context.stateNavigator;
    }
    componentDidMount() {
        this.getStateNavigator().onNavigate(this.reset);
        this.animate();
        this.animateTimeout = setTimeout(() => cancelAnimationFrame(this.animatedId), 300);
    }
    componentWillUnmount() {
        this.getStateNavigator().offNavigate(this.reset);
        cancelAnimationFrame(this.animatedId);
        clearTimeout(this.animateTimeout);
    }
    animate() {
        this.animatedId = requestAnimationFrame(() => {
            if (this.state.url !== this.getStateNavigator().stateContext.url)
                return;
            var sharedElements = this.context.getSharedElements();
            if (sharedElements.length !== 0) {
                this.setState({sharedElements}, () => {
                    var {onAnimating} = this.props;
                    for(var i = 0; i < sharedElements.length && onAnimating; i++) {
                        var {name, oldElement: old, mountedElement: mounted} = sharedElements[i];
                        if (!this.state.animatedElements[name])
                            onAnimating(name, old.ref, mounted.ref, old.data, mounted.data);
                    }
                });
            }
            this.animate();
        });
    }
    reset() {
        if (this.state.url === this.getStateNavigator().stateContext.url) {
            this.setState(({force}) => ({sharedElements: [], animatedElements: {}, force: force + 1}));
            cancelAnimationFrame(this.animatedId);
            clearTimeout(this.animateTimeout);
            this.animate();
            this.animateTimeout = setTimeout(() => cancelAnimationFrame(this.animatedId), 300);
        }
    }
    stripStyle(style) {
        var newStyle = {};
        for(var key in style) {
            newStyle[key] = style[key].val;
        }
        return newStyle;
    }
    onAnimated(name, old, mounted) {
        this.setState(
            ({animatedElements}) => ({animatedElements: {...animatedElements, [name]: true}}),
            () => {
                var {onAnimated = () => {}} = this.props;
                var unmounted = old.url = this.getStateNavigator().stateContext.oldUrl;
                onAnimated(name, !unmounted ? old.ref : null, mounted.ref, !unmounted ? old.data : null, mounted.data)
            }
        );
    }
    render() {
        var {children, elementStyle} = this.props;
        var {url, sharedElements, animatedElements, force} = this.state;
        return (url === this.getStateNavigator().stateContext.url &&
            <Modal
                transparent={true} animationType="none" onRequestClose={() => {}}
                visible={sharedElements.length > Object.keys(animatedElements).length}
                supportedOrientations={['portrait', 'landscape', 'landscape-left', 'landscape-right']}>
                {sharedElements.map(({name, oldElement: old, mountedElement: mounted}) => (
                    <Motion
                        key={name} onRest={() => {this.onAnimated(name, old, mounted)}}
                        defaultStyle={{...this.stripStyle(elementStyle(name, {...old.measurements, ...old.data})), __force: 0}}
                        style={{...elementStyle(name, {...mounted.measurements, ...mounted.data}), __force: spring(force)}}>
                        {({__force, ...tweenStyle}) => children(tweenStyle, name, old.data, mounted.data)}
                    </Motion>
                ))}
            </Modal>
        );
    }
}

export default SharedElementMotion;
<commit_msg>Renamed raf to match timeoute<commit_after>import * as React from 'react';
import { Motion } from 'react-motion';
import { Modal } from 'react-native';
import spring from './spring';

class SharedElementMotion extends React.Component {
    constructor(props, context) {
        super(props, context);
        this.animate = this.animate.bind(this);
        this.reset = this.reset.bind(this);
        this.state = {
            url: this.getStateNavigator().stateContext.url,
            sharedElements: [], animatedElements: {}, force: 1,
        };
    }
    static contextTypes = {
        stateNavigator: React.PropTypes.object,
        getSharedElements: React.PropTypes.func
    }
    getStateNavigator() {
        return this.props.stateNavigator || this.context.stateNavigator;
    }
    componentDidMount() {
        this.getStateNavigator().onNavigate(this.reset);
        this.animate();
        this.animateTimeout = setTimeout(() => cancelAnimationFrame(this.animateFrame), 300);
    }
    componentWillUnmount() {
        this.getStateNavigator().offNavigate(this.reset);
        cancelAnimationFrame(this.animateFrame);
        clearTimeout(this.animateTimeout);
    }
    animate() {
        this.animateFrame = requestAnimationFrame(() => {
            if (this.state.url !== this.getStateNavigator().stateContext.url)
                return;
            var sharedElements = this.context.getSharedElements();
            if (sharedElements.length !== 0) {
                this.setState({sharedElements}, () => {
                    var {onAnimating} = this.props;
                    for(var i = 0; i < sharedElements.length && onAnimating; i++) {
                        var {name, oldElement: old, mountedElement: mounted} = sharedElements[i];
                        if (!this.state.animatedElements[name])
                            onAnimating(name, old.ref, mounted.ref, old.data, mounted.data);
                    }
                });
            }
            this.animate();
        });
    }
    reset() {
        if (this.state.url === this.getStateNavigator().stateContext.url) {
            this.setState(({force}) => ({sharedElements: [], animatedElements: {}, force: force + 1}));
            cancelAnimationFrame(this.animateFrame);
            clearTimeout(this.animateTimeout);
            this.animate();
            this.animateTimeout = setTimeout(() => cancelAnimationFrame(this.animateFrame), 300);
        }
    }
    stripStyle(style) {
        var newStyle = {};
        for(var key in style) {
            newStyle[key] = style[key].val;
        }
        return newStyle;
    }
    onAnimated(name, old, mounted) {
        this.setState(
            ({animatedElements}) => ({animatedElements: {...animatedElements, [name]: true}}),
            () => {
                var {onAnimated = () => {}} = this.props;
                var unmounted = old.url = this.getStateNavigator().stateContext.oldUrl;
                onAnimated(name, !unmounted ? old.ref : null, mounted.ref, !unmounted ? old.data : null, mounted.data)
            }
        );
    }
    render() {
        var {children, elementStyle} = this.props;
        var {url, sharedElements, animatedElements, force} = this.state;
        return (url === this.getStateNavigator().stateContext.url &&
            <Modal
                transparent={true} animationType="none" onRequestClose={() => {}}
                visible={sharedElements.length > Object.keys(animatedElements).length}
                supportedOrientations={['portrait', 'landscape', 'landscape-left', 'landscape-right']}>
                {sharedElements.map(({name, oldElement: old, mountedElement: mounted}) => (
                    <Motion
                        key={name} onRest={() => {this.onAnimated(name, old, mounted)}}
                        defaultStyle={{...this.stripStyle(elementStyle(name, {...old.measurements, ...old.data})), __force: 0}}
                        style={{...elementStyle(name, {...mounted.measurements, ...mounted.data}), __force: spring(force)}}>
                        {({__force, ...tweenStyle}) => children(tweenStyle, name, old.data, mounted.data)}
                    </Motion>
                ))}
            </Modal>
        );
    }
}

export default SharedElementMotion;
<|endoftext|>


<commit_before>/**
	The MIT License (MIT)

	Copyright (c) 2014 MyChannel-Apps.de

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

	@author		Adrian Preuß <Bizarrus>, Christoph Kühl <djchrisnet>
*/

var Users = (new function() {
	this.get = function(nickname) {
		if(KnuddelsServer.userExists(nickname)) {
			var userId	= KnuddelsServer.getUserId(nickname);

			if(KnuddelsServer.canAccessUser(userId)) {
				nickname	= KnuddelsServer.getUser(userId);
			}
		} else {
			return undefined;
		}

		if(typeof(nickname) == 'string') {
			return (new function() {
				var _nickname			= nickname;
				var _uid 				= userId;
				this.virtual			= true;
				this.getPersistence		= function(_uid) {
					return (new function Persistence(uid) {
						_uid = uid;

						this.getString = function(key, defaults) { return DB.load('_userdb')[_uid][key] || defaults; };
						this.getNumber = function(key, defaults) { return DB.load('_userdb')[_uid][key] || defaults; };
						this.getObject = function(key, defaults) { return DB.load('_userdb')[_uid][key] || defaults; };

						this.deleteNumber = function(key) {
							userdb = DB.load('_userdb');
							delete userdb[_uid][key];
							DB.save('_userdb', userdb);
						};
						this.deleteObject = function(key) {
							userdb = DB.load('_userdb');
							delete userdb[_uid][key];
							DB.save('_userdb', userdb);
						};
						this.deleteString = function(key) {
							userdb = DB.load('_userdb');
							delete userdb[_uid][key];
							DB.save('_userdb', userdb);
						};
						this.setString = function(key, data) {
							userdb = DB.load('_userdb');
							userdb[_uid][key] = data;
							DB.save('_userdb', userdb);
						};
						this.setNumber = function(key, data) {
							userdb = DB.load('_userdb');
							userdb[_uid][key] = data;
							DB.save('_userdb', userdb);
						};
						this.setObject = function(key, data) {
							userdb = DB.load('_userdb');
							userdb[_uid][key] = data;
							DB.save('_userdb', userdb);
						};
					}());
				};
				this.equals				= function(user) {/* TODO */};
				this.getAge				= function() { return -1; };
				this.getGender			= function() { return Gender.Unknown; };
				this.getKnuddelAmount	= function() { return new KnuddelAmount(0); };
				this.getNick			= function() { return _nickname; };
				this.getOnlineMinutes	= function() { return -1; };
				this.getProfileLink		= function() { return '°>_h'+_nickname.escapeKCode()+'|/w "|/serverpp "<°'; };
				this.getReadme			= function() { return ''; };
				this.getRegDate			= function() { return new Date(0); };
				this.getUserId			= function() { return _uid; };
				this.getUserStatus		= function() { return UserStatus.Newbie; };
				this.getUserType		= function() { return UserType.Human; };
				this.isAppDeveloper		= function() { return false; };
				this.isAway				= function() { return false; };
				this.isChannelModerator	= function() { return false; };
				this.isChannelOwner		= function() { return false; };
				this.isEventModerator	= function() { return false; };
				this.isOnline			= function() { return false; };
				this.isOnlineInChannel	= function() { return false; };
				this.sendPostMessage	= function(topic, message) {};
				this.sendPrivateMessage	= function(message) {};
			}());
		}

		return nickname;
	};
}());<commit_msg>User: more methods<commit_after>/**
	The MIT License (MIT)

	Copyright (c) 2014 MyChannel-Apps.de

	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:

	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.

	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

	@author		Adrian Preuß <Bizarrus>, Christoph Kühl <djchrisnet>
*/

var Users = (new function() {
	this.online = function(type) {
		return KnuddelsServer.getChannel().getOnlineUsers(type);
	};

	this.moderators = function() {
		return KnuddelsServer.getChannel().getChannelConfiguration().getChannelRights().getChannelModerators();
	};

	this.get = function(nickname) {
		if(KnuddelsServer.userExists(nickname)) {
			var userId	= KnuddelsServer.getUserId(nickname);

			if(KnuddelsServer.canAccessUser(userId)) {
				nickname	= KnuddelsServer.getUser(userId);
			}
		} else {
			return undefined;
		}

		if(typeof(nickname) == 'string') {
			return (new function() {
				var _nickname			= nickname;
				var _uid 				= userId;
				this.virtual			= true;
				this.getPersistence		= function(_uid) {
					return (new function Persistence(uid) {
						_uid = uid;

						this.getString = function(key, defaults) { return DB.load('_userdb')[_uid][key] || defaults; };
						this.getNumber = function(key, defaults) { return DB.load('_userdb')[_uid][key] || defaults; };
						this.getObject = function(key, defaults) { return DB.load('_userdb')[_uid][key] || defaults; };

						this.deleteNumber = function(key) {
							userdb = DB.load('_userdb');
							delete userdb[_uid][key];
							DB.save('_userdb', userdb);
						};
						this.deleteObject = function(key) {
							userdb = DB.load('_userdb');
							delete userdb[_uid][key];
							DB.save('_userdb', userdb);
						};
						this.deleteString = function(key) {
							userdb = DB.load('_userdb');
							delete userdb[_uid][key];
							DB.save('_userdb', userdb);
						};
						this.setString = function(key, data) {
							userdb = DB.load('_userdb');
							userdb[_uid][key] = data;
							DB.save('_userdb', userdb);
						};
						this.setNumber = function(key, data) {
							userdb = DB.load('_userdb');
							userdb[_uid][key] = data;
							DB.save('_userdb', userdb);
						};
						this.setObject = function(key, data) {
							userdb = DB.load('_userdb');
							userdb[_uid][key] = data;
							DB.save('_userdb', userdb);
						};
					}());
				};
				this.equals				= function(user) {/* TODO */};
				this.getAge				= function() { return -1; };
				this.getGender			= function() { return Gender.Unknown; };
				this.getKnuddelAmount	= function() { return new KnuddelAmount(0); };
				this.getNick			= function() { return _nickname; };
				this.getOnlineMinutes	= function() { return -1; };
				this.getProfileLink		= function() { return '°>_h'+_nickname.escapeKCode()+'|/w "|/serverpp "<°'; };
				this.getReadme			= function() { return ''; };
				this.getRegDate			= function() { return new Date(0); };
				this.getUserId			= function() { return _uid; };
				this.getUserStatus		= function() { return UserStatus.Newbie; };
				this.getUserType		= function() { return UserType.Human; };
				this.isAppDeveloper		= function() { return false; };
				this.isAway				= function() { return false; };
				this.isChannelModerator	= function() { return false; };
				this.isChannelOwner		= function() { return false; };
				this.isEventModerator	= function() { return false; };
				this.isOnline			= function() { return false; };
				this.isOnlineInChannel	= function() { return false; };
				this.sendPostMessage	= function(topic, message) {};
				this.sendPrivateMessage	= function(message) {};
			}());
		}

		return nickname;
	};
}());<|endoftext|>


<commit_before>var path = require('path'),
  fs = require('fs'),
  util = require('util'),
  crypto = require('crypto'),
  extend = require('extend'),
  net = require('net'),
  http = require('http'),
  https = require('https'),
  cluster = require('cluster'),
  async = require('async'),
  regexpQuote = require('./DispatchTable').regexpQuote,
  url = require('url'),
  tls = require('tls');

var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);

var EventEmitter = require('events').EventEmitter;

var config = {}; // will be sent by master
var argv = {}; // will be sent by master

var common = require('./common');
var runModules = common.runModules;
var punycode = require('punycode');

var createCredentials;
if(tls.createSecureContext) {
  createCredentials = tls.createSecureContext;
} else {
  createCredentials = crypto.createCredentials;
}

function getTcpServer(port, host, cb) {
  var tcpServers = this.tcpServers;

  var entry = (host ? host + ":" + port : port);
  if (tcpServers[entry]) {
    cb(null, tcpServers[entry]);
  } else {
    var tcpServer = tcpServers[entry] = net.createServer();

    function handler(err) {
      if (err) return cb(err);
      cb(null, tcpServer);
    }
    try {
      if (host)
        tcpServer.listen(port, host, handler);
      else
        tcpServer.listen(port, handler);
      tcpServer.once('error', function(err) {
        delete tcpServers[entry];
        cb(err);
      });
    } catch (err) {
      cb(err);
    }
  }
}

function normalizeCert(cert) {
  if (!cert.match(/\n$/g)) {
    return cert + "\n";
  }
  return cert;
}

function loadKeysforConfigEntry(config, callback) {

  if (config.ssl) {
    var SNI = config.ssl.SNI;
    var SNImatchers = {};
    if (config.ssl.SNI) {
      for (key in config.ssl.SNI) {
        SNImatchers[key] = new RegExp(regexpQuote(key).replace(/^\\\*\\\./g, '^([^.]+\\.)?'), 'i'); // domain names are case insensitive
      }
      var sniCallback = function(hostname, cb) {
        hostname = punycode.toUnicode(hostname);
        for (key in SNI) {
          if (hostname.match(SNImatchers[key])) {
            if (cb) // since node 0.11.5
              return cb(null, SNI[key])
            else
              return SNI[key];
          }
        }
        if (cb)
          return cb(null);
      }
      config.ssl.SNICallback = sniCallback;
    }

    //    loadKeysForContext(config.ssl, function(err) {
    //      if (err) return callback(err);

    if (SNI) {
      var todo = [];
      for (key in SNI)
        todo.push(key);

      async.each(todo, function(key, sniLoaded) {
        SNI[key].ciphers = SNI[key].ciphers || config.ssl.ciphers;
        SNI[key].honorCipherOrder = SNI[key].honorCipherOrder || config.ssl.honorCipherOrder;
        SNI[key].ecdhCurve = SNI[key].ecdhCurve || config.ssl.ecdhCurve;

        // joyent/node#7249
        if (SNI[key].honorCipherOrder) {
          SNI[key].secureOptions = require('constants').SSL_OP_CIPHER_SERVER_PREFERENCE;
        }
        if (!SNI[key].ecdhCurve) {
          SNI[key].ecdhCurve = require('tls').DEFAULT_ECDH_CURVE;
        }

        //          loadKeysForContext(SNI[key], function(err) {
        //            if (err) return sniLoaded(err);
        try {
          var credentials = createCredentials(SNI[key]);
          SNI[key] = credentials.context;
          sniLoaded();
        } catch (err) {
          sniLoaded(err);
        }
        //          });
      }, callback);
    } else { // (!SNI)
      callback();
    }
    //    });
  } else { // (!config.ssl)
    callback();
  }
}

function handleConfigEntry(config, callback) {
  var self = this;
  loadKeysforConfigEntry(config, function(err) {
    if (err) {
      return callback(err);
    }
    handleConfigEntryAfterLoadingKeys.call(self, config, callback);
  });
}

function handleConfigEntryAfterLoadingKeys(config, callback) {
  var self = this;
  //
  // Check to see if we should silence the logs
  //
  config.silent = typeof argv.silent !== 'undefined' ? argv.silent : config.silent;

  var middlewares = [];

  var requestHandlers = [];
  var upgradeHandlers = [];

  runModules(function(name, middleware) {
    if (middleware.failedEntries) {
      Object.keys(middleware.failedEntries).forEach(function(key) {
        var failedEntry = middleware.failedEntries[key];
        self.logError('Failed starting entry ' + key + ' : ' + JSON.stringify(failedEntry.entry));
        self.logError(failedEntry.err);
      });
    }

    middlewares.push(middleware);
    if (typeof middleware == 'function')
      requestHandlers.push(middleware);
    else if (middleware.requestHandler)
      requestHandlers.push(middleware.handleRequest.bind(middleware));
    if (middleware.upgradeHandler)
      upgradeHandlers.push(middleware.handleUpgrade.bind(middleware));
  }, "middleware", config);

  var handler = require('./requestHandler')(config, requestHandlers);

  var server;
  try {
    if (config.ssl) {
      var baseModule = config.ssl.spdy ? require('spdy') : https;

      server = baseModule.createServer(config.ssl, handler.request);

      if (!config.ssl.skipWorkerSessionResumption) {
        server.on('resumeSession', self.tlsSessionStore.get.bind(self.tlsSessionStore));
        server.on('newSession', self.tlsSessionStore.set.bind(self.tlsSessionStore));

        if (self.token) {
          if (server._setServerData) {
            server._setServerData({
              ticketKeys: self.token
            });
          } else {
            self.logNotice("SSL/TLS ticket session resumption may not work due to missing method _setServerData, you might be using an old version of Node");
          }
        }
      }

    } else {
      server = http.createServer(handler.request);
    }
  } catch (err) {
    return callback(err, null);
  }

  function listeningHandler() {
    server.removeAllListeners('error'); // remove the below handler
    callback(null, server);
    server.removeListener('error', errorHandler);
  }

  function errorHandler(err) {
    server.removeAllListeners('listening'); // remove the above handler
    callback(err, server);
    server.removeListener('listening', listeningHandler);
  }

  server.once('listening', listeningHandler);
  server.once('error', errorHandler);
  server.on('upgrade', function(req, socket, head) {
    req.parsedUrl = url.parse(req.url);
    for (var i = 0; i < upgradeHandlers.length; ++i) {
      if (upgradeHandlers[i](req, socket, head)) { // ws handled
        break;
      }
    }
  });

  getTcpServer.call(this, config.port, config.host, function(err, tcpServer) {

    if (err) return callback(err, server);

    tcpServer.removeAllListeners();
    tcpServer.on('connection', function(socket) {
      server.emit('connection', socket);
    });
    tcpServer.on('error', function(err) {
      server.emit('error', err);
    });
    tcpServer.on('close', function(err) {
      server.emit('close');
    });
    server.emit('listening');
    // FIXME: this should run at every config reload

    runModules('onServerListening', config, server);
  });
}

function handleConfig(config, configHandled) {
  var self = this;
  runModules('preprocessConfig', config);

  async.parallel(Object.keys(config.ports || {}).map(function(portEntry) {

    return function(asyncCallback) {

      var m;
      // TODO: IPV6?
      if ((m = portEntry.match(/((\S+):)?(\d+)(?:(?:\s*=>\s*)?(\S+):(\d+)?)?/))) {
        var host = m[2];
        var port = parseInt(m[3]);
        var targetHost = m[4];
        var targetPort = m[5];

        var portConfig = config.ports[portEntry];
        var configEntry = extend({
          targetHost: targetHost,
          targetPort: targetPort,
          host: host,
          port: port,
        }, portConfig);

        handleConfigEntry.call(self, configEntry, function(err, server) {
          var entryString = (configEntry.host ? configEntry.host + ":" + configEntry.port : "port " + configEntry.port);
          if (err) {
            self.logError("Error while starting entry " + entryString + " : " + err.toString());
            if (err.stack)
              self.logError(err.stack);
          }
          if (server) {
            self.logNotice("Listening on port: " + entryString);
          } else
            self.logNotice("Entry " + entryString + " is unusable");
          // ignore error to not crash the entire proxy
          asyncCallback(null, server);
        });
      };
    };
  }), function(err, results) {
    if (err) {
      return configHandled(err);
    }
    self.logNotice("Start successful");

    // TODO
    //dropPrivileges();

    self.servers = results.filter(function(server) {
      return !!server;
    });
    configHandled();
  });
}

function unbindAll(cb) {
  this.servers.forEach(function(server) {
    server.removeAllListeners();
  });
  var self = this;
  Object.keys(this.tcpServers).forEach(function(key) {
    self.tcpServers[key].removeAllListeners();
  });
  cb();
}

function HttpMasterWorker(config) {
  config = config || {};
  var store = {};
  this.tlsSessionStore = config.tlsSessionStore || {
    get: function(id, cb) {
      id = id.toString('base64');
      cb(null, store[id], null);
    },
    set: function(id, data, cb) {
      id = id.toString('base64');
      store[id] = data;
      if (cb)
        cb();
    }
  };
  this.tcpServers = {};
  this.servers = [];
}

HttpMasterWorker.prototype = Object.create(EventEmitter.prototype);

HttpMasterWorker.prototype.logNotice = function(msg) {
  this.emit('logNotice', msg);
}

HttpMasterWorker.prototype.logError = function(msg) {
  this.emit('logError', msg);
}

HttpMasterWorker.prototype.unbindAll = function(unbindFinished) {
  unbindAll.call(this, unbindFinished);
}

HttpMasterWorker.prototype.loadConfig = function(config, configLoaded) {
  var self = this;

  this.unbindAll(function() {});

  handleConfig.call(this, config, function(err) {
    if (err) return configLoaded(err);
    self.gcServers(configLoaded);
  });

}

HttpMasterWorker.prototype.gcServers = function(gcFinished) {
  var self = this;
  var toClose = [];

  Object.keys(this.tcpServers).forEach(function(key) {
    var server = self.tcpServers[key];
    if (EventEmitter.listenerCount(server, 'connection') === 0) {
      toClose.push(server);
      delete self.tcpServers[key];
    }
  });
  async.each(toClose, function(server, cb) {
    server.close();
    cb();
  }, gcFinished);

};

module.exports = HttpMasterWorker;<commit_msg>Implement #57 and #58<commit_after>var path = require('path'),
  fs = require('fs'),
  util = require('util'),
  crypto = require('crypto'),
  extend = require('extend'),
  net = require('net'),
  http = require('http'),
  https = require('https'),
  cluster = require('cluster'),
  async = require('async'),
  regexpQuote = require('./DispatchTable').regexpQuote,
  url = require('url'),
  tls = require('tls');

var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);

var EventEmitter = require('events').EventEmitter;

var config = {}; // will be sent by master
var argv = {}; // will be sent by master

var common = require('./common');
var runModules = common.runModules;
var punycode = require('punycode');

var createCredentials;
if(tls.createSecureContext) {
  createCredentials = tls.createSecureContext;
} else {
  createCredentials = crypto.createCredentials;
}

function getTcpServer(port, host, cb) {
  var tcpServers = this.tcpServers;

  var entry = (host ? host + ":" + port : port);
  if (tcpServers[entry]) {
    cb(null, tcpServers[entry]);
  } else {
    var tcpServer = tcpServers[entry] = net.createServer();

    function handler(err) {
      if (err) return cb(err);
      cb(null, tcpServer);
    }
    try {
      if (host)
        tcpServer.listen(port, host, handler);
      else
        tcpServer.listen(port, handler);
      tcpServer.once('error', function(err) {
        delete tcpServers[entry];
        cb(err);
      });
    } catch (err) {
      cb(err);
    }
  }
}

function normalizeCert(cert) {
  if (!cert.match(/\n$/g)) {
    return cert + "\n";
  }
  return cert;
}

function loadKeysforConfigEntry(config, callback) {

  if (config.ssl) {
    var SNI = config.ssl.SNI;
    var SNImatchers = {};
    if (config.ssl.SNI) {
      for (key in config.ssl.SNI) {
        SNImatchers[key] = new RegExp(regexpQuote(key).replace(/^\\\*\\\./g, '^([^.]+\\.)?'), 'i'); // domain names are case insensitive
      }
      var sniCallback = function(hostname, cb) {
        hostname = punycode.toUnicode(hostname);
        for (key in SNI) {
          if (hostname.match(SNImatchers[key])) {
            if (cb) // since node 0.11.5
              return cb(null, SNI[key])
            else
              return SNI[key];
          }
        }
        if (cb)
          return cb(null);
      }
      config.ssl.SNICallback = sniCallback;
    }

    //    loadKeysForContext(config.ssl, function(err) {
    //      if (err) return callback(err);

    if (SNI) {
      var todo = [];
      for (key in SNI)
        todo.push(key);

      async.each(todo, function(key, sniLoaded) {
        SNI[key].ciphers = SNI[key].ciphers || config.ssl.ciphers;
        SNI[key].honorCipherOrder = SNI[key].honorCipherOrder || config.ssl.honorCipherOrder;
        SNI[key].ecdhCurve = SNI[key].ecdhCurve || config.ssl.ecdhCurve;

        // joyent/node#7249
        if (SNI[key].honorCipherOrder) {
          SNI[key].secureOptions = require('constants').SSL_OP_CIPHER_SERVER_PREFERENCE;
        }
        if (!SNI[key].ecdhCurve) {
          SNI[key].ecdhCurve = require('tls').DEFAULT_ECDH_CURVE;
        }

        //          loadKeysForContext(SNI[key], function(err) {
        //            if (err) return sniLoaded(err);
        try {
          var credentials = createCredentials(SNI[key]);
          SNI[key] = credentials.context;
          sniLoaded();
        } catch (err) {
          sniLoaded(err);
        }
        //          });
      }, callback);
    } else { // (!SNI)
      callback();
    }
    //    });
  } else { // (!config.ssl)
    callback();
  }
}

function handleConfigEntry(config, callback) {
  var self = this;
  loadKeysforConfigEntry(config, function(err) {
    if (err) {
      return callback(err);
    }
    handleConfigEntryAfterLoadingKeys.call(self, config, callback);
  });
}

function handleConfigEntryAfterLoadingKeys(config, callback) {
  var self = this;
  //
  // Check to see if we should silence the logs
  //
  config.silent = typeof argv.silent !== 'undefined' ? argv.silent : config.silent;

  var middlewares = [];

  var requestHandlers = [];
  var upgradeHandlers = [];

  runModules(function(name, middleware) {
    if (middleware.failedEntries) {
      Object.keys(middleware.failedEntries).forEach(function(key) {
        var failedEntry = middleware.failedEntries[key];
        self.logError('Failed starting entry ' + key + ' : ' + JSON.stringify(failedEntry.entry));
        self.logError(failedEntry.err);
      });
    }

    middlewares.push(middleware);
    if (typeof middleware == 'function')
      requestHandlers.push(middleware);
    else if (middleware.requestHandler)
      requestHandlers.push(middleware.handleRequest.bind(middleware));
    if (middleware.upgradeHandler)
      upgradeHandlers.push(middleware.handleUpgrade.bind(middleware));
  }, "middleware", config);

  var handler = require('./requestHandler')(config, requestHandlers);

  var server;
  try {
    if (config.ssl) {
      var baseModule = config.ssl.spdy ? require('spdy') : https;

      if(nodeVersion >= 0.11) { // use fancy cipher settings only for 0.11
        if(config.ssl.honorCipherOrder !== false) {
           // prefer server ciphers over clients - prevents BEAST attack
           config.ssl.honorCipherOrder = true;
        }
        if(!config.ssl.ciphers) {
          config.ssl.ciphers = 'EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+AES+SHA:EECDH+aRSA+RC4:EECDH:EDH+aRSA:RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS::+RC4:RC4';
          if(config.ssl.disableWeakCiphers) {
            config.ssl.ciphers += ':!RC4';
          }
        }
      }

      server = baseModule.createServer(config.ssl, handler.request);

      if (!config.ssl.skipWorkerSessionResumption) {
        server.on('resumeSession', self.tlsSessionStore.get.bind(self.tlsSessionStore));
        server.on('newSession', self.tlsSessionStore.set.bind(self.tlsSessionStore));

        if (self.token) {
          if (server._setServerData) {
            server._setServerData({
              ticketKeys: self.token
            });
          } else {
            self.logNotice("SSL/TLS ticket session resumption may not work due to missing method _setServerData, you might be using an old version of Node");
          }
        }
      }
    } else {
      server = http.createServer(handler.request);
    }
  } catch (err) {
    return callback(err, null);
  }

  function listeningHandler() {
    server.removeAllListeners('error'); // remove the below handler
    callback(null, server);
    server.removeListener('error', errorHandler);
  }

  function errorHandler(err) {
    server.removeAllListeners('listening'); // remove the above handler
    callback(err, server);
    server.removeListener('listening', listeningHandler);
  }

  server.once('listening', listeningHandler);
  server.once('error', errorHandler);
  server.on('upgrade', function(req, socket, head) {
    req.parsedUrl = url.parse(req.url);
    for (var i = 0; i < upgradeHandlers.length; ++i) {
      if (upgradeHandlers[i](req, socket, head)) { // ws handled
        break;
      }
    }
  });

  getTcpServer.call(this, config.port, config.host, function(err, tcpServer) {

    if (err) return callback(err, server);

    tcpServer.removeAllListeners();
    tcpServer.on('connection', function(socket) {
      server.emit('connection', socket);
    });
    tcpServer.on('error', function(err) {
      server.emit('error', err);
    });
    tcpServer.on('close', function(err) {
      server.emit('close');
    });
    server.emit('listening');
    // FIXME: this should run at every config reload

    runModules('onServerListening', config, server);
  });
}

function handleConfig(config, configHandled) {
  var self = this;
  runModules('preprocessConfig', config);

  async.parallel(Object.keys(config.ports || {}).map(function(portEntry) {

    return function(asyncCallback) {

      var m;
      // TODO: IPV6?
      if ((m = portEntry.match(/((\S+):)?(\d+)(?:(?:\s*=>\s*)?(\S+):(\d+)?)?/))) {
        var host = m[2];
        var port = parseInt(m[3]);
        var targetHost = m[4];
        var targetPort = m[5];

        var portConfig = config.ports[portEntry];
        var configEntry = extend({
          targetHost: targetHost,
          targetPort: targetPort,
          host: host,
          port: port,
        }, portConfig);

        handleConfigEntry.call(self, configEntry, function(err, server) {
          var entryString = (configEntry.host ? configEntry.host + ":" + configEntry.port : "port " + configEntry.port);
          if (err) {
            self.logError("Error while starting entry " + entryString + " : " + err.toString());
            if (err.stack)
              self.logError(err.stack);
          }
          if (server) {
            self.logNotice("Listening on port: " + entryString);
          } else
            self.logNotice("Entry " + entryString + " is unusable");
          // ignore error to not crash the entire proxy
          asyncCallback(null, server);
        });
      };
    };
  }), function(err, results) {
    if (err) {
      return configHandled(err);
    }
    self.logNotice("Start successful");

    // TODO
    //dropPrivileges();

    self.servers = results.filter(function(server) {
      return !!server;
    });
    configHandled();
  });
}

function unbindAll(cb) {
  this.servers.forEach(function(server) {
    server.removeAllListeners();
  });
  var self = this;
  Object.keys(this.tcpServers).forEach(function(key) {
    self.tcpServers[key].removeAllListeners();
  });
  cb();
}

function HttpMasterWorker(config) {
  config = config || {};
  var store = {};
  this.tlsSessionStore = config.tlsSessionStore || {
    get: function(id, cb) {
      id = id.toString('base64');
      cb(null, store[id], null);
    },
    set: function(id, data, cb) {
      id = id.toString('base64');
      store[id] = data;
      if (cb)
        cb();
    }
  };
  this.tcpServers = {};
  this.servers = [];
}

HttpMasterWorker.prototype = Object.create(EventEmitter.prototype);

HttpMasterWorker.prototype.logNotice = function(msg) {
  this.emit('logNotice', msg);
}

HttpMasterWorker.prototype.logError = function(msg) {
  this.emit('logError', msg);
}

HttpMasterWorker.prototype.unbindAll = function(unbindFinished) {
  unbindAll.call(this, unbindFinished);
}

HttpMasterWorker.prototype.loadConfig = function(config, configLoaded) {
  var self = this;

  this.unbindAll(function() {});

  handleConfig.call(this, config, function(err) {
    if (err) return configLoaded(err);
    self.gcServers(configLoaded);
  });

}

HttpMasterWorker.prototype.gcServers = function(gcFinished) {
  var self = this;
  var toClose = [];

  Object.keys(this.tcpServers).forEach(function(key) {
    var server = self.tcpServers[key];
    if (EventEmitter.listenerCount(server, 'connection') === 0) {
      toClose.push(server);
      delete self.tcpServers[key];
    }
  });
  async.each(toClose, function(server, cb) {
    server.close();
    cb();
  }, gcFinished);

};

module.exports = HttpMasterWorker;<|endoftext|>


<commit_before>(function (factory) {
    var root = (typeof self == 'object' && self.self == self && self) ||
        (typeof global == 'object' && global.global == global && global);

    if (typeof define === 'function' && define.amd) {
        define(['exports'], function (exports) {
            module.exports= factory(root, exports);
        });
    } else if (typeof exports !== 'undefined') {
        module.exports=factory(root, exports);
    } else {
         factory(root, {});
    }

}(function (root, modelObj) {
  root.Ds = root.Ds || {};
  root.Ds.gemo = root.Ds.gemo || {};
  root.Ds.gemo.InputInteractive=InputInteractive;
  function InputInteractive(){}
  /**
   * 省市联动二级组件 绑定方法
   * @param  {[String]}   pUrl  [省份请求接口地址]
   * @param  {[String]}   cUrl  [城市请求接口地址]
   * @param  {[DOM]}   domBox  [组件所在dom]
   * @param  {[Object]}   opts  [description]
   * opts.pName  省份的class名称   默认 province
   * opts.cName  城市份的class名称 默认 city
   * opts.replace  是否使用代替的div 或者其他dom来显示 ,默认true
   * 如果replace  为true,  .province+'Label' 与  .city+'Label' 是代替显示的选择结果
   * opts.dataType  ajax 请求方式
   * opts.pDesc   省份进行显示描述字段  默认'province_desc'
   * opts.pID     省份交互请求id字段  默认'province_id'
   * opts.cDesc   省份进行显示描述字段  默认'province_desc'
   * opts.defaultP   省份默认选择空显示项
   * opts.defaultC   城市默认选择空显示项
   * opts.select     城市选择调用
   * @example
   *    html结构可以如下

       <select class="province"></select>

城市

       <select class="city"></select>
       //---------------js
       var _provincesDataUrl=SiteModel.APIer.WebUrl+'/ajax/Ajax.aspx?method=GetProvince';
       var _cityDataUrl=SiteModel.APIer.WebUrl+'/ajax/Ajax.aspx?method=GetCity';
       Ds.gemo.InputInteractive.ProvincesCityLinkComponents(
         _provincesDataUrl,
         _cityDataUrl,
         _Dom,
         {
           pDesc:'province_desc',//省份数据描述字段
           cDesc:'c_desc',//城市数据描述字段
           pID:'province_id'//获取城市list 提交省份字段
         }
       );
   * @return {[type]} [description]
   */

  InputInteractive.ProvincesCityLinkComponents=function(pUrl,cUrl,domBox,opts){
    opts=opts||{};
    var _dataType=opts.dataType!==undefined?opts.dataType:'json';
    if(!opts.defaultP)opts.defaultP='省份';
    if(!opts.defaultC)opts.defaultC='城市';
    var _pName=opts.pName||'province';
    var _cName=opts.cName||'city';
    var _provinceDom=domBox.find('.'+_pName)[0],_cityDom=domBox.find('.'+_cName)[0];
    if(!_provinceDom||!_cityDom){
      console.warn('InputInteractive.ProvincesCityLinkComponents 没有对应的dom对象');
      return;
    }
    var _provinceLabel,_cityLabel;
    var _replace=opts.replace;
    if(opts.replace===undefined)_replace=true;
    if(_replace){
      _provinceLabel=domBox.find('.'+_pName+'Label')[0];
      _cityLabel=domBox.find('.'+_cName+'Label')[0];
      Ds.gemo.InputInteractive.SetShowLabelUpChange(_provinceDom,_provinceLabel);
      Ds.gemo.InputInteractive.SetShowLabelUpChange(_cityDom,_cityLabel);
    }

    var _provinceConfig={
      dataType:_dataType,//ajax 使用 jsonp跨域
      label:opts.pDesc!==undefined?opts.pDesc:'province_desc',//需要在选项里面显示的内容
      defaultData:opts.defaultP!==undefined?opts.defaultP:'省份',
      callback:function(){
        if(_replace)Ds.gemo.InputInteractive.UpSelectShowLabel(_provinceDom,_provinceLabel);
      },
      select:provinceSelectUpCity
    };

    Ds.gemo.InputInteractive.CreatSelectGetUrl(pUrl,{},
      _provinceDom,
      _provinceConfig
    );

    function provinceSelectUpCity(option,index,data){
      console.log('provinceSelectUpCity:',data,opts.defaultP);
      if(data===opts.defaultP)return;
      var _cityConfig={
        dataType:_dataType,//ajax 使用 jsonp跨域
        label:opts.cDesc!==undefined?opts.cDesc:'city_desc',//需要在选项里面显示的内容
        defaultData:opts.defaultC!==undefined?opts.defaultC:'城市',
        callback:function(){
          if(_replace)Ds.gemo.InputInteractive.UpSelectShowLabel(_cityDom,_cityLabel);
        },
        select:function(option,index,data){
          if(opts.select)opts.select(option,index,data);
        }
      };
      var _postData={};
      if(opts.pID)_postData[opts.pID]=data[opts.pID];
      else if(data['province_id'])_postData['province_id']=data['province_id'];
      else _postData.province_id='';
      Ds.gemo.InputInteractive.CreatSelectGetUrl(cUrl,_postData,_cityDom,_cityConfig);
    }

  };
  /**
   * 使用url创建下来选择项目
   * @param  {[type]}   url        [获取内容的url]
   * @param  {[type]}   postData [post数据]
   * @param  {[type]}   selectDom [下拉列表dom对象]
   * @param  {[Object]}   opts  [description]
   * opts.type      ajax请求类型  默认POST
   * opts.dataType      ajax请求类型  默认json
   * opts.defaultData   默认选择值
   * opts.label     label值   需要显示value内的变量名  默认空
   * opts.value     数据值  value如果是object 会转换成json  默认空
   * opts.callback   ajax后callback
   * opts.erorr   ajax erorr后callback
   *
   * @return {[type]}              [description]
   */
  InputInteractive.CreatSelectGetUrl=function(url,postData,selectDom,opts){
    selectDom=getHTMLElement(selectDom);
    opts=opts||{};
    var _type=opts.type!==undefined?opts.type:'POST';
    var _dataType=opts.dataType!==undefined?opts.dataType:'json';
    if(_dataType==='jsonp')_type = 'GET';
    if(opts.debug)console.log('InputInteractive.CreatSelectGetUrl:',url);
    // console.log('InputInteractive.CreatSelectGetUrl:',url,postData,opts);
    $.ajax({
      type:_type,
      url:url,
      data:postData!==undefined?postData:{},
      dataType:opts.dataType||'json',
      success: function(data){
        if(typeof(data)==='string')data=JSON.parse(data);
        if(opts.debug)console.log('CreatSelectGetUrl: ' + url + ':', data);
        // console.log('CreatSelectGetUrl: ' + url + ':', data);
        //如果是公司数据返回结果处理方式
        if (data&&data.IsSuccess&&Number(data.IsSuccess) !== 1) {
          if(opts.erorr)opts.erorr(data.ErrMsg,data);
          return;
        }
        var _dataList=data.data;
        InputInteractive.UpSelectListData(selectDom,_dataList,opts);
        if(opts.callback)opts.callback(data);
        selectOption();
        // console.log(data);
      },
      error: function(xhr, type){
        console.log('Error：',url);
        if(opts.erorr)opts.erorr('网络异常');
      }
    });

    if(selectDom.selectOptionFun)  selectDom.removeEventListener('change',selectDom.selectOptionFun);

    selectDom.selectOptionFun=selectOption;
    selectDom.addEventListener('change',selectOption);
    function  selectOption() {
      var _index=selectDom.selectedIndex;
      var _option=selectDom.options[_index];
      var _data=_option.data;
      if(opts.select)opts.select(_option,_index,_option.data);
    }

  };
  /**
   * 更新选择列表项目
   * @param  {[type]} selectDom [列表数据]
   * @param  {[type]} dataList [列表数据]
   * @param  {[type]} opts      [参数]
   * opts.defaultData   默认选择值
   * @return {[type]}           [description]
   */
  InputInteractive.UpSelectListData=function(selectDom,dataList,opts){
    selectDom=getHTMLElement(selectDom);
    selectDom.options.length=0;
    selectDom.options=[];
    var _option,_data,_label,_value;
    if(opts.defaultData){
      // console.log('add defaultData-----');
      if(typeof(opts.defaultData)==='string'){
        _data=opts.defaultData;
        _value=opts.defaultData;
        _label=opts.defaultData;
      }else{
        _data=opts.defaultData;
        if(opts.label&&_data[opts.label])_label=_data[opts.label];
        if(opts.value&&_data[opts.value])_value=_data[opts.value];
        else _value=JSON.stringify(_data);
        if(!_label&&(typeof(_value)==='string'))_label=_value;
        else _label=JSON.stringify(_value);
      }
      _option=new Option(_label,_value);
      _option.data=_data;
      selectDom.options.add(_option);
    }

    _label=null;_value=null;
    for (var i = 0; i < dataList.length; i++) {
      _data=dataList[i];
      if(typeof(_data)==='string'){
        _label=_data;_value=_data;
      }else{
        if(opts.label)_label=_data[opts.label];
        if(!opts.value)_value=JSON.stringify(_data);
        else _value=_data[opts.value];
        if(!_label){
          if(typeof(_value)==='string') _label=_value;
          else _label=JSON.stringify(_value);
        }
      }

      _option=new Option(_label,_value);
      _option.data=_data;
      selectDom.options.add(_option);
    }
  };

  /**
   * 进行绑定输入框与具体显示框显示
   * @param  {[Dom]} selectDom    [选择框]
   * @param  {[Dom]} showLabelDom [需要进行渲染的dom]
   * @param  {[Dom]} opts [进行渲染的属性]
   * @return {[type]}              [description]
   */
  InputInteractive.SetShowLabelUpChange=function(selectDom,showLabelDom,opts){
    selectDom=getHTMLElement(selectDom);
    showLabelDom=getHTMLElement(showLabelDom);
    // console.log(selectDom,showLabelDom);
    opts=opts||{};
    if(selectDom&&selectDom.changeFun){
      selectDom.removeEventListener('change',selectDom.changeFun);
    }
    selectDom.changeFun=changeFun;
    selectDom.addEventListener('change',changeFun);
    function changeFun(){
      InputInteractive.UpSelectShowLabel(selectDom,showLabelDom);
    }
    InputInteractive.UpSelectShowLabel(selectDom,showLabelDom);
  };
  /**
   * 把选择框内容显到指定渲染dom上
   * @param  {[Dom]} selectDom    [选择框]
   * @param  {[Dom]} showLabelDom [需要进行渲染的dom]
   * @param  {[Dom]} opts [进行渲染的属性]
   * opts.label
   * @return {[String]}              [渲染的文本]
   */
  InputInteractive.UpSelectShowLabel=function(selectDom,showLabelDom,opts){
    selectDom=getHTMLElement(selectDom);
    showLabelDom=getHTMLElement(showLabelDom);
    if(!selectDom.options||selectDom.options.length<=0)return;
    opts=opts||{};
    var _selectedIndex=selectDom.selectedIndex;
    var _options=selectDom.options[_selectedIndex];
    var _selectObj=selectDom.options[selectDom.selectedIndex];
    var _label;
    if(opts.label&&_selectObj.data&&typeof(_selectObj.data)==='object'){
      _label=_selectObj.data[opts.label];
    }else{
      _label=selectDom.options[selectDom.selectedIndex].text;
    }
    if(_label)$(showLabelDom).html(_label);
    return _label;
  };
  /**
   * 获取当前select Dom 值，
   * @param  {[DOM]} selectDom [select对象]
   * @param  {[String]} value     [获取指定的值]
   * 必须存在data 数据对象，不存在 返回option.value
   * 如果value不传 data存在 返回 data对象
   *
   * @return {[type]}           [description]
   */
  InputInteractive.GetOptionData=function(selectDom,value){
    selectDom=getHTMLElement(selectDom);
    var _index=selectDom.selectedIndex;
    var _option=selectDom.options[_index];
    var _data=_option.data;
    if(!value&&_data)return _data;
    if(_data&&_data&&_data[value]!==undefined)return _data[value];
    return _option.value;
  };
  /**
   * $对象转换成HTMLElement对象
   * @param  {[$ HTMLElement]} dom [一个dom对象]
   * @return {[HTMLElement]}     [dom对象]
   */
  function getHTMLElement(dom){
    if(dom instanceof HTMLElement)return dom;
    else if(!(dom instanceof HTMLElement)&&(dom[0] instanceof HTMLElement))return dom[0];
    else return null;
  }

  return InputInteractive;
}));
<commit_msg>update<commit_after>(function (factory) {
    var root = (typeof self == 'object' && self.self == self && self) ||
        (typeof global == 'object' && global.global == global && global);

    if (typeof define === 'function' && define.amd) {
        define(['exports'], function (exports) {
            module.exports= factory(root, exports);
        });
    } else if (typeof exports !== 'undefined') {
        module.exports=factory(root, exports);
    } else {
         factory(root, {});
    }

}(function (root, modelObj) {
  root.Ds = root.Ds || {};
  root.Ds.gemo = root.Ds.gemo || {};
  root.Ds.gemo.InputInteractive=InputInteractive;
  function InputInteractive(){}
  /**
   * 省市联动二级组件 绑定方法
   * @param  {[String]}   pUrl  [省份请求接口地址]
   * @param  {[String]}   cUrl  [城市请求接口地址]
   * @param  {[DOM]}   domBox  [组件所在dom]
   * @param  {[Object]}   opts  [description]
   * opts.pName  省份的class名称   默认 province
   * opts.cName  城市份的class名称 默认 city
   * opts.replace  是否使用代替的div 或者其他dom来显示 ,默认true
   * 如果replace  为true,  .province+'Label' 与  .city+'Label' 是代替显示的选择结果
   * opts.dataType  ajax 请求方式
   * opts.pDesc   省份进行显示描述字段  默认'province_desc'
   * opts.pID     省份交互请求id字段  默认'province_id'
   * opts.cDesc   省份进行显示描述字段  默认'province_desc'
   * opts.defaultP   省份默认选择空显示项
   * opts.defaultC   城市默认选择空显示项
   * opts.select     城市选择调用
   * @example
   *    html结构可以如下

       <select class="province"></select>

城市

       <select class="city"></select>
       //---------------js
       var _provincesDataUrl=SiteModel.APIer.WebUrl+'/ajax/Ajax.aspx?method=GetProvince';
       var _cityDataUrl=SiteModel.APIer.WebUrl+'/ajax/Ajax.aspx?method=GetCity';
       Ds.gemo.InputInteractive.ProvincesCityLinkComponents(
         _provincesDataUrl,
         _cityDataUrl,
         _Dom,
         {
           pDesc:'province_desc',//省份数据描述字段
           cDesc:'c_desc',//城市数据描述字段
           pID:'province_id'//获取城市list 提交省份字段
         }
       );
   * @return {[type]} [description]
   */

  InputInteractive.ProvincesCityLinkComponents=function(pUrl,cUrl,domBox,opts){
    opts=opts||{};
    var _dataType=opts.dataType!==undefined?opts.dataType:'json';
    if(!opts.defaultP)opts.defaultP='省份';
    if(!opts.defaultC)opts.defaultC='城市';
    var _pName=opts.pName||'province';
    var _cName=opts.cName||'city';
    var _provinceDom=domBox.find('.'+_pName)[0],_cityDom=domBox.find('.'+_cName)[0];
    if(!_provinceDom||!_cityDom){
      console.warn('InputInteractive.ProvincesCityLinkComponents 没有对应的dom对象');
      return;
    }
    var _provinceLabel,_cityLabel;
    var _replace=opts.replace;
    if(opts.replace===undefined)_replace=true;
    if(_replace){
      _provinceLabel=domBox.find('.'+_pName+'Label')[0];
      _cityLabel=domBox.find('.'+_cName+'Label')[0];
      Ds.gemo.InputInteractive.SetShowLabelUpChange(_provinceDom,_provinceLabel);
      Ds.gemo.InputInteractive.SetShowLabelUpChange(_cityDom,_cityLabel);
    }

    var _provinceConfig={
      dataType:_dataType,//ajax 使用 jsonp跨域
      label:opts.pDesc!==undefined?opts.pDesc:'province_desc',//需要在选项里面显示的内容
      defaultData:opts.defaultP!==undefined?opts.defaultP:'省份',
      callback:function(){
        if(_replace)Ds.gemo.InputInteractive.UpSelectShowLabel(_provinceDom,_provinceLabel);
      },
      select:provinceSelectUpCity
    };

    Ds.gemo.InputInteractive.CreatSelectGetUrl(pUrl,{},
      _provinceDom,
      _provinceConfig
    );

    function provinceSelectUpCity(option,index,data){
      console.log('provinceSelectUpCity:',data,opts.defaultP);
      if(data===opts.defaultP)return;
      var _cityConfig={
        dataType:_dataType,//ajax 使用 jsonp跨域
        label:opts.cDesc!==undefined?opts.cDesc:'city_desc',//需要在选项里面显示的内容
        defaultData:opts.defaultC!==undefined?opts.defaultC:'城市',
        callback:function(){
          if(_replace)Ds.gemo.InputInteractive.UpSelectShowLabel(_cityDom,_cityLabel);
        },
        select:function(option,index,data){
          if(opts.select)opts.select(option,index,data);
        }
      };
      var _postData={};
      if(opts.pID)_postData[opts.pID]=data[opts.pID];
      else if(data['province_id'])_postData['province_id']=data['province_id'];
      else _postData.province_id='';
      Ds.gemo.InputInteractive.CreatSelectGetUrl(cUrl,_postData,_cityDom,_cityConfig);
    }

  };
  /**
   * 使用url创建下来选择项目
   * @param  {[type]}   url        [获取内容的url]
   * @param  {[type]}   postData [post数据]
   * @param  {[type]}   selectDom [下拉列表dom对象]
   * @param  {[Object]}   opts  [description]
   * opts.type      ajax请求类型  默认POST
   * opts.dataType      ajax请求类型  默认json
   * opts.defaultData   默认选择值
   * opts.label     label值   需要显示value内的变量名  默认空
   * opts.value     数据值  value如果是object 会转换成json  默认空
   * opts.callback   ajax后callback
   * opts.erorr   ajax erorr后callback
   *
   * @return {[type]}              [description]
   */
  InputInteractive.CreatSelectGetUrl=function(url,postData,selectDom,opts){
    selectDom=getHTMLElement(selectDom);
    opts=opts||{};
    var _type=opts.type!==undefined?opts.type:'POST';
    var _dataType=opts.dataType!==undefined?opts.dataType:'json';
    if(_dataType==='jsonp')_type = 'GET';
    if(opts.debug)console.log('InputInteractive.CreatSelectGetUrl:',url);
    // console.log('InputInteractive.CreatSelectGetUrl:',url,postData,opts);
    $.ajax({
      type:_type,
      url:url,
      data:postData!==undefined?postData:{},
      dataType:opts.dataType||'json',
      success: function(data){
        if(typeof(data)==='string')data=JSON.parse(data);
        if(opts.debug)console.log('CreatSelectGetUrl: ' + url + ':', data);
        // console.log('CreatSelectGetUrl: ' + url + ':', data);
        //如果是公司数据返回结果处理方式
        if (data&&data.IsSuccess&&Number(data.IsSuccess) !== 1) {
          if(opts.erorr)opts.erorr(data.ErrMsg,data);
          return;
        }
        var _dataList=data.data;
        InputInteractive.UpSelectListData(selectDom,_dataList,opts);
        if(opts.callback)opts.callback(data);
        selectOption();
        // console.log(data);
      },
      error: function(xhr, type){
        console.log('Error：',url);
        if(opts.erorr)opts.erorr('网络异常');
      }
    });

    if(selectDom.selectOptionFun)  selectDom.removeEventListener('change',selectDom.selectOptionFun);

    selectDom.selectOptionFun=selectOption;
    selectDom.addEventListener('change',selectOption);
    function  selectOption() {
      var _index=selectDom.selectedIndex;
      var _option=selectDom.options[_index];
      var _data=_option.data;
      if(opts.select)opts.select(_option,_index,_option.data);
    }

  };
  /**
   * 更新选择列表项目
   * @param  {[type]} selectDom [列表数据]
   * @param  {[type]} dataList [列表数据]
   * @param  {[type]} opts      [参数]
   * opts.defaultData   默认选择值
   * @return {[type]}           [description]
   */
  InputInteractive.UpSelectListData=function(selectDom,dataList,opts){
    selectDom=getHTMLElement(selectDom);
    selectDom.options.length=0;
    selectDom.options=[];
    var _option,_data,_label,_value;
    if(opts.defaultData){
      // console.log('add defaultData-----');
      if(typeof(opts.defaultData)==='string'){
        _data=opts.defaultData;
        _value=opts.defaultData;
        _label=opts.defaultData;
      }else{
        _data=opts.defaultData;
        if(opts.label&&_data[opts.label])_label=_data[opts.label];
        if(opts.value&&_data[opts.value])_value=_data[opts.value];
        else _value=JSON.stringify(_data);
        if(!_label&&(typeof(_value)==='string'))_label=_value;
        else _label=JSON.stringify(_value);
      }
      _option=new Option(_label,_value);
      _option.data=_data;
      selectDom.options.add(_option);
    }

    _label=null;_value=null;
    for (var i = 0; i < dataList.length; i++) {
      _data=dataList[i];
      if(typeof(_data)==='string'){
        _label=_data;_value=_data;
      }else{
        if(opts.label)_label=_data[opts.label];
        if(!opts.value)_value=JSON.stringify(_data);
        else _value=_data[opts.value];
        if(!_label){
          if(typeof(_value)==='string') _label=_value;
          else _label=JSON.stringify(_value);
        }
      }

      _option=new Option(_label,_value);
      _option.data=_data;
      selectDom.options.add(_option);
    }
  };

  /**
   * 进行绑定输入框与具体显示框显示
   * @param  {[Dom]} selectDom    [选择框]
   * @param  {[Dom]} showLabelDom [需要进行渲染的dom]
   * @param  {[Dom]} opts [进行渲染的属性]
   * @return {[type]}              [description]
   */
  InputInteractive.SetShowLabelUpChange=function(selectDom,showLabelDom,opts){
    selectDom=getHTMLElement(selectDom);
    showLabelDom=getHTMLElement(showLabelDom);
    // console.log(selectDom,showLabelDom);
    opts=opts||{};
    if(selectDom&&selectDom.changeFun){
      selectDom.removeEventListener('change',selectDom.changeFun);
    }
    selectDom.changeFun=changeFun;
    selectDom.addEventListener('change',changeFun);
    function changeFun(){
      InputInteractive.UpSelectShowLabel(selectDom,showLabelDom);
    }
    InputInteractive.UpSelectShowLabel(selectDom,showLabelDom);
  };
  /**
   * 把选择框内容显到指定渲染dom上
   * @param  {[Dom]} selectDom    [选择框]
   * @param  {[Dom]} showLabelDom [需要进行渲染的dom]
   * @param  {[Dom]} opts [进行渲染的属性]
   * opts.label
   * @return {[String]}              [渲染的文本]
   */
  InputInteractive.UpSelectShowLabel=function(selectDom,showLabelDom,opts){
    selectDom=getHTMLElement(selectDom);
    showLabelDom=getHTMLElement(showLabelDom);
    if(!selectDom.options||selectDom.options.length<=0)return;
    opts=opts||{};
    var _selectedIndex=selectDom.selectedIndex;
    var _options=selectDom.options[_selectedIndex];
    var _selectObj=selectDom.options[selectDom.selectedIndex];
    var _label;
    if(opts.label&&_selectObj.data&&typeof(_selectObj.data)==='object'){
      _label=_selectObj.data[opts.label];
    }else{
      _label=selectDom.options[selectDom.selectedIndex].text;
    }
    if(_label)$(showLabelDom).html(_label);
    return _label;
  };
  /**
   * 获取当前select Dom 值，
   * @param  {[DOM]} selectDom [select对象]
   * @param  {[String]} value     [获取指定的值]
   * 必须存在data 数据对象，不存在 返回option.value
   * 如果value不传 data存在 返回 data对象
   *
   * @return {[type]}           [description]
   */
  InputInteractive.GetOptionData=function(selectDom,value){
    selectDom=getHTMLElement(selectDom);
    var _index=selectDom.selectedIndex;
    var _option=selectDom.options[_index];
    if(!_option) return undefined;
    var _data=_option.data;
    if(!value&&_data)return _data;
    if(_data&&_data&&_data[value]!==undefined)return _data[value];
    return _option.value;
  };
  /**
   * $对象转换成HTMLElement对象
   * @param  {[$ HTMLElement]} dom [一个dom对象]
   * @return {[HTMLElement]}     [dom对象]
   */
  function getHTMLElement(dom){
    if(dom instanceof HTMLElement)return dom;
    else if(!(dom instanceof HTMLElement)&&(dom[0] instanceof HTMLElement))return dom[0];
    else return null;
  }

  return InputInteractive;
}));
<|endoftext|>


<commit_before>/* @flow */

import { NativeModules } from 'react-native';

import {
    CONFERENCE_FAILED,
    CONFERENCE_JOINED,
    CONFERENCE_LEFT,
    CONFERENCE_WILL_JOIN,
    CONFERENCE_WILL_LEAVE,
    JITSI_CONFERENCE_URL_KEY,
    SET_ROOM,
    isRoomValid
} from '../../base/conference';
import { LOAD_CONFIG_ERROR } from '../../base/config';
import { MiddlewareRegistry } from '../../base/redux';
import { toURLString } from '../../base/util';
import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture';

/**
 * Middleware that captures Redux actions and uses the ExternalAPI module to
 * turn them into native events so the application knows about them.
 *
 * @param {Store} store - Redux store.
 * @returns {Function}
 */
MiddlewareRegistry.register(store => next => action => {
    const result = next(action);

    switch (action.type) {
    case CONFERENCE_FAILED: {
        const { error, ...data } = action;

        // XXX Certain CONFERENCE_FAILED errors are recoverable i.e. they have
        // prevented the user from joining a specific conference but the app may
        // be able to eventually join the conference. For example, the app will
        // ask the user for a password upon
        // JitsiConferenceErrors.PASSWORD_REQUIRED and will retry joining the
        // conference afterwards. Such errors are to not reach the native
        // counterpart of the External API (or at least not in the
        // fatality/finality semantics attributed to
        // conferenceFailed:/onConferenceFailed).
        if (!error.recoverable) {
            _sendConferenceEvent(store, /* action */ {
                error: _toErrorString(error),
                ...data
            });
        }
        break;
    }

    case CONFERENCE_JOINED:
    case CONFERENCE_LEFT:
    case CONFERENCE_WILL_JOIN:
    case CONFERENCE_WILL_LEAVE:
        _sendConferenceEvent(store, action);
        break;

    case ENTER_PICTURE_IN_PICTURE:
        _sendEvent(store, _getSymbolDescription(action.type), /* data */ {});
        break;

    case LOAD_CONFIG_ERROR: {
        const { error, locationURL, type } = action;

        _sendEvent(store, _getSymbolDescription(type), /* data */ {
            error: _toErrorString(error),
            url: toURLString(locationURL)
        });
        break;
    }

    case SET_ROOM:
        _maybeTriggerEarlyConferenceWillJoin(store, action);
        break;
    }

    return result;
});

/**
 * Returns a {@code String} representation of a specific error {@code Object}.
 *
 * @param {Error|Object|string} error - The error {@code Object} to return a
 * {@code String} representation of.
 * @returns {string} A {@code String} representation of the specified
 * {@code error}.
 */
function _toErrorString(
        error: Error | { message: ?string, name: ?string } | string) {
    // XXX In lib-jitsi-meet and jitsi-meet we utilize errors in the form of
    // strings, Error instances, and plain objects which resemble Error.
    return (
        error
            ? typeof error === 'string'
                ? error
                : Error.prototype.toString.apply(error)
            : '');
}

/**
 * Gets the description of a specific {@code Symbol}.
 *
 * @param {Symbol} symbol - The {@code Symbol} to retrieve the description of.
 * @private
 * @returns {string} The description of {@code symbol}.
 */
function _getSymbolDescription(symbol: Symbol) {
    let description = symbol.toString();

    if (description.startsWith('Symbol(') && description.endsWith(')')) {
        description = description.slice(7, -1);
    }

    // The polyfill es6-symbol that we use does not appear to comply with the
    // Symbol standard and, merely, adds @@ at the beginning of the description.
    if (description.startsWith('@@')) {
        description = description.slice(2);
    }

    return description;
}

/**
 * If {@link SET_ROOM} action happens for a valid conference room this method
 * will emit an early {@link CONFERENCE_WILL_JOIN} event to let the external API
 * know that a conference is being joined. Before that happens a connection must
 * be created and only then base/conference feature would emit
 * {@link CONFERENCE_WILL_JOIN}. That is fine for the Jitsi Meet app, because
 * that's the a conference instance gets created, but it's too late for
 * the external API to learn that. The latter {@link CONFERENCE_WILL_JOIN} is
 * swallowed in {@link _swallowEvent}.
 *
 * @param {Store} store - The redux store.
 * @param {Action} action - The redux action.
 * @returns {void}
 */
function _maybeTriggerEarlyConferenceWillJoin(store, action) {
    const { locationURL } = store.getState()['features/base/connection'];
    const { room } = action;

    isRoomValid(room) && locationURL && _sendEvent(
        store,
        _getSymbolDescription(CONFERENCE_WILL_JOIN),
        /* data */ {
            url: toURLString(locationURL)
        });
}

/**
 * Sends an event to the native counterpart of the External API for a specific
 * conference-related redux action.
 *
 * @param {Store} store - The redux store.
 * @param {Action} action - The redux action.
 * @returns {void}
 */
function _sendConferenceEvent(
        store: Object,
        action: {
            conference: Object,
            type: Symbol,
            url: ?string
        }) {
    const { conference, type, ...data } = action;

    // For these (redux) actions, conference identifies a JitsiConference
    // instance. The external API cannot transport such an object so we have to
    // transport an "equivalent".
    if (conference) {
        data.url = toURLString(conference[JITSI_CONFERENCE_URL_KEY]);
    }

    _swallowEvent(store, action, data)
        || _sendEvent(store, _getSymbolDescription(type), data);
}

/**
 * Sends a specific event to the native counterpart of the External API. Native
 * apps may listen to such events via the mechanisms provided by the (native)
 * mobile Jitsi Meet SDK.
 *
 * @param {Object} store - The redux store.
 * @param {string} name - The name of the event to send.
 * @param {Object} data - The details/specifics of the event to send determined
 * by/associated with the specified {@code name}.
 * @private
 * @returns {void}
 */
function _sendEvent(
        { getState }: { getState: Function },
        name: string,
        data: Object) {
    // The JavaScript App needs to provide uniquely identifying information to
    // the native ExternalAPI module so that the latter may match the former to
    // the native JitsiMeetView which hosts it.
    const { app } = getState()['features/app'];

    if (app) {
        const { externalAPIScope } = app.props;

        if (externalAPIScope) {
            NativeModules.ExternalAPI.sendEvent(name, data, externalAPIScope);
        }
    }
}

/**
 * Determines whether to not send a {@code CONFERENCE_LEFT} event to the native
 * counterpart of the External API.
 *
 * @param {Object} store - The redux store.
 * @param {Action} action - The redux action which is causing the sending of the
 * event.
 * @param {Object} data - The details/specifics of the event to send determined
 * by/associated with the specified {@code action}.
 * @returns {boolean} If the specified event is to not be sent, {@code true};
 * otherwise, {@code false}.
 */
function _swallowConferenceLeft({ getState }, action, { url }) {
    // XXX Internally, we work with JitsiConference instances. Externally
    // though, we deal with URL strings. The relation between the two is many to
    // one so it's technically and practically possible (by externally loading
    // the same URL string multiple times) to try to send CONFERENCE_LEFT
    // externally for a URL string which identifies a JitsiConference that the
    // app is internally legitimately working with.

    if (url) {
        const stateFeaturesBaseConference
            = getState()['features/base/conference'];

        // eslint-disable-next-line guard-for-in
        for (const p in stateFeaturesBaseConference) {
            const v = stateFeaturesBaseConference[p];

            // Does the value of the base/conference's property look like a
            // JitsiConference?
            if (v && typeof v === 'object') {
                const vURL = v[JITSI_CONFERENCE_URL_KEY];

                if (vURL && vURL.toString() === url) {
                    return true;
                }
            }
        }
    }

    return false;
}

/**
 * Determines whether to not send a specific event to the native counterpart of
 * the External API.
 *
 * @param {Object} store - The redux store.
 * @param {Action} action - The redux action which is causing the sending of the
 * event.
 * @param {Object} data - The details/specifics of the event to send determined
 * by/associated with the specified {@code action}.
 * @returns {boolean} If the specified event is to not be sent, {@code true};
 * otherwise, {@code false}.
 */
function _swallowEvent(store, action, data) {
    switch (action.type) {
    case CONFERENCE_LEFT:
        return _swallowConferenceLeft(store, action, data);
    case CONFERENCE_WILL_JOIN:
        // CONFERENCE_WILL_JOIN is dispatched to the external API on SET_ROOM,
        // before the connection is created, so we need to swallow the original
        // one emitted by base/conference.
        return true;

    default:
        return false;
    }
}
<commit_msg>ref(external API): emit CONFERENCE_FAILED on CONNECTION_FAILED<commit_after>/* @flow */

import { NativeModules } from 'react-native';

import {
    CONFERENCE_FAILED,
    CONFERENCE_JOINED,
    CONFERENCE_LEFT,
    CONFERENCE_WILL_JOIN,
    CONFERENCE_WILL_LEAVE,
    JITSI_CONFERENCE_URL_KEY,
    SET_ROOM,
    isRoomValid
} from '../../base/conference';
import { LOAD_CONFIG_ERROR } from '../../base/config';
import { CONNECTION_FAILED } from '../../base/connection';
import { MiddlewareRegistry } from '../../base/redux';
import { toURLString } from '../../base/util';
import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture';

/**
 * Middleware that captures Redux actions and uses the ExternalAPI module to
 * turn them into native events so the application knows about them.
 *
 * @param {Store} store - Redux store.
 * @returns {Function}
 */
MiddlewareRegistry.register(store => next => action => {
    const result = next(action);

    switch (action.type) {
    case CONFERENCE_FAILED: {
        const { error, ...data } = action;

        // XXX Certain CONFERENCE_FAILED errors are recoverable i.e. they have
        // prevented the user from joining a specific conference but the app may
        // be able to eventually join the conference. For example, the app will
        // ask the user for a password upon
        // JitsiConferenceErrors.PASSWORD_REQUIRED and will retry joining the
        // conference afterwards. Such errors are to not reach the native
        // counterpart of the External API (or at least not in the
        // fatality/finality semantics attributed to
        // conferenceFailed:/onConferenceFailed).
        if (!error.recoverable) {
            _sendConferenceEvent(store, /* action */ {
                error: _toErrorString(error),
                ...data
            });
        }
        break;
    }

    case CONFERENCE_JOINED:
    case CONFERENCE_LEFT:
    case CONFERENCE_WILL_JOIN:
    case CONFERENCE_WILL_LEAVE:
        _sendConferenceEvent(store, action);
        break;

    case CONNECTION_FAILED:
        _sendConferenceFailedOnConnectionError(store, action);
        break;

    case ENTER_PICTURE_IN_PICTURE:
        _sendEvent(store, _getSymbolDescription(action.type), /* data */ {});
        break;

    case LOAD_CONFIG_ERROR: {
        const { error, locationURL, type } = action;

        _sendEvent(store, _getSymbolDescription(type), /* data */ {
            error: _toErrorString(error),
            url: toURLString(locationURL)
        });
        break;
    }

    case SET_ROOM:
        _maybeTriggerEarlyConferenceWillJoin(store, action);
        break;
    }

    return result;
});

/**
 * Returns a {@code String} representation of a specific error {@code Object}.
 *
 * @param {Error|Object|string} error - The error {@code Object} to return a
 * {@code String} representation of.
 * @returns {string} A {@code String} representation of the specified
 * {@code error}.
 */
function _toErrorString(
        error: Error | { message: ?string, name: ?string } | string) {
    // XXX In lib-jitsi-meet and jitsi-meet we utilize errors in the form of
    // strings, Error instances, and plain objects which resemble Error.
    return (
        error
            ? typeof error === 'string'
                ? error
                : Error.prototype.toString.apply(error)
            : '');
}

/**
 * Gets the description of a specific {@code Symbol}.
 *
 * @param {Symbol} symbol - The {@code Symbol} to retrieve the description of.
 * @private
 * @returns {string} The description of {@code symbol}.
 */
function _getSymbolDescription(symbol: Symbol) {
    let description = symbol.toString();

    if (description.startsWith('Symbol(') && description.endsWith(')')) {
        description = description.slice(7, -1);
    }

    // The polyfill es6-symbol that we use does not appear to comply with the
    // Symbol standard and, merely, adds @@ at the beginning of the description.
    if (description.startsWith('@@')) {
        description = description.slice(2);
    }

    return description;
}

/**
 * If {@link SET_ROOM} action happens for a valid conference room this method
 * will emit an early {@link CONFERENCE_WILL_JOIN} event to let the external API
 * know that a conference is being joined. Before that happens a connection must
 * be created and only then base/conference feature would emit
 * {@link CONFERENCE_WILL_JOIN}. That is fine for the Jitsi Meet app, because
 * that's the a conference instance gets created, but it's too late for
 * the external API to learn that. The latter {@link CONFERENCE_WILL_JOIN} is
 * swallowed in {@link _swallowEvent}.
 *
 * @param {Store} store - The redux store.
 * @param {Action} action - The redux action.
 * @returns {void}
 */
function _maybeTriggerEarlyConferenceWillJoin(store, action) {
    const { locationURL } = store.getState()['features/base/connection'];
    const { room } = action;

    isRoomValid(room) && locationURL && _sendEvent(
        store,
        _getSymbolDescription(CONFERENCE_WILL_JOIN),
        /* data */ {
            url: toURLString(locationURL)
        });
}

/**
 * Sends an event to the native counterpart of the External API for a specific
 * conference-related redux action.
 *
 * @param {Store} store - The redux store.
 * @param {Action} action - The redux action.
 * @returns {void}
 */
function _sendConferenceEvent(
        store: Object,
        action: {
            conference: Object,
            type: Symbol,
            url: ?string
        }) {
    const { conference, type, ...data } = action;

    // For these (redux) actions, conference identifies a JitsiConference
    // instance. The external API cannot transport such an object so we have to
    // transport an "equivalent".
    if (conference) {
        data.url = toURLString(conference[JITSI_CONFERENCE_URL_KEY]);
    }

    _swallowEvent(store, action, data)
        || _sendEvent(store, _getSymbolDescription(type), data);
}

/**
 * Sends {@link CONFERENCE_FAILED} event when the {@link CONNECTION_FAILED}
 * occurs. Otherwise the external API will not emit such event, because at this
 * point conference has not been created yet and the base/conference feature
 * will not emit it.
 *
 * @param {Store} store - The redux store.
 * @param {Action} action - The redux action.
 * @returns {void}
 */
function _sendConferenceFailedOnConnectionError(store, action) {
    const { locationURL } = store.getState()['features/base/connection'];

    locationURL && _sendEvent(
        store,
        _getSymbolDescription(CONFERENCE_FAILED),
        /* data */ {
            url: toURLString(locationURL),
            error: action.error.name
        });
}

/**
 * Sends a specific event to the native counterpart of the External API. Native
 * apps may listen to such events via the mechanisms provided by the (native)
 * mobile Jitsi Meet SDK.
 *
 * @param {Object} store - The redux store.
 * @param {string} name - The name of the event to send.
 * @param {Object} data - The details/specifics of the event to send determined
 * by/associated with the specified {@code name}.
 * @private
 * @returns {void}
 */
function _sendEvent(
        { getState }: { getState: Function },
        name: string,
        data: Object) {
    // The JavaScript App needs to provide uniquely identifying information to
    // the native ExternalAPI module so that the latter may match the former to
    // the native JitsiMeetView which hosts it.
    const { app } = getState()['features/app'];

    if (app) {
        const { externalAPIScope } = app.props;

        if (externalAPIScope) {
            NativeModules.ExternalAPI.sendEvent(name, data, externalAPIScope);
        }
    }
}

/**
 * Determines whether to not send a {@code CONFERENCE_LEFT} event to the native
 * counterpart of the External API.
 *
 * @param {Object} store - The redux store.
 * @param {Action} action - The redux action which is causing the sending of the
 * event.
 * @param {Object} data - The details/specifics of the event to send determined
 * by/associated with the specified {@code action}.
 * @returns {boolean} If the specified event is to not be sent, {@code true};
 * otherwise, {@code false}.
 */
function _swallowConferenceLeft({ getState }, action, { url }) {
    // XXX Internally, we work with JitsiConference instances. Externally
    // though, we deal with URL strings. The relation between the two is many to
    // one so it's technically and practically possible (by externally loading
    // the same URL string multiple times) to try to send CONFERENCE_LEFT
    // externally for a URL string which identifies a JitsiConference that the
    // app is internally legitimately working with.

    if (url) {
        const stateFeaturesBaseConference
            = getState()['features/base/conference'];

        // eslint-disable-next-line guard-for-in
        for (const p in stateFeaturesBaseConference) {
            const v = stateFeaturesBaseConference[p];

            // Does the value of the base/conference's property look like a
            // JitsiConference?
            if (v && typeof v === 'object') {
                const vURL = v[JITSI_CONFERENCE_URL_KEY];

                if (vURL && vURL.toString() === url) {
                    return true;
                }
            }
        }
    }

    return false;
}

/**
 * Determines whether to not send a specific event to the native counterpart of
 * the External API.
 *
 * @param {Object} store - The redux store.
 * @param {Action} action - The redux action which is causing the sending of the
 * event.
 * @param {Object} data - The details/specifics of the event to send determined
 * by/associated with the specified {@code action}.
 * @returns {boolean} If the specified event is to not be sent, {@code true};
 * otherwise, {@code false}.
 */
function _swallowEvent(store, action, data) {
    switch (action.type) {
    case CONFERENCE_LEFT:
        return _swallowConferenceLeft(store, action, data);
    case CONFERENCE_WILL_JOIN:
        // CONFERENCE_WILL_JOIN is dispatched to the external API on SET_ROOM,
        // before the connection is created, so we need to swallow the original
        // one emitted by base/conference.
        return true;

    default:
        return false;
    }
}
<|endoftext|>