<commit_before>'use strict';

var React = require('react');
var ReactDOM = require('react-dom');
var QuillMixin = require('./mixin');
var find = require('lodash/find');
var isEqual = require('lodash/isEqual');
var T = React.PropTypes;

var QuillComponent = React.createClass({

	displayName: 'Quill',

	mixins: [ QuillMixin ],

	propTypes: {
		id: T.string,
		className: T.string,
		theme: T.string,
		style: T.object,
		readOnly: T.bool,
		value: T.string,
		defaultValue: T.string,
		placeholder: T.string,
		bounds: T.oneOfType([T.string, T.element]),
		onKeyPress: T.func,
		onKeyDown: T.func,
		onKeyUp: T.func,
		onChange: T.func,
		onChangeSelection: T.func,

		modules: function(props) {
			var isNotObject = T.object.apply(this, arguments);
			if (isNotObject) return isNotObject;

			if (
				props.modules &&
				props.modules.toolbar &&
				props.modules.toolbar[0] &&
				props.modules.toolbar[0].type
			) return new Error(
				'Since v1.0.0, React Quill will not create a custom toolbar for you ' +
				'anymore. Create a toolbar explictly, or let Quill create one. ' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		},

		toolbar: function(props) {
			if ('toolbar' in props) return new Error(
				'The `toolbar` prop has been deprecated. Use `modules.toolbar` instead. ' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		},

		formats: function(props) {
			var isNotArrayOfString = T.arrayOf(T.string).apply(this, arguments);

			if (isNotArrayOfString) return new Error(
				'You cannot specify custom `formats` anymore. Use Parchment instead.  ' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		},

		styles: function(props) {
			if ('styles' in props) return new Error(
				'The `styles` prop has been deprecated. Use custom stylesheets instead. ' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		},

		pollInterval: function(props) {
			if ('pollInterval' in props) return new Error(
				'The `pollInterval` property does not have any effect anymore. ' +
				'You can safely remove it from your props.' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		}
	},

	/*
	Changing one of these props should cause a re-render.
	*/
	dirtyProps: [
		'id',
		'className',
		'style',
		'modules',
		'formats',
		'bounds',
		'theme',
	],

	getDefaultProps: function() {
		return {
			className: '',
			theme: 'snow',
			modules: {},
		};
	},

	/*
	We consider the component to be controlled if
	whenever `value` is bein sent in props.
	*/
	isControlled: function() {
		return 'value' in this.props;
	},

	getInitialState: function() {
		return {
			value: this.isControlled()
				? this.props.value
				: this.props.defaultValue
		};
	},

	componentWillReceiveProps: function(nextProps) {
		var editor = this.state.editor;
		// If the component is unmounted and mounted too quickly
		// an error is thrown in setEditorContents since editor is
		// still undefined. Must check if editor is undefined
		// before performing this call.
		if (editor) {
			// Update only if we've been passed a new `value`.
			// This leaves components using `defaultValue` alone.
			if ('value' in nextProps) {
				// NOTE: Seeing that Quill is missing a way to prevent
				//       edits, we have to settle for a hybrid between
				//       controlled and uncontrolled mode. We can't prevent
				//       the change, but we'll still override content
				//       whenever `value` differs from current state.
				if (nextProps.value !== this.getEditorContents()) {
					this.setEditorContents(editor, nextProps.value);
				}
			}
			// We can update readOnly state in-place.
			if ('readOnly' in nextProps) {
				if (nextProps.readOnly !== this.props.readOnly) {
					this.setEditorReadOnly(editor, nextProps.readOnly);
				}
			}
		}
	},

	componentDidMount: function() {
		var editor = this.createEditor(
			this.getEditorElement(),
			this.getEditorConfig()
		);
		this.setState({ editor:editor });
	},

	componentWillUnmount: function() {
		// NOTE: Don't set the state to null here
		//       as it would generate a loop.
	},

	shouldComponentUpdate: function(nextProps, nextState) {
		// Check if one of the changes should trigger a re-render.
		for (var i=0; i<this.dirtyProps.length; i++) {
			var prop = this.dirtyProps[i];
			if (!isEqual(nextProps[prop], this.props[prop])) {
				return true;
			}
		}
		// Never re-render otherwise.
		return false;
	},

	/*
	If for whatever reason we are rendering again,
	we should tear down the editor and bring it up
	again.
	*/
	componentWillUpdate: function() {
		this.componentWillUnmount();
	},

	componentDidUpdate: function() {
		this.componentDidMount();
	},

	getEditorConfig: function() {
		return {
			bounds:       this.props.bounds,
			formats:      this.props.formats,
			modules:      this.props.modules,
			placeholder:  this.props.placeholder,
			readOnly:     this.props.readOnly,
			theme:        this.props.theme,
		};
	},

	getEditor: function() {
		return this.state.editor;
	},

	getEditorElement: function() {
		return ReactDOM.findDOMNode(this.refs.editor);
	},

	getEditorContents: function() {
		return this.state.value;
	},

	getEditorSelection: function() {
		return this.state.selection;
	},

	/*
	Renders an editor element, unless it has been provided one to clone.
	*/
	renderContents: function() {
		var contents = [];
		var children = React.Children.map(
			this.props.children,
			function(c) { return React.cloneElement(c, {ref: c.ref}); }
		);

		var editor = find(children, function(child) {
			return child.ref === 'editor';
		});
		contents.push(editor || React.DOM.div({
			key: 'editor-' + Math.random(),
			ref: 'editor',
			className: 'quill-contents',
			dangerouslySetInnerHTML: { __html:this.getEditorContents() }
		}));

		return contents;
	},

	render: function() {
		return React.DOM.div({
			id: this.props.id,
			style: this.props.style,
			className: ['quill'].concat(this.props.className).join(' '),
			onKeyPress: this.props.onKeyPress,
			onKeyDown: this.props.onKeyDown,
			onKeyUp: this.props.onKeyUp },
			this.renderContents()
		);
	},

	onEditorChange: function(value, delta, source, editor) {
		if (value !== this.getEditorContents()) {
			this.setState({ value: value });
			if (this.props.onChange) {
				this.props.onChange(value, delta, source, editor);
			}
		}
	},

	onEditorChangeSelection: function(range, source, editor) {
		var s = this.getEditorSelection() || {};
		var r = range || {};
		if (r.length !== s.length || r.index !== s.index) {
			this.setState({ selection: range });
			if (this.props.onChangeSelection) {
				this.props.onChangeSelection(range, source, editor);
			}
		}
	},

	focus: function() {
		this.state.editor.focus();
	},

	blur: function() {
		this.setEditorSelection(this.state.editor, null);
	}

});

module.exports = QuillComponent;
<commit_msg>Simpler dirtyProp rerendering check<commit_after>'use strict';

var React = require('react');
var ReactDOM = require('react-dom');
var QuillMixin = require('./mixin');
var find = require('lodash/find');
var some = require('lodash/some');
var isEqual = require('lodash/isEqual');
var T = React.PropTypes;

var QuillComponent = React.createClass({

	displayName: 'Quill',

	mixins: [ QuillMixin ],

	propTypes: {
		id: T.string,
		className: T.string,
		theme: T.string,
		style: T.object,
		readOnly: T.bool,
		value: T.string,
		defaultValue: T.string,
		placeholder: T.string,
		bounds: T.oneOfType([T.string, T.element]),
		onKeyPress: T.func,
		onKeyDown: T.func,
		onKeyUp: T.func,
		onChange: T.func,
		onChangeSelection: T.func,

		modules: function(props) {
			var isNotObject = T.object.apply(this, arguments);
			if (isNotObject) return isNotObject;

			if (
				props.modules &&
				props.modules.toolbar &&
				props.modules.toolbar[0] &&
				props.modules.toolbar[0].type
			) return new Error(
				'Since v1.0.0, React Quill will not create a custom toolbar for you ' +
				'anymore. Create a toolbar explictly, or let Quill create one. ' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		},

		toolbar: function(props) {
			if ('toolbar' in props) return new Error(
				'The `toolbar` prop has been deprecated. Use `modules.toolbar` instead. ' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		},

		formats: function(props) {
			var isNotArrayOfString = T.arrayOf(T.string).apply(this, arguments);

			if (isNotArrayOfString) return new Error(
				'You cannot specify custom `formats` anymore. Use Parchment instead.  ' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		},

		styles: function(props) {
			if ('styles' in props) return new Error(
				'The `styles` prop has been deprecated. Use custom stylesheets instead. ' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		},

		pollInterval: function(props) {
			if ('pollInterval' in props) return new Error(
				'The `pollInterval` property does not have any effect anymore. ' +
				'You can safely remove it from your props.' +
				'See: https://github.com/zenoamaro/react-quill#upgrading-to-react-quill-v1-0-0'
			);
		}
	},

	/*
	Changing one of these props should cause a re-render.
	*/
	dirtyProps: [
		'id',
		'className',
		'style',
		'modules',
		'formats',
		'bounds',
		'theme',
	],

	getDefaultProps: function() {
		return {
			className: '',
			theme: 'snow',
			modules: {},
		};
	},

	/*
	We consider the component to be controlled if
	whenever `value` is bein sent in props.
	*/
	isControlled: function() {
		return 'value' in this.props;
	},

	getInitialState: function() {
		return {
			value: this.isControlled()
				? this.props.value
				: this.props.defaultValue
		};
	},

	componentWillReceiveProps: function(nextProps) {
		var editor = this.state.editor;
		// If the component is unmounted and mounted too quickly
		// an error is thrown in setEditorContents since editor is
		// still undefined. Must check if editor is undefined
		// before performing this call.
		if (editor) {
			// Update only if we've been passed a new `value`.
			// This leaves components using `defaultValue` alone.
			if ('value' in nextProps) {
				// NOTE: Seeing that Quill is missing a way to prevent
				//       edits, we have to settle for a hybrid between
				//       controlled and uncontrolled mode. We can't prevent
				//       the change, but we'll still override content
				//       whenever `value` differs from current state.
				if (nextProps.value !== this.getEditorContents()) {
					this.setEditorContents(editor, nextProps.value);
				}
			}
			// We can update readOnly state in-place.
			if ('readOnly' in nextProps) {
				if (nextProps.readOnly !== this.props.readOnly) {
					this.setEditorReadOnly(editor, nextProps.readOnly);
				}
			}
		}
	},

	componentDidMount: function() {
		var editor = this.createEditor(
			this.getEditorElement(),
			this.getEditorConfig()
		);
		this.setState({ editor:editor });
	},

	componentWillUnmount: function() {
		// NOTE: Don't set the state to null here
		//       as it would generate a loop.
	},

	shouldComponentUpdate: function(nextProps, nextState) {
		// Rerender whenever a "dirtyProp" changes
		var props = this.props;
		return some(this.dirtyProps, function(prop) {
			return !isEqual(nextProps[prop], props[prop]);
		});
	},

	/*
	If for whatever reason we are rendering again,
	we should tear down the editor and bring it up
	again.
	*/
	componentWillUpdate: function() {
		this.componentWillUnmount();
	},

	componentDidUpdate: function() {
		this.componentDidMount();
	},

	getEditorConfig: function() {
		return {
			bounds:       this.props.bounds,
			formats:      this.props.formats,
			modules:      this.props.modules,
			placeholder:  this.props.placeholder,
			readOnly:     this.props.readOnly,
			theme:        this.props.theme,
		};
	},

	getEditor: function() {
		return this.state.editor;
	},

	getEditorElement: function() {
		return ReactDOM.findDOMNode(this.refs.editor);
	},

	getEditorContents: function() {
		return this.state.value;
	},

	getEditorSelection: function() {
		return this.state.selection;
	},

	/*
	Renders an editor element, unless it has been provided one to clone.
	*/
	renderContents: function() {
		var contents = [];
		var children = React.Children.map(
			this.props.children,
			function(c) { return React.cloneElement(c, {ref: c.ref}); }
		);

		var editor = find(children, function(child) {
			return child.ref === 'editor';
		});
		contents.push(editor || React.DOM.div({
			key: 'editor-' + Math.random(),
			ref: 'editor',
			className: 'quill-contents',
			dangerouslySetInnerHTML: { __html:this.getEditorContents() }
		}));

		return contents;
	},

	render: function() {
		return React.DOM.div({
			id: this.props.id,
			style: this.props.style,
			className: ['quill'].concat(this.props.className).join(' '),
			onKeyPress: this.props.onKeyPress,
			onKeyDown: this.props.onKeyDown,
			onKeyUp: this.props.onKeyUp },
			this.renderContents()
		);
	},

	onEditorChange: function(value, delta, source, editor) {
		if (value !== this.getEditorContents()) {
			this.setState({ value: value });
			if (this.props.onChange) {
				this.props.onChange(value, delta, source, editor);
			}
		}
	},

	onEditorChangeSelection: function(range, source, editor) {
		var s = this.getEditorSelection() || {};
		var r = range || {};
		if (r.length !== s.length || r.index !== s.index) {
			this.setState({ selection: range });
			if (this.props.onChangeSelection) {
				this.props.onChangeSelection(range, source, editor);
			}
		}
	},

	focus: function() {
		this.state.editor.focus();
	},

	blur: function() {
		this.setEditorSelection(this.state.editor, null);
	}

});

module.exports = QuillComponent;
<|endoftext|>


<commit_before>import Stream from "./stream";

/**
 Check whether an object is a stream or not

 @private
 @function isStream
 @param {Object|Stream} object object to check whether it is a stream
 @return {Boolean} `true` if the object is a stream, `false` otherwise
*/
export function isStream(object) {
  return object && object.isStream;
}

/**
 A method of subscribing to a stream which is safe for use with a non-stream
 object. If a non-stream object is passed, the function does nothing.

 @private
 @function subscribe
 @param {Object|Stream} object object or stream to potentially subscribe to
 @param {Function} callback function to run when stream value changes
 @param {Object} [context] the callback will be executed with this context if it
                           is provided
 */
export function subscribe(object, callback, context) {
  if (object && object.isStream) {
    object.subscribe(callback, context);
  }
}

/**
 A method of unsubscribing from a stream which is safe for use with a non-stream
 object. If a non-stream object is passed, the function does nothing.

 @private
 @function unsubscribe
 @param {Object|Stream} object object or stream to potentially unsubscribe from
 @param {Function} callback function originally passed to `subscribe()`
 @param {Object} [context] object originally passed to `subscribe()`
 */
export function unsubscribe(object, callback, context) {
  if (object && object.isStream) {
    object.unsubscribe(callback, context);
  }
}

/**
 Retrieve the value of a stream, or in the case a non-stream object is passed,
 return the object itself.

 @private
 @function read
 @param {Object|Stream} object object to return the value of
 @return the stream's current value, or the non-stream object itself
 */
export function read(object) {
  if (object && object.isStream) {
    return object.value();
  } else {
    return object;
  }
}

/**
 Map an array, replacing any streams with their values.

 @private
 @function readArray
 @param {Array} array The array to read values from
 @return {Array} a new array of the same length with the values of non-stream
                 objects mapped from their original positions untouched, and
                 the values of stream objects retaining their original position
                 and replaced with the stream's current value.
 */
export function readArray(array) {
  var length = array.length;
  var ret = new Array(length);
  for (var i = 0; i < length; i++) {
    ret[i] = read(array[i]);
  }
  return ret;
}

/**
 Map a hash, replacing any stream property values with the current value of that
 stream.

 @private
 @function readHash
 @param {Object} object The hash to read keys and values from
 @return {Object} a new object with the same keys as the passed object. The
                  property values in the new object are the original values in
                  the case of non-stream objects, and the streams' current
                  values in the case of stream objects.
 */
export function readHash(object) {
  var ret = {};
  for (var key in object) {
    ret[key] = read(object[key]);
  }
  return ret;
}

/**
 Check whether an array contains any stream values

 @private
 @function scanArray
 @param {Array} array array given to a handlebars helper
 @return {Boolean} `true` if the array contains a stream/bound value, `false`
                   otherwise
*/
export function scanArray(array) {
  var length = array.length;
  var containsStream = false;

  for (var i = 0; i < length; i++) {
    if (isStream(array[i])) {
      containsStream = true;
      break;
    }
  }

  return containsStream;
}

/**
 Check whether a hash has any stream property values

 @private
 @function scanHash
 @param {Object} hash "hash" argument given to a handlebars helper
 @return {Boolean} `true` if the object contains a stream/bound value, `false`
                   otherwise
 */
export function scanHash(hash) {
  var containsStream = false;

  for (var prop in hash) {
    if (isStream(hash[prop])) {
      containsStream = true;
      break;
    }
  }

  return containsStream;
}

/**
 Join an array, with any streams replaced by their current values

 @private
 @function concat
 @param {Array} array An array containing zero or more stream objects and
                      zero or more non-stream objects
 @param {String} separator string to be used to join array elements
 @return {String} String with array elements concatenated and joined by the
                  provided separator, and any stream array members having been
                  replaced by the current value of the stream
 */
export function concat(array, separator) {
  // TODO: Create subclass ConcatStream < Stream. Defer
  // subscribing to streams until the value() is called.
  var hasStream = scanArray(array);
  if (hasStream) {
    var i, l;
    var stream = new Stream(function() {
      return readArray(array).join(separator);
    });

    for (i = 0, l=array.length; i < l; i++) {
      subscribe(array[i], stream.notify, stream);
    }

    return stream;
  } else {
    return array.join(separator);
  }
}

/**
 Generate a new stream by providing a source stream and a function that can
 be used to transform the stream's value. In the case of a non-stream object,
 returns the result of the function.

 The value to transform would typically be available to the function you pass
 to `chain()` via scope. For example:

 ```javascript
     var source = ...;  // stream returning a number
                            // or a numeric (non-stream) object
     var result = chain(source, function(){
       var currentValue = read(source);
       return currentValue + 1;
     });
 ```

 In the example, result is a stream if source is a stream, or a number of
 source was numeric.

 @private
 @function chain
 @param {Object|Stream} array An array containing zero or more stream objects
                              and zero or more non-stream objects
 @param {Function} fn function becoming the value function of a new stream,
                      or in the case of a non-stream object, executed once
 @return {Object|Stream} String with array elements concatenated and joined by
                         the provided separator, and any stream array members
                         having been replaced by the current value of the
                         stream
 */
export function chain(value, fn) {
  if (isStream(value)) {
    var stream = new Stream(fn);
    subscribe(value, stream.notify, stream);
    return stream;
  } else {
    return fn();
  }
}
<commit_msg>[DOC] Stream util doc fixup<commit_after>import Stream from "./stream";

/**
 Check whether an object is a stream or not

 @private
 @function isStream
 @param {Object|Stream} object object to check whether it is a stream
 @return {Boolean} `true` if the object is a stream, `false` otherwise
*/
export function isStream(object) {
  return object && object.isStream;
}

/**
 A method of subscribing to a stream which is safe for use with a non-stream
 object. If a non-stream object is passed, the function does nothing.

 @private
 @function subscribe
 @param {Object|Stream} object object or stream to potentially subscribe to
 @param {Function} callback function to run when stream value changes
 @param {Object} [context] the callback will be executed with this context if it
                           is provided
 */
export function subscribe(object, callback, context) {
  if (object && object.isStream) {
    object.subscribe(callback, context);
  }
}

/**
 A method of unsubscribing from a stream which is safe for use with a non-stream
 object. If a non-stream object is passed, the function does nothing.

 @private
 @function unsubscribe
 @param {Object|Stream} object object or stream to potentially unsubscribe from
 @param {Function} callback function originally passed to `subscribe()`
 @param {Object} [context] object originally passed to `subscribe()`
 */
export function unsubscribe(object, callback, context) {
  if (object && object.isStream) {
    object.unsubscribe(callback, context);
  }
}

/**
 Retrieve the value of a stream, or in the case a non-stream object is passed,
 return the object itself.

 @private
 @function read
 @param {Object|Stream} object object to return the value of
 @return the stream's current value, or the non-stream object itself
 */
export function read(object) {
  if (object && object.isStream) {
    return object.value();
  } else {
    return object;
  }
}

/**
 Map an array, replacing any streams with their values.

 @private
 @function readArray
 @param {Array} array The array to read values from
 @return {Array} a new array of the same length with the values of non-stream
                 objects mapped from their original positions untouched, and
                 the values of stream objects retaining their original position
                 and replaced with the stream's current value.
 */
export function readArray(array) {
  var length = array.length;
  var ret = new Array(length);
  for (var i = 0; i < length; i++) {
    ret[i] = read(array[i]);
  }
  return ret;
}

/**
 Map a hash, replacing any stream property values with the current value of that
 stream.

 @private
 @function readHash
 @param {Object} object The hash to read keys and values from
 @return {Object} a new object with the same keys as the passed object. The
                  property values in the new object are the original values in
                  the case of non-stream objects, and the streams' current
                  values in the case of stream objects.
 */
export function readHash(object) {
  var ret = {};
  for (var key in object) {
    ret[key] = read(object[key]);
  }
  return ret;
}

/**
 Check whether an array contains any stream values

 @private
 @function scanArray
 @param {Array} array array given to a handlebars helper
 @return {Boolean} `true` if the array contains a stream/bound value, `false`
                   otherwise
*/
export function scanArray(array) {
  var length = array.length;
  var containsStream = false;

  for (var i = 0; i < length; i++) {
    if (isStream(array[i])) {
      containsStream = true;
      break;
    }
  }

  return containsStream;
}

/**
 Check whether a hash has any stream property values

 @private
 @function scanHash
 @param {Object} hash "hash" argument given to a handlebars helper
 @return {Boolean} `true` if the object contains a stream/bound value, `false`
                   otherwise
 */
export function scanHash(hash) {
  var containsStream = false;

  for (var prop in hash) {
    if (isStream(hash[prop])) {
      containsStream = true;
      break;
    }
  }

  return containsStream;
}

/**
 Join an array, with any streams replaced by their current values

 @private
 @function concat
 @param {Array} array An array containing zero or more stream objects and
                      zero or more non-stream objects
 @param {String} separator string to be used to join array elements
 @return {String} String with array elements concatenated and joined by the
                  provided separator, and any stream array members having been
                  replaced by the current value of the stream
 */
export function concat(array, separator) {
  // TODO: Create subclass ConcatStream < Stream. Defer
  // subscribing to streams until the value() is called.
  var hasStream = scanArray(array);
  if (hasStream) {
    var i, l;
    var stream = new Stream(function() {
      return readArray(array).join(separator);
    });

    for (i = 0, l=array.length; i < l; i++) {
      subscribe(array[i], stream.notify, stream);
    }

    return stream;
  } else {
    return array.join(separator);
  }
}

/**
 Generate a new stream by providing a source stream and a function that can
 be used to transform the stream's value. In the case of a non-stream object,
 returns the result of the function.

 The value to transform would typically be available to the function you pass
 to `chain()` via scope. For example:

 ```javascript
     var source = ...;  // stream returning a number
                            // or a numeric (non-stream) object
     var result = chain(source, function(){
       var currentValue = read(source);
       return currentValue + 1;
     });
 ```

 In the example, result is a stream if source is a stream, or a number of
 source was numeric.

 @private
 @function chain
 @param {Object|Stream} value A stream or non-stream object
 @param {Function} fn function to be run when the stream value changes, or to
                      be run once in the case of a non-stream object
 @return {Object|Stream} In the case of a stream `value` parameter, a new
                         stream that will be updated with the return value of
                         the provided function `fn`. In the case of a
                         non-stream object, the return value of the provided
                         function `fn`.
 */
export function chain(value, fn) {
  if (isStream(value)) {
    var stream = new Stream(fn);
    subscribe(value, stream.notify, stream);
    return stream;
  } else {
    return fn();
  }
}
<|endoftext|>


<commit_before>var configurator = require('./configurator');
var Detector = window.Detector = require("detector-webgl");
var THREE = window.THREE = require("three");
var collada = require('three-loaders-collada')(THREE);
var animation = require('./vendors/loaders/collada/Animation')(THREE);
var KeyFrameAnimation = require('./vendors/loaders/collada/KeyFrameAnimation')(THREE);
var W = window.innerWidth;
var H = window.innerHeight;

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('webgl2');
var isWebGL2 = !!ctx;

delete canvas;

var HoloWeb = function (selector, config) {
    this.selector = selector || window.document.body;
    this.config = config;
    if (!Detector)
        return console.error("your browser does not support WebGL");
    var renderer;
    var windowWidth, windowHeight;
    var views = configurator(this.config, {H: H, W: W});
    var scene = new THREE.Scene();
    this.scene = scene;
    init(this.selector);
    animate();

    this.add = function(mesh){
        return this.scene.add(mesh);
    }

    function init(container) {
        for (var i = 0; i < views.length; ++i) {
            var view = views[i];
            camera = new THREE.PerspectiveCamera(view.fov, window.innerWidth / window.innerHeight, 1, 10000);
            camera.position.x = view.eye[ 0 ];
            camera.position.y = view.eye[ 1 ];
            camera.position.z = view.eye[ 2 ];
            camera.up.x = view.up[ 0 ];
            camera.up.y = view.up[ 1 ];
            camera.up.z = view.up[ 2 ];
            view.camera = camera;
        }
		if (!isWebGL2){
			renderer = new THREE.WebGLRenderer({antialias: true});
			renderer.setPixelRatio(window.devicePixelRatio);
			renderer.setSize(W, H);
			container.appendChild(renderer.domElement);
		}else{
			renderer = new THREE.WebGL2Renderer({antialias: true});
			renderer.setPixelRatio(window.devicePixelRatio);
			renderer.setSize(W, H);
			container.appendChild(renderer.domElement);
		}
		if (!ctx) {
		console.log('your browser does not support WebGL');
		}
	}
    function updateSize() {
        if (windowWidth != W || windowHeight != H) {
            windowWidth = W;
            windowHeight = H;
            renderer.setSize(windowWidth, windowHeight);
        }
    }
    function animate() {
        requestAnimationFrame(animate);
        render();
    }
    function render() {
        updateSize();
        for (var i = 0; i < views.length; ++i) {
            view = views[i];
            camera = view.camera;
            camera.lookAt(scene.position);
            var x = Math.floor(windowWidth * view.x);
            var y = Math.floor(windowHeight * view.y);
            var width = Math.floor(windowWidth * view.width);
            var height = Math.floor(windowHeight * view.height);
            renderer.setViewport(x, y, width, height);
            renderer.setScissor(x, y, width, height);
            renderer.setScissorTest(true);
            camera.aspect = width / height;
            camera.updateProjectionMatrix();
            renderer.render(scene, camera);
        }
    }
}
module.exports = HoloWeb;
<commit_msg>Fixes #9<commit_after>var configurator = require('./configurator');
var Detector = window.Detector = require("detector-webgl");
var THREE = window.THREE = require("three");
var collada = require('three-loaders-collada')(THREE);
var animation = require('./vendors/loaders/collada/Animation')(THREE);
var KeyFrameAnimation = require('./vendors/loaders/collada/KeyFrameAnimation')(THREE);
var W = window.innerWidth;
var H = window.innerHeight;

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('webgl2');
var isWebGL2 = !!ctx;

delete canvas;

var HoloWeb = function (selector, config) {
    this.selector = selector || window.document.body;
    this.config = config;
    if (!Detector)
        return console.error("your browser does not support WebGL");
    var renderer;
    var windowWidth, windowHeight;
    var views = configurator(this.config, {H: H, W: W});
    var scene = new THREE.Scene();
    this.scene = scene;
    init(this.selector);
    animate();

    this.add = function(mesh){
        return this.scene.add(mesh);
    }
     this.remove = function(mesh){
        return this.scene.remove(mesh);
    }

    function init(container) {
        for (var i = 0; i < views.length; ++i) {
            var view = views[i];
            camera = new THREE.PerspectiveCamera(view.fov, window.innerWidth / window.innerHeight, 1, 10000);
            camera.position.x = view.eye[ 0 ];
            camera.position.y = view.eye[ 1 ];
            camera.position.z = view.eye[ 2 ];
            camera.up.x = view.up[ 0 ];
            camera.up.y = view.up[ 1 ];
            camera.up.z = view.up[ 2 ];
            view.camera = camera;
        }
		if (!isWebGL2){
			renderer = new THREE.WebGLRenderer({antialias: true});
			renderer.setPixelRatio(window.devicePixelRatio);
			renderer.setSize(W, H);
			container.appendChild(renderer.domElement);
		}else{
			renderer = new THREE.WebGL2Renderer({antialias: true});
			renderer.setPixelRatio(window.devicePixelRatio);
			renderer.setSize(W, H);
			container.appendChild(renderer.domElement);
		}
		if (!ctx) {
		console.log('your browser does not support WebGL');
		}
	}
    function updateSize() {
        if (windowWidth != W || windowHeight != H) {
            windowWidth = W;
            windowHeight = H;
            renderer.setSize(windowWidth, windowHeight);
        }
    }
    function animate() {
        requestAnimationFrame(animate);
        render();
    }
    function render() {
        updateSize();
        for (var i = 0; i < views.length; ++i) {
            view = views[i];
            camera = view.camera;
            camera.lookAt(scene.position);
            var x = Math.floor(windowWidth * view.x);
            var y = Math.floor(windowHeight * view.y);
            var width = Math.floor(windowWidth * view.width);
            var height = Math.floor(windowHeight * view.height);
            renderer.setViewport(x, y, width, height);
            renderer.setScissor(x, y, width, height);
            renderer.setScissorTest(true);
            camera.aspect = width / height;
            camera.updateProjectionMatrix();
            renderer.render(scene, camera);
        }
    }
}
module.exports = HoloWeb;
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.

// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

'use strict';

var isNaN = function(obj) {
  return typeof obj === 'number' && obj !== +obj;
};

/**
 * Class containing methods for communicating with a WebDAV server over XHR
 * and manipulating the responses.
 * @constructs
 */
var WebDAVClient = function() {};

/**
 * Convenience function for selecting the text content of nodes in an XML
 * document, using the DAV namespace.
 * @param {Node} element The XML Node to select from.
 * @param {string} selector The name of the tag to search select, excluding
 *     the namespace.
 * @return {string} The text content of the selected node.
 */
WebDAVClient.prototype.select = function(element, selector) {
  // TODO(lavelle): is this consistent for the WebDAV protocol, or an
  // implementation detail of the server?
  var namespace = 'DAV:';

  // Perform a query for the given selector, scoped by the DAV namespace.
  var elements = element.getElementsByTagNameNS(namespace, selector);

  // Return the text content of the first node in the returned collection, if
  // there are any.
  if (elements.length > 0) {
    return elements[0].textContent;
  } else {
    // Otherwise just return the empty string - no useful data here.
    return '';
  }
};

/**
 * Converts an XML Node in a WebDAV response object to an object representing
 * an entry in the ChromeOS File system.
 * @param {Node} node The XML Node to convert
 * @return {Object} A plain object representing the file or directory in the
 *     file system provider API.
 */
WebDAVClient.prototype.nodeToEntry = function(node) {
  // Extract the name of the file/directory from the href attribute.
  var name = this.select(node, 'href');

  if (name !== '/') {
    // Remove leading and trailing slashes from the name.
    name = name.replace(/^\/|\/$/g, '').split('/').pop();
  }

  // Extract the MIME type of the file from the getcontenttype attribute.
  var contentType = this.select(node, 'getcontenttype');

  // Determine whether an entry is a directory by the absence of a content type
  // attribute.
  var isDirectory = contentType === '';

  // Extract the modification time of the file from the  getlastmodified
  // attribute, and parse it into a Date object.
  var modificationTime = new Date(this.select(node, 'getlastmodified'));

  var size = parseInt(this.select(node, 'getcontentlength'), 10);

  if (isNaN(size)) {
    size = 0;
  }

  // Construct the entry object to be returned to the file system provider.
  var entry = {
    name: name,
    modificationTime: modificationTime,
    size: size,
    isDirectory: isDirectory
  };

  // Only give files MIME types, not directories.
  if (!isDirectory) {
    entry.mimeType = contentType;
  }

  return entry;
};

/**
 * Make a HTTP GET request -- fetch an entry from the server.
 * @param {string} url The URL of the server.
 * @param {Object=} opt_headers Any HTTP headers to set on the request.
 * @param {Function} onSuccess Function to be called with the response data
 *     from the request if it was successful.
 * @param {Function} onError Function to be called with an error message
 *     if the request failed.
 */
WebDAVClient.prototype.get = function(url, opt_headers, onSuccess, onError) {
  var verb = 'GET';
  var headers = opt_headers || {};
  var data = null;
  var responseType = 'arraybuffer';

  this.request(verb, url, headers, data, responseType, onSuccess, onError);
};

/**
 * Make a HTTP PROPFIND request -- fetch the metadta for an entry from the
 * server.
 * @param {string} url The URL of the server.
 * @param {Function} onSuccess Function to be called with the response data
 *     from the request if it was successful.
 * @param {Function} onError Function to be called with an error message
 *     if the request failed.
 * @param {Number} depth Number of levels of the filesystem to hierarchy to
 *     return information for.
 */
WebDAVClient.prototype.propertyFind = function(url, onSuccess, onError, depth) {
  var verb = 'PROPFIND';
  var headers = {Depth: depth};
  var data = null;
  var responseType = 'document';

  this.request(verb, url, headers, data, responseType, onSuccess, onError);
};

/**
 * Low-level wrapper function for making HTTP requests.
 * @param {string} verb HTTP verb to use for the request.
 * @param {string} url URL to send the request to.
 * @param {Object} headers Any HTTP headers to attach to the request.
 * @param {Object} data Data to be sent in the request.
 * @param {string} responseType The type of data returned by the request.
 * @param {Function} onSuccess Function to be called with the response data
 *     from the request if it was successful.
 * @param {Function} onError Function to be called with an error message
 *     if the request failed.
 * @return {Element} The XML document response from the server.
 */
WebDAVClient.prototype.request = function(verb, url, headers, data, responseType,
  onSuccess, onError) {
    var xhr = new XMLHttpRequest();

    var processBody = function() {
      var body = xhr.response;

      // If we're making a PROPFIND, remove the top level of the XML document
      // as it contains no useful information.
      if (verb === 'PROPFIND') {
        body = body.firstChild.nextSibling ? body.firstChild.nextSibling : body.firstChild;
      }

      return body;
    };

    // Register the callback to to be called when the request sucessfully
    // completes.
    xhr.onreadystatechange = function() {
      if(xhr.readyState !== 4) { return; }

      // Return an error for a non-2XX failure status code.
      if (xhr.status < 200 || xhr.status >= 300) {
        onError('FAILED');
        return;
      }

      var body = processBody();

      // Return an error if there was no response.
      if (!body) {
        onError('FAILED');
        return;
      }

      onSuccess(body);
    };

    // Always make asynchronous requests.
    var isAsynchronous = true;

    // Open the XHR connection.
    xhr.open(verb, url, isAsynchronous);

    // Set the expected data type of the server response.
    xhr.responseType = responseType;

    // If we're making a GET request, the request data is an XML document
    // so make sure to set this in the headers.
    if (verb === 'GET') {
      xhr.setRequestHeader('Content-Type', 'text/xml; charset=UTF-8');
    }

    // Set any other headers provided by the caller.
    for (var header in headers) {
      xhr.setRequestHeader(header, headers[header]);
    }

    // Send the data over the connection.
    xhr.send(data);
};

module.exports = WebDAVClient;
<commit_msg>fix jshint error<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.

// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd

'use strict';

window.isNaN = function(obj) {
  return typeof obj === 'number' && obj !== +obj;
};

/**
 * Class containing methods for communicating with a WebDAV server over XHR
 * and manipulating the responses.
 * @constructs
 */
var WebDAVClient = function() {};

/**
 * Convenience function for selecting the text content of nodes in an XML
 * document, using the DAV namespace.
 * @param {Node} element The XML Node to select from.
 * @param {string} selector The name of the tag to search select, excluding
 *     the namespace.
 * @return {string} The text content of the selected node.
 */
WebDAVClient.prototype.select = function(element, selector) {
  // TODO(lavelle): is this consistent for the WebDAV protocol, or an
  // implementation detail of the server?
  var namespace = 'DAV:';

  // Perform a query for the given selector, scoped by the DAV namespace.
  var elements = element.getElementsByTagNameNS(namespace, selector);

  // Return the text content of the first node in the returned collection, if
  // there are any.
  if (elements.length > 0) {
    return elements[0].textContent;
  } else {
    // Otherwise just return the empty string - no useful data here.
    return '';
  }
};

/**
 * Converts an XML Node in a WebDAV response object to an object representing
 * an entry in the ChromeOS File system.
 * @param {Node} node The XML Node to convert
 * @return {Object} A plain object representing the file or directory in the
 *     file system provider API.
 */
WebDAVClient.prototype.nodeToEntry = function(node) {
  // Extract the name of the file/directory from the href attribute.
  var name = this.select(node, 'href');

  if (name !== '/') {
    // Remove leading and trailing slashes from the name.
    name = name.replace(/^\/|\/$/g, '').split('/').pop();
  }

  // Extract the MIME type of the file from the getcontenttype attribute.
  var contentType = this.select(node, 'getcontenttype');

  // Determine whether an entry is a directory by the absence of a content type
  // attribute.
  var isDirectory = contentType === '';

  // Extract the modification time of the file from the  getlastmodified
  // attribute, and parse it into a Date object.
  var modificationTime = new Date(this.select(node, 'getlastmodified'));

  var size = parseInt(this.select(node, 'getcontentlength'), 10);

  if (isNaN(size)) {
    size = 0;
  }

  // Construct the entry object to be returned to the file system provider.
  var entry = {
    name: name,
    modificationTime: modificationTime,
    size: size,
    isDirectory: isDirectory
  };

  // Only give files MIME types, not directories.
  if (!isDirectory) {
    entry.mimeType = contentType;
  }

  return entry;
};

/**
 * Make a HTTP GET request -- fetch an entry from the server.
 * @param {string} url The URL of the server.
 * @param {Object=} opt_headers Any HTTP headers to set on the request.
 * @param {Function} onSuccess Function to be called with the response data
 *     from the request if it was successful.
 * @param {Function} onError Function to be called with an error message
 *     if the request failed.
 */
WebDAVClient.prototype.get = function(url, opt_headers, onSuccess, onError) {
  var verb = 'GET';
  var headers = opt_headers || {};
  var data = null;
  var responseType = 'arraybuffer';

  this.request(verb, url, headers, data, responseType, onSuccess, onError);
};

/**
 * Make a HTTP PROPFIND request -- fetch the metadta for an entry from the
 * server.
 * @param {string} url The URL of the server.
 * @param {Function} onSuccess Function to be called with the response data
 *     from the request if it was successful.
 * @param {Function} onError Function to be called with an error message
 *     if the request failed.
 * @param {Number} depth Number of levels of the filesystem to hierarchy to
 *     return information for.
 */
WebDAVClient.prototype.propertyFind = function(url, onSuccess, onError, depth) {
  var verb = 'PROPFIND';
  var headers = {Depth: depth};
  var data = null;
  var responseType = 'document';

  this.request(verb, url, headers, data, responseType, onSuccess, onError);
};

/**
 * Low-level wrapper function for making HTTP requests.
 * @param {string} verb HTTP verb to use for the request.
 * @param {string} url URL to send the request to.
 * @param {Object} headers Any HTTP headers to attach to the request.
 * @param {Object} data Data to be sent in the request.
 * @param {string} responseType The type of data returned by the request.
 * @param {Function} onSuccess Function to be called with the response data
 *     from the request if it was successful.
 * @param {Function} onError Function to be called with an error message
 *     if the request failed.
 * @return {Element} The XML document response from the server.
 */
WebDAVClient.prototype.request = function(verb, url, headers, data, responseType,
  onSuccess, onError) {
    var xhr = new XMLHttpRequest();

    var processBody = function() {
      var body = xhr.response;

      // If we're making a PROPFIND, remove the top level of the XML document
      // as it contains no useful information.
      if (verb === 'PROPFIND') {
        body = body.firstChild.nextSibling ? body.firstChild.nextSibling : body.firstChild;
      }

      return body;
    };

    // Register the callback to to be called when the request sucessfully
    // completes.
    xhr.onreadystatechange = function() {
      if(xhr.readyState !== 4) { return; }

      // Return an error for a non-2XX failure status code.
      if (xhr.status < 200 || xhr.status >= 300) {
        onError('FAILED');
        return;
      }

      var body = processBody();

      // Return an error if there was no response.
      if (!body) {
        onError('FAILED');
        return;
      }

      onSuccess(body);
    };

    // Always make asynchronous requests.
    var isAsynchronous = true;

    // Open the XHR connection.
    xhr.open(verb, url, isAsynchronous);

    // Set the expected data type of the server response.
    xhr.responseType = responseType;

    // If we're making a GET request, the request data is an XML document
    // so make sure to set this in the headers.
    if (verb === 'GET') {
      xhr.setRequestHeader('Content-Type', 'text/xml; charset=UTF-8');
    }

    // Set any other headers provided by the caller.
    for (var header in headers) {
      xhr.setRequestHeader(header, headers[header]);
    }

    // Send the data over the connection.
    xhr.send(data);
};

module.exports = WebDAVClient;
<|endoftext|>


<commit_before>(function(jsGrid) {

    jsGrid.locales.ru = {
        grid: {
            noDataContent: "Pas de données",
            deleteConfirm: "Êtes-vous sûr ?",
            pagerFormat: "Pages: {first} {prev} {pages} {next} {last}    {pageIndex} de {pageCount}",
            pagePrevText: "<",
            pageNextText: ">",
            pageFirstText: "<<",
            pageLastText: ">>",
            loadMessage: "Chargement en cours...",
            invalidMessage: "Des données incorrectes sont entrés !"
        },

        loadIndicator: {
            message: "Chargement en cours..."
        },

        fields: {
            control: {
                searchModeButtonTooltip: "Recherche",
                insertModeButtonTooltip: "Ajouter une entrée",
                editButtonTooltip: "Changer",
                deleteButtonTooltip: "Effacer",
                searchButtonTooltip: "Trouve",
                clearFilterButtonTooltip: "Effacer",
                insertButtonTooltip: "Ajouter",
                updateButtonTooltip: "Sauvegarder",
                cancelEditButtonTooltip: "Annuler"
            }
        },

        validators: {
            required: { message: "Champ requis" },
            rangeLength: { message: "Longueur de la valeur du champ est hors de la plage définie" },
            minLength: { message: "La valeur du champ est trop long" },
            maxLength: { message: "La valeur du champ est trop court" },
            pattern: { message: "La valeur du champ ne correspond pas à la configuration définie" },
            range: { message: "La valeur du champ est hors de la plage définie" },
            min: { message: "La valeur du champ est trop grande" },
            max: { message: "La valeur du champ est trop petit" }
        }
    };

}(jsGrid, jQuery));

<commit_msg>i18n: Correct French localization name<commit_after>(function(jsGrid) {

    jsGrid.locales.fr = {
        grid: {
            noDataContent: "Pas de données",
            deleteConfirm: "Êtes-vous sûr ?",
            pagerFormat: "Pages: {first} {prev} {pages} {next} {last}    {pageIndex} de {pageCount}",
            pagePrevText: "<",
            pageNextText: ">",
            pageFirstText: "<<",
            pageLastText: ">>",
            loadMessage: "Chargement en cours...",
            invalidMessage: "Des données incorrectes sont entrés !"
        },

        loadIndicator: {
            message: "Chargement en cours..."
        },

        fields: {
            control: {
                searchModeButtonTooltip: "Recherche",
                insertModeButtonTooltip: "Ajouter une entrée",
                editButtonTooltip: "Changer",
                deleteButtonTooltip: "Effacer",
                searchButtonTooltip: "Trouve",
                clearFilterButtonTooltip: "Effacer",
                insertButtonTooltip: "Ajouter",
                updateButtonTooltip: "Sauvegarder",
                cancelEditButtonTooltip: "Annuler"
            }
        },

        validators: {
            required: { message: "Champ requis" },
            rangeLength: { message: "Longueur de la valeur du champ est hors de la plage définie" },
            minLength: { message: "La valeur du champ est trop long" },
            maxLength: { message: "La valeur du champ est trop court" },
            pattern: { message: "La valeur du champ ne correspond pas à la configuration définie" },
            range: { message: "La valeur du champ est hors de la plage définie" },
            min: { message: "La valeur du champ est trop grande" },
            max: { message: "La valeur du champ est trop petit" }
        }
    };

}(jsGrid, jQuery));

<|endoftext|>


<commit_before>var event = require("./event");

function Component(props) {
  this.props = this._buildProps(props);
  this.state = {};
  this.mounted = false;
  event.on(this, "mount", function(root) {
    this.mounted = true;
    this.root = root;
    event.emit(this, "upstream:update");
  });
  event.on(this, "unmount", function() {
    this.mounted = false;
    this.root = null;
  });
  if(this.mixins) {
    this.mixins.forEach(function(mixin) {
      mixin.init(this);
    }, this);
  }
  this.init();
}

Component.createClass = function(proto) {
  var componentClass = function() {
    return Component.apply(this, arguments);
  };
  componentClass.prototype = Object.create(Component.prototype);
  Object.defineProperty(componentClass.prototype, "constructor", {
    configurable: true,
    enumerable: false,
    writable: true,
    value: componentClass
  });
  Object.assign(componentClass.prototype, proto);
  return componentClass;
};

Component.mixins = null;

Component.propTypes = {};

Component.dom = {};

Component.defaultProps = {};

["mixins", "propTypes", "dom", "defaultProps"].forEach(function(name) {
  Object.defineProperty(Component.prototype, name, {
    configurable: true,
    enumerable: true,
    get: function() {
      return this.constructor[name];
    },
    set: function(value) {
      this.constructor[name] = value;
    }
  });
});

Component.prototype.init = function() {};

Component.prototype.needUpdate = function(nextProps, nextState) {
  return true;
};

Component.prototype._buildProps = function(props) {
  return Object.assign({}, this.defaultProps, props);
};

Component.prototype._update = function(props, state) {
  if(props !== this.props) {
    event.emit(this, "receive-props", props);
  }
  if(this.needUpdate(props, state)) {
    this.props = props;
    this.state = state;
    if(this.mounted) {
      event.emit(this, "upstream:update");
    }
  }
};

Component.prototype.forceUpdate = function() {
  if(this.mounted) {
    event.emit(this, "upstream:update");
  }
};

Component.prototype.setProps = function(props) {
  this._update(Object.assign({}, this.props, props), this.state);
};

Component.prototype.replaceProps = function(props) {
  this._update(this._buildProps(props), this.state);
};

Component.prototype.setState = function(state) {
  this._update(this.props, Object.assign({}, this.state, state));
};

Component.prototype.replaceState = function(state) {
  this._update(this.props, state);
};

Component.prototype.emit = function(type, detail) {
  event.emit(this, "upstream:emit-event", type, detail);
};

Component.prototype.render = function() {
  return null;
};

module.exports = Component;
<commit_msg>fix logic bug in component update<commit_after>var event = require("./event");

function Component(props) {
  this.props = this._buildProps(props);
  this.state = {};
  this.mounted = false;
  event.on(this, "mount", function(root) {
    this.mounted = true;
    this.root = root;
    event.emit(this, "upstream:update");
  });
  event.on(this, "unmount", function() {
    this.mounted = false;
    this.root = null;
  });
  if(this.mixins) {
    this.mixins.forEach(function(mixin) {
      mixin.init(this);
    }, this);
  }
  this.init();
}

Component.createClass = function(proto) {
  var componentClass = function() {
    return Component.apply(this, arguments);
  };
  componentClass.prototype = Object.create(Component.prototype);
  Object.defineProperty(componentClass.prototype, "constructor", {
    configurable: true,
    enumerable: false,
    writable: true,
    value: componentClass
  });
  Object.assign(componentClass.prototype, proto);
  return componentClass;
};

Component.mixins = null;

Component.propTypes = {};

Component.dom = {};

Component.defaultProps = {};

["mixins", "propTypes", "dom", "defaultProps"].forEach(function(name) {
  Object.defineProperty(Component.prototype, name, {
    configurable: true,
    enumerable: true,
    get: function() {
      return this.constructor[name];
    },
    set: function(value) {
      this.constructor[name] = value;
    }
  });
});

Component.prototype.init = function() {};

Component.prototype.needUpdate = function(nextProps, nextState) {
  return true;
};

Component.prototype._buildProps = function(props) {
  return Object.assign({}, this.defaultProps, props);
};

Component.prototype._update = function(props, state) {
  if(props !== this.props) {
    event.emit(this, "receive-props", props);
  }
  var needUpdate = this.mounted && this.needUpdate(props, state);
  this.props = props;
  this.state = state;
  if(needUpdate) {
    event.emit(this, "upstream:update");
  }
};

Component.prototype.forceUpdate = function() {
  if(this.mounted) {
    event.emit(this, "upstream:update");
  }
};

Component.prototype.setProps = function(props) {
  this._update(Object.assign({}, this.props, props), this.state);
};

Component.prototype.replaceProps = function(props) {
  this._update(this._buildProps(props), this.state);
};

Component.prototype.setState = function(state) {
  this._update(this.props, Object.assign({}, this.state, state));
};

Component.prototype.replaceState = function(state) {
  this._update(this.props, state);
};

Component.prototype.emit = function(type, detail) {
  event.emit(this, "upstream:emit-event", type, detail);
};

Component.prototype.render = function() {
  return null;
};

module.exports = Component;
<|endoftext|>


<commit_before>

export default ({ maxWidth }) => `

body {
  margin: 0;
}

.idyll-root {
  box-sizing: border-box;
  margin: 0 auto;
  padding: 60px 0;
  margin-bottom: 60px;
}

.section {
  padding: 0 10px;
  margin: 0 auto;
}

.article-header {
  width: 600px;
  max-width: 90vw;
  margin-bottom: 45px;
}

.inset {
  max-width: 400px;
  margin: 0 auto;
}

input {
  cursor: pointer;
}

.relative {
  position: relative;
}
.aside-container {
  position: relative;
}
.aside {
  position: absolute;
  width: 300px;
  right: calc((10vw + 600px + 150px) / -2);
}

.fixed {
  position: fixed;
  display: flex;
  align-self: center;
  flex-direction: column;
  align-items: center;
  right: 25px;
  top: 0;
  bottom: 0;
  width: calc((80vw - 600px) - 50px);
  justify-content: center;
}

.fixed div {
  width: 100%;
}

.idyll-scroll-graphic {
  position: -webkit-sticky;
  position: sticky;
}

.idyll-scroll-graphic img {
  max-height: 100vh;
}

.component-debug-view {
  position: relative;
  transition: background-color 0.3s ease-in;
}

.author-view-button {
  position: absolute;
  top: 3px;
  right: 0;
  opacity: .38;
  background-color: #E7E3D0;
  background-image: url('https://idyll-lang.org/static/images/quill-icon.png');
  background-repeat: no-repeat;
  background-size: contain;
  width: 30px;
  height: 30px;
  margin-right: 10px;
  box-sizing: border-box;
  border-radius: 15px;
  cursor: pointer;
}

.author-view-button:focus {
  outline: none;
}

.component-debug-view:hover > .author-view-button {
  opacity: 0.87;
  transition: opacity 600ms linear;
}

.author-component-view {
  display: flex;
  flex-direction: column;
}

.author-component-view h2, .author-component-view h3 {
  margin-top: 5px;
  margin-bottom: 5px;
}

.props-table {
  width: 90%;
  display: table;
  border: 1px solid #A4A2A2;
  border-radius: 20px;
  margin: 0 auto;
}

.props-table-type {
  font-family: 'Courier-New';
}

.props-table-row {
  text-align: center;
}

.debug-collapse {
  overflow: hidden;
  transition: height 0.3s ease-in;
  margin: 0;
  box-sizing: border-box;
}

.icon-links {
  margin-top: 13px;
  text-align: center;
  display: flex;
  flex-direction: row;
  justify-content: center;
}

.icon-link {
  width: 20px;
  height: 20px;
}

.icon-link-image {
  cursor: pointer;
}

.button-tooltip {
  background-color: black !important;
  padding: 0 5px;
}

.tooltip-header {
  line-height: 1;
  margin: 6px 0;
  font-size: 18px;
}

.tooltip-subtitle {
  font-style: italic;
}

@media all and (max-width: 1600px) {
  .fixed {
    width: calc((85vw - 600px) - 50px);
  }
}

@media all and (max-width: 1000px) {
  /* put your css styles in here */
  .desktop {
    display: none;
  }
  .relative {
    position: static;
  }
  .aside {
    position: static;
    width: 100%;
    right: 0;
  }

  .hed {
    width: 100%;
  }

  .idyll-root {
    padding: 15px 0;
  }

  .idyll-root {
    width: 90vw;
    max-width: 600px;
    margin: 0 auto;
    padding-bottom: 80vh;
  }
  .fixed {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100vw;
    top: initial;
    background: white;
    padding: 20px 0;
    border-top: solid 2px black;
  }
}
`
<commit_msg>make button 24x24<commit_after>

export default ({ maxWidth }) => `

body {
  margin: 0;
}

.idyll-root {
  box-sizing: border-box;
  margin: 0 auto;
  padding: 60px 0;
  margin-bottom: 60px;
}

.section {
  padding: 0 10px;
  margin: 0 auto;
}

.article-header {
  width: 600px;
  max-width: 90vw;
  margin-bottom: 45px;
}

.inset {
  max-width: 400px;
  margin: 0 auto;
}

input {
  cursor: pointer;
}

.relative {
  position: relative;
}
.aside-container {
  position: relative;
}
.aside {
  position: absolute;
  width: 300px;
  right: calc((10vw + 600px + 150px) / -2);
}

.fixed {
  position: fixed;
  display: flex;
  align-self: center;
  flex-direction: column;
  align-items: center;
  right: 25px;
  top: 0;
  bottom: 0;
  width: calc((80vw - 600px) - 50px);
  justify-content: center;
}

.fixed div {
  width: 100%;
}

.idyll-scroll-graphic {
  position: -webkit-sticky;
  position: sticky;
}

.idyll-scroll-graphic img {
  max-height: 100vh;
}

.component-debug-view {
  position: relative;
  transition: background-color 0.3s ease-in;
}

.author-view-button {
  position: absolute;
  top: 3px;
  right: 0;
  opacity: .38;
  background-color: #E7E3D0;
  background-image: url('https://idyll-lang.org/static/images/quill-icon.png');
  background-repeat: no-repeat;
  background-size: contain;
  width: 24px;
  height: 24px;
  margin-right: 10px;
  box-sizing: border-box;
  border-radius: 12px;
  cursor: pointer;
}

.author-view-button:focus {
  outline: none;
}

.component-debug-view:hover > .author-view-button {
  opacity: 0.87;
  transition: opacity 600ms linear;
}

.author-component-view {
  display: flex;
  flex-direction: column;
}

.author-component-view h2, .author-component-view h3 {
  margin-top: 5px;
  margin-bottom: 5px;
}

.props-table {
  width: 90%;
  display: table;
  border: 1px solid #A4A2A2;
  border-radius: 20px;
  margin: 0 auto;
}

.props-table-type {
  font-family: 'Courier-New';
}

.props-table-row {
  text-align: center;
}

.debug-collapse {
  overflow: hidden;
  transition: height 0.3s ease-in;
  margin: 0;
  box-sizing: border-box;
}

.icon-links {
  margin-top: 13px;
  text-align: center;
  display: flex;
  flex-direction: row;
  justify-content: center;
}

.icon-link {
  width: 20px;
  height: 20px;
}

.icon-link-image {
  cursor: pointer;
}

.button-tooltip {
  background-color: black !important;
  padding: 0 5px;
}

.tooltip-header {
  line-height: 1;
  margin: 6px 0;
  font-size: 18px;
}

.tooltip-subtitle {
  font-style: italic;
}

@media all and (max-width: 1600px) {
  .fixed {
    width: calc((85vw - 600px) - 50px);
  }
}

@media all and (max-width: 1000px) {
  /* put your css styles in here */
  .desktop {
    display: none;
  }
  .relative {
    position: static;
  }
  .aside {
    position: static;
    width: 100%;
    right: 0;
  }

  .hed {
    width: 100%;
  }

  .idyll-root {
    padding: 15px 0;
  }

  .idyll-root {
    width: 90vw;
    max-width: 600px;
    margin: 0 auto;
    padding-bottom: 80vh;
  }
  .fixed {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100vw;
    top: initial;
    background: white;
    padding: 20px 0;
    border-top: solid 2px black;
  }
}
`
<|endoftext|>


<commit_before>import { assign } from './util';
import { diff, commitRoot } from './diff/index';
import options from './options';
import { Fragment } from './create-element';

/**
 * Base Component class. Provides `setState()` and `forceUpdate()`, which
 * trigger rendering
 * @param {object} props The initial component props
 * @param {object} context The initial context from parent components'
 * getChildContext
 */
export function Component(props, context) {
	this.props = props;
	this.context = context;
}

/**
 * Update component state and schedule a re-render.
 * @param {object | ((s: object, p: object) => object)} update A hash of state
 * properties to update with new values or a function that given the current
 * state and props returns a new partial state
 * @param {() => void} [callback] A function to be called once component state is
 * updated
 */
Component.prototype.setState = function(update, callback) {
	// only clone state when copying to nextState the first time.
	let s;
	if (this._nextState !== this.state) {
		s = this._nextState;
	} else {
		s = this._nextState = assign({}, this.state);
	}

	if (typeof update == 'function') {
		update = update(s, this.props);
	}

	if (update) {
		assign(s, update);
	}

	// Skip update if updater function returned null
	if (update == null) return;

	if (this._vnode) {
		if (callback) this._renderCallbacks.push(callback);
		enqueueRender(this);
	}
};

/**
 * Immediately perform a synchronous re-render of the component
 * @param {() => void} [callback] A function to be called after component is
 * re-rendered
 */
Component.prototype.forceUpdate = function(callback) {
	if (this._vnode) {
		// Set render mode so that we can differentiate where the render request
		// is coming from. We need this because forceUpdate should never call
		// shouldComponentUpdate
		this._force = true;
		if (callback) this._renderCallbacks.push(callback);
		enqueueRender(this);
	}
};

/**
 * Accepts `props` and `state`, and returns a new Virtual DOM tree to build.
 * Virtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).
 * @param {object} props Props (eg: JSX attributes) received from parent
 * element/component
 * @param {object} state The component's current state
 * @param {object} context Context object, as returned by the nearest
 * ancestor's `getChildContext()`
 * @returns {import('./index').ComponentChildren | void}
 */
Component.prototype.render = Fragment;

Component.prototype._rerenderCount = 0;

/**
 * @param {import('./internal').VNode} vnode
 * @param {number | null} [childIndex]
 */
export function getDomSibling(vnode, childIndex) {
	if (childIndex == null) {
		// Use childIndex==null as a signal to resume the search from the vnode's sibling
		return vnode._parent
			? getDomSibling(vnode._parent, vnode._parent._children.indexOf(vnode) + 1)
			: null;
	}

	let sibling;
	for (; childIndex < vnode._children.length; childIndex++) {
		sibling = vnode._children[childIndex];

		if (sibling != null && sibling._dom != null) {
			// Since updateParentDomPointers keeps _dom pointer correct,
			// we can rely on _dom to tell us if this subtree contains a
			// rendered DOM node, and what the first rendered DOM node is
			return sibling._dom;
		}
	}

	// If we get here, we have not found a DOM node in this vnode's children.
	// We must resume from this vnode's sibling (in it's parent _children array)
	// Only climb up and search the parent if we aren't searching through a DOM
	// VNode (meaning we reached the DOM parent of the original vnode that began
	// the search)
	return typeof vnode.type == 'function' ? getDomSibling(vnode) : null;
}

/**
 * Trigger in-place re-rendering of a component.
 * @param {import('./internal').Component} component The component to rerender
 */
function renderComponent(component) {
	let vnode = component._vnode,
		oldDom = vnode._dom,
		parentDom = component._parentDom;

	if (parentDom) {
		let commitQueue = [];
		const oldVNode = assign({}, vnode);
		oldVNode._original = oldVNode;

		let newDom = diff(
			parentDom,
			vnode,
			oldVNode,
			component._globalContext,
			parentDom.ownerSVGElement !== undefined,
			null,
			commitQueue,
			oldDom == null ? getDomSibling(vnode) : oldDom
		);
		commitRoot(commitQueue, vnode);

		if (newDom != oldDom) {
			updateParentDomPointers(vnode);
		}
	}
}

/**
 * @param {import('./internal').VNode} vnode
 */
function updateParentDomPointers(vnode) {
	if ((vnode = vnode._parent) != null && vnode._component != null) {
		vnode._dom = vnode._component.base = null;
		for (let i = 0; i < vnode._children.length; i++) {
			let child = vnode._children[i];
			if (child != null && child._dom != null) {
				vnode._dom = vnode._component.base = child._dom;
				break;
			}
		}

		return updateParentDomPointers(vnode);
	}
}

/**
 * The render queue
 * @type {Array<import('./internal').Component>}
 */
let rerenderQueue = [];

/**
 * Asynchronously schedule a callback
 * @type {(cb: () => void) => void}
 */
/* istanbul ignore next */
// Note the following line isn't tree-shaken by rollup cuz of rollup/rollup#2566
const defer =
	typeof Promise == 'function'
		? Promise.prototype.then.bind(Promise.resolve())
		: setTimeout;

/*
 * The value of `Component.debounce` must asynchronously invoke the passed in callback. It is
 * important that contributors to Preact can consistently reason about what calls to `setState`, etc.
 * do, and when their effects will be applied. See the links below for some further reading on designing
 * asynchronous APIs.
 * * [Designing APIs for Asynchrony](https://blog.izs.me/2013/08/designing-apis-for-asynchrony)
 * * [Callbacks synchronous and asynchronous](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/)
 */

let prevDebounce;

/**
 * Enqueue a rerender of a component
 * @param {import('./internal').Component} c The component to rerender
 */
export function enqueueRender(c) {
	if (
		(!c._dirty &&
			(c._dirty = true) &&
			rerenderQueue.push(c) &&
			!Component.prototype.rerenderCount++) ||
		prevDebounce !== options.debounceRendering
	) {
		prevDebounce = options.debounceRendering;
		(prevDebounce || defer)(process);
	}
}

/** Flush the render queue by rerendering all queued components */
function process() {
	let queue;
	while ((Component.prototype._rerenderCount = rerenderQueue.length)) {
		queue = rerenderQueue.sort((a, b) => a._vnode._depth - b._vnode._depth);
		rerenderQueue = [];
		// Don't update `renderCount` yet. Keep its value non-zero to prevent unnecessary
		// process() calls from getting scheduled while `queue` is still being consumed.
		queue.some(c => {
			if (c._dirty) renderComponent(c);
		});
	}
}
<commit_msg>check how much process adds<commit_after>import { assign } from './util';
import { diff, commitRoot } from './diff/index';
import options from './options';
import { Fragment } from './create-element';

/**
 * Base Component class. Provides `setState()` and `forceUpdate()`, which
 * trigger rendering
 * @param {object} props The initial component props
 * @param {object} context The initial context from parent components'
 * getChildContext
 */
export function Component(props, context) {
	this.props = props;
	this.context = context;
}

/**
 * Update component state and schedule a re-render.
 * @param {object | ((s: object, p: object) => object)} update A hash of state
 * properties to update with new values or a function that given the current
 * state and props returns a new partial state
 * @param {() => void} [callback] A function to be called once component state is
 * updated
 */
Component.prototype.setState = function(update, callback) {
	// only clone state when copying to nextState the first time.
	let s;
	if (this._nextState !== this.state) {
		s = this._nextState;
	} else {
		s = this._nextState = assign({}, this.state);
	}

	if (typeof update == 'function') {
		update = update(s, this.props);
	}

	if (update) {
		assign(s, update);
	}

	// Skip update if updater function returned null
	if (update == null) return;

	if (this._vnode) {
		if (callback) this._renderCallbacks.push(callback);
		enqueueRender(this);
	}
};

/**
 * Immediately perform a synchronous re-render of the component
 * @param {() => void} [callback] A function to be called after component is
 * re-rendered
 */
Component.prototype.forceUpdate = function(callback) {
	if (this._vnode) {
		// Set render mode so that we can differentiate where the render request
		// is coming from. We need this because forceUpdate should never call
		// shouldComponentUpdate
		this._force = true;
		if (callback) this._renderCallbacks.push(callback);
		enqueueRender(this);
	}
};

/**
 * Accepts `props` and `state`, and returns a new Virtual DOM tree to build.
 * Virtual DOM is generally constructed via [JSX](http://jasonformat.com/wtf-is-jsx).
 * @param {object} props Props (eg: JSX attributes) received from parent
 * element/component
 * @param {object} state The component's current state
 * @param {object} context Context object, as returned by the nearest
 * ancestor's `getChildContext()`
 * @returns {import('./index').ComponentChildren | void}
 */
Component.prototype.render = Fragment;

/**
 * @param {import('./internal').VNode} vnode
 * @param {number | null} [childIndex]
 */
export function getDomSibling(vnode, childIndex) {
	if (childIndex == null) {
		// Use childIndex==null as a signal to resume the search from the vnode's sibling
		return vnode._parent
			? getDomSibling(vnode._parent, vnode._parent._children.indexOf(vnode) + 1)
			: null;
	}

	let sibling;
	for (; childIndex < vnode._children.length; childIndex++) {
		sibling = vnode._children[childIndex];

		if (sibling != null && sibling._dom != null) {
			// Since updateParentDomPointers keeps _dom pointer correct,
			// we can rely on _dom to tell us if this subtree contains a
			// rendered DOM node, and what the first rendered DOM node is
			return sibling._dom;
		}
	}

	// If we get here, we have not found a DOM node in this vnode's children.
	// We must resume from this vnode's sibling (in it's parent _children array)
	// Only climb up and search the parent if we aren't searching through a DOM
	// VNode (meaning we reached the DOM parent of the original vnode that began
	// the search)
	return typeof vnode.type == 'function' ? getDomSibling(vnode) : null;
}

/**
 * Trigger in-place re-rendering of a component.
 * @param {import('./internal').Component} component The component to rerender
 */
function renderComponent(component) {
	let vnode = component._vnode,
		oldDom = vnode._dom,
		parentDom = component._parentDom;

	if (parentDom) {
		let commitQueue = [];
		const oldVNode = assign({}, vnode);
		oldVNode._original = oldVNode;

		let newDom = diff(
			parentDom,
			vnode,
			oldVNode,
			component._globalContext,
			parentDom.ownerSVGElement !== undefined,
			null,
			commitQueue,
			oldDom == null ? getDomSibling(vnode) : oldDom
		);
		commitRoot(commitQueue, vnode);

		if (newDom != oldDom) {
			updateParentDomPointers(vnode);
		}
	}
}

/**
 * @param {import('./internal').VNode} vnode
 */
function updateParentDomPointers(vnode) {
	if ((vnode = vnode._parent) != null && vnode._component != null) {
		vnode._dom = vnode._component.base = null;
		for (let i = 0; i < vnode._children.length; i++) {
			let child = vnode._children[i];
			if (child != null && child._dom != null) {
				vnode._dom = vnode._component.base = child._dom;
				break;
			}
		}

		return updateParentDomPointers(vnode);
	}
}

/**
 * The render queue
 * @type {Array<import('./internal').Component>}
 */
let rerenderQueue = [];

/**
 * Asynchronously schedule a callback
 * @type {(cb: () => void) => void}
 */
/* istanbul ignore next */
// Note the following line isn't tree-shaken by rollup cuz of rollup/rollup#2566
const defer =
	typeof Promise == 'function'
		? Promise.prototype.then.bind(Promise.resolve())
		: setTimeout;

/*
 * The value of `Component.debounce` must asynchronously invoke the passed in callback. It is
 * important that contributors to Preact can consistently reason about what calls to `setState`, etc.
 * do, and when their effects will be applied. See the links below for some further reading on designing
 * asynchronous APIs.
 * * [Designing APIs for Asynchrony](https://blog.izs.me/2013/08/designing-apis-for-asynchrony)
 * * [Callbacks synchronous and asynchronous](https://blog.ometer.com/2011/07/24/callbacks-synchronous-and-asynchronous/)
 */

let prevDebounce;

/**
 * Enqueue a rerender of a component
 * @param {import('./internal').Component} c The component to rerender
 */
export function enqueueRender(c) {
	if (
		(!c._dirty &&
			(c._dirty = true) &&
			rerenderQueue.push(c) &&
			!process.rerenderCount++) ||
		prevDebounce !== options.debounceRendering
	) {
		prevDebounce = options.debounceRendering;
		(prevDebounce || defer)(process);
	}
}

/** Flush the render queue by rerendering all queued components */
function process() {
	let queue;
	while ((process._rerenderCount = rerenderQueue.length)) {
		queue = rerenderQueue.sort((a, b) => a._vnode._depth - b._vnode._depth);
		rerenderQueue = [];
		// Don't update `renderCount` yet. Keep its value non-zero to prevent unnecessary
		// process() calls from getting scheduled while `queue` is still being consumed.
		queue.some(c => {
			if (c._dirty) renderComponent(c);
		});
	}
}
process._rerenderCount = 0;
<|endoftext|>


<commit_before>import LernaRepo          from "lerna/lib/Repository";
import progressBar        from "lerna/lib/progressBar";
import RemoteRepo         from "./RemoteRepo";
import execSync           from "./execSync";
import ConfigurationError from "./ConfigurationError";

export default class Changelog {
  constructor(config) {
    this.config = this.getConfig();
    this.remote = new RemoteRepo(this.config);
  }

  getConfig() {
    const lerna = new LernaRepo();

    const config = lerna.lernaJson.changelog;

    if (!config) {
      throw new ConfigurationError(
        "Missing changelog config in `lerna.json`.\n"+
        "See docs for setup: https://github.com/lerna/lerna-changelog#readme"
      );
    }

    config.rootPath = lerna.rootPath;

    return config;
  }

  createMarkdown() {
    const commitInfo = this.getCommitInfo();
    const committers = this.getCommitters(commitInfo);
    const commitsByCategory = this.getCommitsByCategory(commitInfo);
    const fixesRegex = /Fix(es)? [T#](\d+)/i;

    let date = new Date().toISOString();

    date = date.slice(0, date.indexOf("T"));

    let markdown = "\n";

    markdown += "## Unreleased (" + date + ")";

    progressBar.init(commitsByCategory.length);

    commitsByCategory.filter(category => {
      return category.commits.length > 0;
    }).forEach(category => {
      progressBar.tick(category.heading);

      markdown += "\n";
      markdown += "\n";
      markdown += "#### " + category.heading;

      category.commits.forEach(commit => {
        markdown += "\n";

        var changedPackages =
        execSync("git log -m --name-only --pretty='format:' " + commit.commitSHA)
        // not sure why it's including extra files
        .split("\n\n")[0]
        // turn into an array
        .split("\n")
        // remove files that aren't in packages/
        .filter(function(files) {
          return files.indexOf("packages/") >= 0;
        })
        // extract base package name
        .map(function(files) {
          files = files.slice(9);
          return files.slice(0, files.indexOf("/"));
        })
        // unique packages
        .filter(function(value, index, self) {
          return self.indexOf(value) === index;
        });

        var spaces = 0;

        if (changedPackages.length > 0) {
          markdown += repeat(" ", spaces) + "* ";

          changedPackages.forEach(function(pkg, i) {
            markdown += (i === 0 ? "" : ", ") + "`" + pkg + "`";
          });

          markdown += "\n";

          // indent more?
          spaces = 2;
        }

        if (commit.number) {
          var prUrl = this.remote.getBasePullRequestUrl() + commit.number;
          markdown += repeat(" ", spaces) + "* ";
          markdown += "[#" + commit.number + "](" + prUrl + ")";
        }

        if (commit.title.match(fixesRegex)) {
          commit.title = commit.title.replace(fixesRegex, "Fixes [#$2](" + this.remote.getBaseIssueUrl() + "$2)");
        }

        markdown += " " + commit.title + "." + " ([@" + commit.user.login + "](" + commit.user.html_url + "))";
      });
    });

    progressBar.terminate();

    markdown += "\n\n#### Commiters: " + committers.length + "\n";
    markdown += committers.map(function(commiter) {
      return "- " + commiter;
    }).join("\n");

    return markdown;
  }

  getLastTag() {
    return execSync("git describe --abbrev=0 --tags");
  }

  getListOfCommits() {
    var lastTag = this.getLastTag();
    var commits = execSync("git log --oneline " + lastTag + "..").split("\n");
    return commits;
  }

  getCommitters(commits) {
    var committers = {}

    commits.forEach(commit => {
      const login = (commit.user||{}).login;
      if (login && !committers[login]){
        const user = this.remote.getUserData(login);
        committers[login] = `${user.name} ([${login}](${user.html_url}))`;
      }
    });

    return Object.keys(committers).map(k => committers[k]).sort();
  }

  getCommitInfo() {
    const commits = this.getListOfCommits();

    progressBar.init(commits.length);

    var logs = commits.map(commit => {

      var sha = commit.slice(0, 7);
      var message = commit.slice(8);
      var response;
      progressBar.tick(sha);

      var mergeCommit = message.match(/\(#(\d+)\)$/);

      if (message.indexOf("Merge pull request ") === 0) {
        var start = message.indexOf("#") + 1;
        var end = message.slice(start).indexOf(" ");
        var issueNumber = message.slice(start, start + end);

        response = this.remote.getIssueData(issueNumber);
        response.commitSHA = sha;
        response.mergeMessage = message;
        return response;
      } else if (mergeCommit) {
        var issueNumber = mergeCommit[1];
        response = this.remote.getIssueData(issueNumber);
        response.commitSHA = sha;
        response.mergeMessage = message;
        return response;
      }

      return {
        commitSHA: sha,
        message: message,
        labels: []
      };
    });

    progressBar.terminate();
    return logs;
  }

  getCommitsByCategory(logs) {
    var categories = this.remote.getLabels().map(label => {
      var commits = [];

      logs.forEach(function(log) {
        var labels = log.labels.map(function(label) {
          return label.name;
        });

        if (labels.indexOf(label.toLowerCase()) >= 0) {
          commits.push(log);
        }
      });

      return {
        heading: this.remote.getHeadingForLabel(label),
        commits: commits
      };
    });

    return categories;
  }
}

function toTitleCase(str) {
    return str.replace(/\w\S*/g, function(text){
      return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
    });
}

function repeat(str, times) {
  return Array(times + 1).join(str);
}
<commit_msg>Stricter package check<commit_after>import LernaRepo          from "lerna/lib/Repository";
import progressBar        from "lerna/lib/progressBar";
import RemoteRepo         from "./RemoteRepo";
import execSync           from "./execSync";
import ConfigurationError from "./ConfigurationError";

export default class Changelog {
  constructor(config) {
    this.config = this.getConfig();
    this.remote = new RemoteRepo(this.config);
  }

  getConfig() {
    const lerna = new LernaRepo();

    const config = lerna.lernaJson.changelog;

    if (!config) {
      throw new ConfigurationError(
        "Missing changelog config in `lerna.json`.\n"+
        "See docs for setup: https://github.com/lerna/lerna-changelog#readme"
      );
    }

    config.rootPath = lerna.rootPath;

    return config;
  }

  createMarkdown() {
    const commitInfo = this.getCommitInfo();
    const committers = this.getCommitters(commitInfo);
    const commitsByCategory = this.getCommitsByCategory(commitInfo);
    const fixesRegex = /Fix(es)? [T#](\d+)/i;

    let date = new Date().toISOString();

    date = date.slice(0, date.indexOf("T"));

    let markdown = "\n";

    markdown += "## Unreleased (" + date + ")";

    progressBar.init(commitsByCategory.length);

    commitsByCategory.filter(category => {
      return category.commits.length > 0;
    }).forEach(category => {
      progressBar.tick(category.heading);

      markdown += "\n";
      markdown += "\n";
      markdown += "#### " + category.heading;

      category.commits.forEach(commit => {
        markdown += "\n";

        var changedPackages =
        execSync("git log -m --name-only --pretty='format:' " + commit.commitSHA)
        // not sure why it's including extra files
        .split("\n\n")[0]
        // turn into an array
        .split("\n")
        // remove files that aren't in packages/
        .filter(function(files) {
          return files.indexOf("packages/") === 0;
        })
        // extract base package name
        .map(function(files) {
          files = files.slice(9);
          return files.slice(0, files.indexOf("/"));
        })
        // unique packages
        .filter(function(value, index, self) {
          return self.indexOf(value) === index;
        });

        var spaces = 0;

        if (changedPackages.length > 0) {
          markdown += repeat(" ", spaces) + "* ";

          changedPackages.forEach(function(pkg, i) {
            markdown += (i === 0 ? "" : ", ") + "`" + pkg + "`";
          });

          markdown += "\n";

          // indent more?
          spaces = 2;
        }

        if (commit.number) {
          var prUrl = this.remote.getBasePullRequestUrl() + commit.number;
          markdown += repeat(" ", spaces) + "* ";
          markdown += "[#" + commit.number + "](" + prUrl + ")";
        }

        if (commit.title.match(fixesRegex)) {
          commit.title = commit.title.replace(fixesRegex, "Fixes [#$2](" + this.remote.getBaseIssueUrl() + "$2)");
        }

        markdown += " " + commit.title + "." + " ([@" + commit.user.login + "](" + commit.user.html_url + "))";
      });
    });

    progressBar.terminate();

    markdown += "\n\n#### Commiters: " + committers.length + "\n";
    markdown += committers.map(function(commiter) {
      return "- " + commiter;
    }).join("\n");

    return markdown;
  }

  getLastTag() {
    return execSync("git describe --abbrev=0 --tags");
  }

  getListOfCommits() {
    var lastTag = this.getLastTag();
    var commits = execSync("git log --oneline " + lastTag + "..").split("\n");
    return commits;
  }

  getCommitters(commits) {
    var committers = {}

    commits.forEach(commit => {
      const login = (commit.user||{}).login;
      if (login && !committers[login]){
        const user = this.remote.getUserData(login);
        committers[login] = `${user.name} ([${login}](${user.html_url}))`;
      }
    });

    return Object.keys(committers).map(k => committers[k]).sort();
  }

  getCommitInfo() {
    const commits = this.getListOfCommits();

    progressBar.init(commits.length);

    var logs = commits.map(commit => {

      var sha = commit.slice(0, 7);
      var message = commit.slice(8);
      var response;
      progressBar.tick(sha);

      var mergeCommit = message.match(/\(#(\d+)\)$/);

      if (message.indexOf("Merge pull request ") === 0) {
        var start = message.indexOf("#") + 1;
        var end = message.slice(start).indexOf(" ");
        var issueNumber = message.slice(start, start + end);

        response = this.remote.getIssueData(issueNumber);
        response.commitSHA = sha;
        response.mergeMessage = message;
        return response;
      } else if (mergeCommit) {
        var issueNumber = mergeCommit[1];
        response = this.remote.getIssueData(issueNumber);
        response.commitSHA = sha;
        response.mergeMessage = message;
        return response;
      }

      return {
        commitSHA: sha,
        message: message,
        labels: []
      };
    });

    progressBar.terminate();
    return logs;
  }

  getCommitsByCategory(logs) {
    var categories = this.remote.getLabels().map(label => {
      var commits = [];

      logs.forEach(function(log) {
        var labels = log.labels.map(function(label) {
          return label.name;
        });

        if (labels.indexOf(label.toLowerCase()) >= 0) {
          commits.push(log);
        }
      });

      return {
        heading: this.remote.getHeadingForLabel(label),
        commits: commits
      };
    });

    return categories;
  }
}

function toTitleCase(str) {
    return str.replace(/\w\S*/g, function(text){
      return text.charAt(0).toUpperCase() + text.substr(1).toLowerCase();
    });
}

function repeat(str, times) {
  return Array(times + 1).join(str);
}
<|endoftext|>


<commit_before>// Used for on-the-fly transpilation. This is only needed in the
// webpack config file to use ES6
require('babel-register');

const webpack = require('webpack');
const config = require('./webpack.config');

const hostname = 'localhost';
const port = '8080';

config.cache = true;
config.debug = true;
config.devtool = 'inline-source-map';
config.entry.index.unshift(`webpack-dev-server/client?http://${hostname}:${port}/`);

config.plugins = [
  new webpack.HotModuleReplacementPlugin(),
];

config.devServer = {
  hot: true,
  inline: true,
};

module.exports = config;
<commit_msg>Added historyApiFallback<commit_after>// Used for on-the-fly transpilation. This is only needed in the
// webpack config file to use ES6
require('babel-register');

const webpack = require('webpack');
const config = require('./webpack.config');

const hostname = 'localhost';
const port = '8080';

config.cache = true;
config.debug = true;
config.devtool = 'inline-source-map';
config.entry.index.unshift(`webpack-dev-server/client?http://${hostname}:${port}/`);

config.plugins = [
  new webpack.HotModuleReplacementPlugin(),
];

config.devServer = {
  hot: true,
  inline: true,
  historyApiFallback: true,
};

module.exports = config;
<|endoftext|>


<commit_before>var path = require('path');
var webpack = require('webpack');
var StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
var env = process.env.WEBPACK_BUILD || 'development';

var CleanWebpackPlugin = require('clean-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var webpackDevConfig = require('./webpack.base.config')('development');
var webpackProdConfig = require('./webpack.base.config')('production');

var paths = [
  '/',
  '/components',
  '/components/buttons',
  '/components/button-group',
  '/components/button-toolbar',
  '/components/button-dropdown',
  '/components/dropdowns',
  '/components/popovers',
  '/components/tooltips',
  '/components/modals',
  '/components/labels',
  '/404.html'
];

var config = [{
  // context: path.join(__dirname, './lib'),
  devtool: 'source-map',
  devServer: {
    contentBase: './build',
    stats: {
      chunks: false
    }
  },
  entry: {
    main: './docs/lib/app.jsx'
  },
  node: {
    fs: 'empty'
  },
  output: {
    filename: 'bundle.js',
    path: './build',
    libraryTarget: 'umd'
  },
  plugins: [
    new CleanWebpackPlugin(['build']),
    new CopyWebpackPlugin([{ from: './docs/static', to: 'assets' }]),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(env)
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.OccurenceOrderPlugin(),
    new StaticSiteGeneratorPlugin('main', paths, {}),
    new webpack.NoErrorsPlugin(),
    new ExtractTextPlugin("/assets/style.css")
  ],
  module: {
    loaders: [
      {
        test: /\.(json)$/,
        loaders: [
          'json-loader?cacheDirectory'
        ]
      },
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loaders: [
          'babel-loader?cacheDirectory'
        ]
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract("style-loader", "css-loader")
      },
    ]
  },
  resolve: {
    extensions: ['', '.js', '.jsx', '.json'],
    alias: {
      'bootstrap-css': path.join(__dirname,'node_modules/bootstrap/dist/css/bootstrap.css'),
      reactstrap: path.resolve('./lib')
    }
  }
}];

if (env === 'development') {
  config.push(webpackDevConfig);
  config.push(webpackProdConfig);
} else {
  config[0].plugins.push(new webpack.optimize.UglifyJsPlugin(
    {
      minimize: true,
      compress: {
        warnings: false
      },
      mangle: true
    }
  ));
}

module.exports = config;
<commit_msg>style(webpack): switch double quotes for single quotes<commit_after>var path = require('path');
var webpack = require('webpack');
var StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
var env = process.env.WEBPACK_BUILD || 'development';

var CleanWebpackPlugin = require('clean-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var webpackDevConfig = require('./webpack.base.config')('development');
var webpackProdConfig = require('./webpack.base.config')('production');

var paths = [
  '/',
  '/components',
  '/components/buttons',
  '/components/button-group',
  '/components/button-toolbar',
  '/components/button-dropdown',
  '/components/dropdowns',
  '/components/popovers',
  '/components/tooltips',
  '/components/modals',
  '/components/labels',
  '/404.html'
];

var config = [{
  // context: path.join(__dirname, './lib'),
  devtool: 'source-map',
  devServer: {
    contentBase: './build',
    stats: {
      chunks: false
    }
  },
  entry: {
    main: './docs/lib/app.jsx'
  },
  node: {
    fs: 'empty'
  },
  output: {
    filename: 'bundle.js',
    path: './build',
    libraryTarget: 'umd'
  },
  plugins: [
    new CleanWebpackPlugin(['build']),
    new CopyWebpackPlugin([{ from: './docs/static', to: 'assets' }]),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(env)
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.OccurenceOrderPlugin(),
    new StaticSiteGeneratorPlugin('main', paths, {}),
    new webpack.NoErrorsPlugin(),
    new ExtractTextPlugin("/assets/style.css")
  ],
  module: {
    loaders: [
      {
        test: /\.(json)$/,
        loaders: [
          'json-loader?cacheDirectory'
        ]
      },
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loaders: [
          'babel-loader?cacheDirectory'
        ]
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract("style-loader", "css-loader")
      },
    ]
  },
  resolve: {
    extensions: ['', '.js', '.jsx', '.json'],
    alias: {
      'bootstrap-css': path.join(__dirname,'node_modules/bootstrap/dist/css/bootstrap.css'),
      reactstrap: path.resolve('./lib')
    }
  }
}];

if (env === 'development') {
  config.push(webpackDevConfig);
  config.push(webpackProdConfig);
} else {
  config[0].plugins.push(new webpack.optimize.UglifyJsPlugin(
    {
      minimize: true,
      compress: {
        warnings: false
      },
      mangle: true
    }
  ));
}

module.exports = config;
<|endoftext|>