import { setupRerender } from 'preact/test-utils';
import { createElement, render, Component } from '../../../src/index';
import { setupScratch, teardown } from '../../_util/helpers';

/** @jsx createElement */

describe('Lifecycle methods', () => {
	/** @type {HTMLDivElement} */
	let scratch;

	/** @type {() => void} */
	let rerender;

	beforeEach(() => {
		scratch = setupScratch();
		rerender = setupRerender();
	});

	afterEach(() => {
		teardown(scratch);
	});

	describe('#componentWillReceiveProps', () => {
		it('should update state when called setState in componentWillReceiveProps', () => {
			let componentState;

			class Foo extends Component {
				constructor(props) {
					super(props);
					this.state = {
						dummy: 0
					};
				}
				componentDidMount() {
					// eslint-disable-next-line react/no-did-mount-set-state
					this.setState({ dummy: 1 });
				}
				render() {
					return <Bar dummy={this.state.dummy} />;
				}
			}
			class Bar extends Component {
				constructor(props) {
					super(props);
					this.state = {
						value: 0
					};
				}
				componentWillReceiveProps() {
					this.setState({ value: 1 });
				}
				render() {
					componentState = this.state;
					return
;
				}
			}

			render(<Foo />, scratch);
			rerender();

			expect(componentState).to.deep.equal({ value: 1 });

			const cWRP = Foo.prototype.componentWillReceiveProps;
			delete Foo.prototype.componentWillReceiveProps;

			Foo.prototype.shouldComponentUpdate = cWRP;

			render(null, scratch);
			render(<Foo />, scratch);
			rerender();

			expect(componentState, 'via shouldComponentUpdate').to.deep.equal({
				value: 1
			});

			delete Foo.prototype.shouldComponentUpdate;
			Foo.prototype.componentWillUpdate = cWRP;

			render(null, scratch);
			render(<Foo />, scratch);
			rerender();

			expect(componentState, 'via componentWillUpdate').to.deep.equal({
				value: 1
			});
		});

		it('should NOT be called on initial render', () => {
			class ReceivePropsComponent extends Component {
				componentWillReceiveProps() {}
				render() {
					return
;
				}
			}
			sinon.spy(ReceivePropsComponent.prototype, 'componentWillReceiveProps');
			render(<ReceivePropsComponent />, scratch);
			expect(ReceivePropsComponent.prototype.componentWillReceiveProps).not.to
				.have.been.called;
		});

		// See last paragraph of cWRP section https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
		it('should not be called on setState or forceUpdate', () => {
			let spy = sinon.spy();
			let spyInner = sinon.spy();
			let c;

			class Inner extends Component {
				componentWillReceiveProps() {
					spyInner();
				}

				render() {
					return
foo
;
				}
			}

			class Outer extends Component {
				constructor() {
					super();
					c = this;
				}

				componentWillReceiveProps() {
					spy();
				}

				render() {
					return <Inner />;
				}
			}

			render(<Outer />, scratch);
			expect(spy).to.not.be.called;

			c.setState({});
			rerender();
			expect(spy).to.not.be.called;
			expect(spyInner).to.be.calledOnce;
			spy.resetHistory();
			spyInner.resetHistory();

			c.forceUpdate();
			rerender();
			expect(spy).to.not.be.called;
			expect(spyInner).to.be.calledOnce;
		});

		it('should be called when rerender with new props from parent', () => {
			let doRender;
			class Outer extends Component {
				constructor(p, c) {
					super(p, c);
					this.state = { i: 0 };
				}
				componentDidMount() {
					doRender = () => this.setState({ i: this.state.i + 1 });
				}
				render(props, { i }) {
					return <Inner i={i} {...props} />;
				}
			}
			class Inner extends Component {
				componentWillMount() {
					expect(this.props.i).to.be.equal(0);
				}
				componentWillReceiveProps(nextProps) {
					expect(nextProps.i).to.be.equal(1);
				}
				render() {
					return
;
				}
			}
			sinon.spy(Inner.prototype, 'componentWillReceiveProps');
			sinon.spy(Outer.prototype, 'componentDidMount');

			// Initial render
			render(<Outer />, scratch);
			expect(Inner.prototype.componentWillReceiveProps).not.to.have.been.called;

			// Rerender inner with new props
			doRender();
			rerender();
			expect(Inner.prototype.componentWillReceiveProps).to.have.been.called;
		});

		it('should be called in right execution order', () => {
			let doRender;
			class Outer extends Component {
				constructor(p, c) {
					super(p, c);
					this.state = { i: 0 };
				}
				componentDidMount() {
					doRender = () => this.setState({ i: this.state.i + 1 });
				}
				render(props, { i }) {
					return <Inner i={i} {...props} />;
				}
			}
			class Inner extends Component {
				componentDidUpdate() {
					expect(Inner.prototype.componentWillReceiveProps).to.have.been.called;
					expect(Inner.prototype.componentWillUpdate).to.have.been.called;
				}
				componentWillReceiveProps() {
					expect(Inner.prototype.componentWillUpdate).not.to.have.been.called;
					expect(Inner.prototype.componentDidUpdate).not.to.have.been.called;
				}
				componentWillUpdate() {
					expect(Inner.prototype.componentWillReceiveProps).to.have.been.called;
					expect(Inner.prototype.componentDidUpdate).not.to.have.been.called;
				}
				shouldComponentUpdate() {
					expect(Inner.prototype.componentWillReceiveProps).to.have.been.called;
					expect(Inner.prototype.componentWillUpdate).not.to.have.been.called;
					return true;
				}
				render() {
					return
;
				}
			}
			sinon.spy(Inner.prototype, 'componentWillReceiveProps');
			sinon.spy(Inner.prototype, 'componentDidUpdate');
			sinon.spy(Inner.prototype, 'componentWillUpdate');
			sinon.spy(Inner.prototype, 'shouldComponentUpdate');
			sinon.spy(Outer.prototype, 'componentDidMount');

			render(<Outer />, scratch);
			doRender();
			rerender();

			expect(
				Inner.prototype.componentWillReceiveProps
			).to.have.been.calledBefore(Inner.prototype.componentWillUpdate);
			expect(
				Inner.prototype.componentWillReceiveProps
			).to.have.been.calledBefore(Inner.prototype.shouldComponentUpdate);
			expect(Inner.prototype.componentWillUpdate).to.have.been.calledBefore(
				Inner.prototype.componentDidUpdate
			);
		});
	});
});


keep replace replace replace keep keep keep

import { EMPTY_OBJ, EMPTY_ARR } from '../constants';
import { Component, enqueueRender } from '../component';
import { Fragment } from '../create-element';
import { diffChildren, toChildArray } from './children';
import { diffProps } from './props';
import { assign, removeNode } from '../util';
import options from '../options';

/**
 * Diff two virtual nodes and apply proper changes to the DOM
 * @param {import('../internal').PreactElement} parentDom The parent of the DOM element
 * @param {import('../internal').VNode} newVNode The new virtual node
 * @param {import('../internal').VNode} oldVNode The old virtual node
 * @param {object} context The current context object
 * @param {boolean} isSvg Whether or not this element is an SVG node
 * @param {Array<import('../internal').PreactElement>} excessDomChildren
 * @param {Array<import('../internal').Component>} commitQueue List of components
 * which have callbacks to invoke in commitRoot
 * @param {Element | Text} oldDom The current attached DOM
 * element any new dom elements should be placed around. Likely `null` on first
 * render (except when hydrating). Can be a sibling DOM element when diffing
 * Fragments that have siblings. In most cases, it starts out as `oldChildren[0]._dom`.
 * @param {boolean} [isHydrating] Whether or not we are in hydration
 */
export function diff(
	parentDom,
	newVNode,
	oldVNode,
	context,
	isSvg,
	excessDomChildren,
	commitQueue,
	oldDom,
	isHydrating
) {
	let tmp,
		newType = newVNode.type;

	// When passing through createElement it assigns the object
	// constructor as undefined. This to prevent JSON-injection.
	if (newVNode.constructor !== undefined) return null;

	if ((tmp = options._diff)) tmp(newVNode);

	try {
		outer: if (typeof newType === 'function') {
			let c, isNew, oldProps, oldState, snapshot, clearProcessingException;
			let newProps = newVNode.props;

			// Necessary for createContext api. Setting this property will pass
			// the context value as `this.context` just for this component.
			tmp = newType.contextType;
			let provider = tmp && context[tmp._id];
			let cctx = tmp
				? provider
					? provider.props.value
					: tmp._defaultValue
				: context;

			// Get component and set it to `c`
			if (oldVNode._component) {
				c = newVNode._component = oldVNode._component;
				clearProcessingException = c._processingException = c._pendingError;
			} else {
				// Instantiate the new component
				if ('prototype' in newType && newType.prototype.render) {
					newVNode._component = c = new newType(newProps, cctx); // eslint-disable-line new-cap
				} else {
					newVNode._component = c = new Component(newProps, cctx);
					c.constructor = newType;
					c.render = doRender;
				}
				if (provider) provider.sub(c);

				c.props = newProps;
				if (!c.state) c.state = {};
				c.context = cctx;
				c._context = context;
				isNew = c._dirty = true;
				c._renderCallbacks = [];
			}

			// Invoke getDerivedStateFromProps
			if (c._nextState == null) {
				c._nextState = c.state;
			}
			if (newType.getDerivedStateFromProps != null) {
				assign(
					c._nextState == c.state
						? (c._nextState = assign({}, c._nextState))
						: c._nextState,
					newType.getDerivedStateFromProps(newProps, c._nextState)
				);
			}

			oldProps = c.props;
			oldState = c.state;

			// Invoke pre-render lifecycle methods
			if (isNew) {
				if (
					newType.getDerivedStateFromProps == null &&
					c.componentWillMount != null
				) {
					c.componentWillMount();
				}

				if (c.componentDidMount != null) {
					c._renderCallbacks.push(c.componentDidMount);
				}
			} else {
				if (
					newType.getDerivedStateFromProps == null &&
					c._force == null &&
					c.componentWillReceiveProps != null
				) {
					c.componentWillReceiveProps(newProps, cctx);
				}

				if (
					!c._force &&
					c.shouldComponentUpdate != null &&
					c.shouldComponentUpdate(newProps, c._nextState, cctx) === false
				) {
					c.props = newProps;
					c.state = c._nextState;
					c._dirty = false;
					c._vnode = newVNode;
					newVNode._dom = oldVNode._dom;
					newVNode._children = oldVNode._children;
					for (tmp = 0; tmp < newVNode._children.length; tmp++) {
						if (newVNode._children[tmp]) {
							newVNode._children[tmp]._parent = newVNode;
						}
					}
					break outer;
				}

				if (c.componentWillUpdate != null) {
					c.componentWillUpdate(newProps, c._nextState, cctx);
				}

				if (c.componentDidUpdate != null) {
					c._renderCallbacks.push(() => {
						c.componentDidUpdate(oldProps, oldState, snapshot);
					});
				}
			}

			c.context = cctx;
			c.props = newProps;
			c.state = c._nextState;

			if ((tmp = options._render)) tmp(newVNode);

			c._dirty = false;
			c._vnode = newVNode;
			c._parentDom = parentDom;

			tmp = c.render(c.props, c.state, c.context);
			let isTopLevelFragment =
				tmp != null && tmp.type == Fragment && tmp.key == null;
			newVNode._children = toChildArray(
				isTopLevelFragment ? tmp.props.children : tmp
			);

			if (c.getChildContext != null) {
				context = assign(assign({}, context), c.getChildContext());
			}

			if (!isNew && c.getSnapshotBeforeUpdate != null) {
				snapshot = c.getSnapshotBeforeUpdate(oldProps, oldState);
			}

			diffChildren(
				parentDom,
				newVNode,
				oldVNode,
				context,
				isSvg,
				excessDomChildren,
				commitQueue,
				oldDom,
				isHydrating
			);

			c.base = newVNode._dom;

			if (c._renderCallbacks.length) {
				commitQueue.push(c);
			}

			if (clearProcessingException) {
				c._pendingError = c._processingException = null;
			}

			c._force = null;
		} else {
			newVNode._dom = diffElementNodes(
				oldVNode._dom,
				newVNode,
				oldVNode,
				context,
				isSvg,
				excessDomChildren,
				commitQueue,
				isHydrating
			);
		}

		if ((tmp = options.diffed)) tmp(newVNode);
	} catch (e) {
		options._catchError(e, newVNode, oldVNode);
	}

	return newVNode._dom;
}

/**
 * @param {Array<import('../internal').Component>} commitQueue List of components
 * which have callbacks to invoke in commitRoot
 * @param {import('../internal').VNode} root
 */
export function commitRoot(commitQueue, root) {
	if (options._commit) options._commit(root, commitQueue);

	commitQueue.some(c => {
		try {
			commitQueue = c._renderCallbacks;
			c._renderCallbacks = [];
			commitQueue.some(cb => {
				cb.call(c);
			});
		} catch (e) {
			options._catchError(e, c._vnode);
		}
	});
}

/**
 * Diff two virtual nodes representing DOM element
 * @param {import('../internal').PreactElement} dom The DOM element representing
 * the virtual nodes being diffed
 * @param {import('../internal').VNode} newVNode The new virtual node
 * @param {import('../internal').VNode} oldVNode The old virtual node
 * @param {object} context The current context object
 * @param {boolean} isSvg Whether or not this DOM node is an SVG node
 * @param {*} excessDomChildren
 * @param {Array<import('../internal').Component>} commitQueue List of components
 * which have callbacks to invoke in commitRoot
 * @param {boolean} isHydrating Whether or not we are in hydration
 * @returns {import('../internal').PreactElement}
 */
function diffElementNodes(
	dom,
	newVNode,
	oldVNode,
	context,
	isSvg,
	excessDomChildren,
	commitQueue,
	isHydrating
) {
	let i;
	let oldProps = oldVNode.props;
	let newProps = newVNode.props;

	// Tracks entering and exiting SVG namespace when descending through the tree.
	isSvg = newVNode.type === 'svg' || isSvg;

	if (dom == null && excessDomChildren != null) {
		for (i = 0; i < excessDomChildren.length; i++) {
			const child = excessDomChildren[i];

			if (
				child != null &&
				(newVNode.type === null
					? child.nodeType === 3
					: child.localName === newVNode.type)
			) {
				dom = child;
				excessDomChildren[i] = null;
				break;
			}
		}
	}

	if (dom == null) {
		if (newVNode.type === null) {
			return document.createTextNode(newProps);
		}
		dom = isSvg
			? document.createElementNS('http://www.w3.org/2000/svg', newVNode.type)
			: document.createElement(newVNode.type);
		// we created a new parent, so none of the previously attached children can be reused:
		excessDomChildren = null;
	}

	if (newVNode.type === null) {
		if (excessDomChildren != null)
			excessDomChildren[excessDomChildren.indexOf(dom)] = null;
		if (oldProps !== newProps) {
			dom.data = newProps;
		}
	} else if (newVNode !== oldVNode) {
		if (excessDomChildren != null) {
			excessDomChildren = EMPTY_ARR.slice.call(dom.childNodes);
		}

		oldProps = oldVNode.props || EMPTY_OBJ;

		let oldHtml = oldProps.dangerouslySetInnerHTML;
		let newHtml = newProps.dangerouslySetInnerHTML;

		// During hydration, props are not diffed at all (including dangerouslySetInnerHTML)
		// @TODO we should warn in debug mode when props don't match here.
		if (!isHydrating) {
			if (oldProps === EMPTY_OBJ) {
				oldProps = {};
				for (let i = 0; i < dom.attributes.length; i++) {
					oldProps[dom.attributes[i].name] = dom.attributes[i].value;
				}
			}

			if (newHtml || oldHtml) {
				// Avoid re-applying the same '__html' if it did not changed between re-render
				if (!newHtml || !oldHtml || newHtml.__html != oldHtml.__html) {
					dom.innerHTML = (newHtml && newHtml.__html) || '';
				}
			}
		}

		diffProps(dom, newProps, oldProps, isSvg, isHydrating);

		newVNode._children = newVNode.props.children;

		// If the new vnode didn't have dangerouslySetInnerHTML, diff its children
		if (!newHtml) {
			diffChildren(
				dom,
				newVNode,
				oldVNode,
				context,
				newVNode.type === 'foreignObject' ? false : isSvg,
				excessDomChildren,
				commitQueue,
				EMPTY_OBJ,
				isHydrating
			);
		}

		// (as above, don't diff props during hydration)
		if (!isHydrating) {
			if (
				'value' in newProps &&
				newProps.value !== undefined &&
				newProps.value !== dom.value
			)
				dom.value = newProps.value == null ? '' : newProps.value;
			if (
				'checked' in newProps &&
				newProps.checked !== undefined &&
				newProps.checked !== dom.checked
			)
				dom.checked = newProps.checked;
		}
	}

	return dom;
}

/**
 * Invoke or update a ref, depending on whether it is a function or object ref.
 * @param {object|function} ref
 * @param {any} value
 * @param {import('../internal').VNode} vnode
 */
export function applyRef(ref, value, vnode) {
	try {
		if (typeof ref == 'function') ref(value);
		else ref.current = value;
	} catch (e) {
		options._catchError(e, vnode);
	}
}

/**
 * Unmount a virtual node from the tree and apply DOM changes
 * @param {import('../internal').VNode} vnode The virtual node to unmount
 * @param {import('../internal').VNode} parentVNode The parent of the VNode that
 * initiated the unmount
 * @param {boolean} [skipRemove] Flag that indicates that a parent node of the
 * current element is already detached from the DOM.
 */
export function unmount(vnode, parentVNode, skipRemove) {
	let r;
	if (options.unmount) options.unmount(vnode);

	if ((r = vnode.ref)) {
		applyRef(r, null, parentVNode);
	}

	let dom;
	if (!skipRemove && typeof vnode.type !== 'function') {
		skipRemove = (dom = vnode._dom) != null;
	}

	vnode._dom = vnode._lastDomChild = null;

	if ((r = vnode._component) != null) {
		if (r.componentWillUnmount) {
			try {
				r.componentWillUnmount();
			} catch (e) {
				options._catchError(e, parentVNode);
			}
		}

		r.base = r._parentDom = null;
	}

	if ((r = vnode._children)) {
		for (let i = 0; i < r.length; i++) {
			if (r[i]) unmount(r[i], parentVNode, skipRemove);
		}
	}

	if (dom != null) removeNode(dom);
}

/** The `.render()` method for a PFC backing instance. */
function doRender(props, state, context) {
	return this.constructor(props, context);
}

/**
 * Find the closest error boundary to a thrown error and call it
 * @param {object} error The thrown value
 * @param {import('../internal').VNode} vnode The vnode that threw
 * the error that was caught (except for unmounting when this parameter
 * is the highest parent that was being unmounted)
 * @param {import('../internal').VNode} oldVNode The oldVNode of the vnode
 * that threw, if this VNode threw while diffing
 */
options._catchError = function(error, vnode, oldVNode) {
	/** @type {import('../internal').Component} */
	let component;

	for (; (vnode = vnode._parent); ) {
		if ((component = vnode._component) && !component._processingException) {
			try {
				if (
					component.constructor &&
					component.constructor.getDerivedStateFromError != null
				) {
					component.setState(
						component.constructor.getDerivedStateFromError(error)
					);
				} else if (component.componentDidCatch != null) {
					component.componentDidCatch(error);
				} else {
					continue;
				}
				return enqueueRender((component._pendingError = component));
			} catch (e) {
				error = e;
			}
		}
	}

	throw error;
};


import { createElement as h, options } from '../../src';
import { assign } from '../../src/util';
import { clearLog, getLog } from './logCall';
import { teardown as testUtilTeardown } from 'preact/test-utils';

/** @jsx h */

export function supportsPassiveEvents() {
	let supported = false;
	try {
		let options = {
			get passive() {
				supported = true;
				return undefined;
			}
		};

		window.addEventListener('test', options, options);
		window.removeEventListener('test', options, options);
	} catch (err) {
		supported = false;
	}
	return supported;
}

export function supportsDataList() {
	return (
		'list' in document.createElement('input') &&
		Boolean(
			document.createElement('datalist') && 'HTMLDataListElement' in window
		)
	);
}

const VOID_ELEMENTS = /^(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/;

function encodeEntities(str) {
	return str.replace(/&/g, '&');
}

/**
 * Normalize svg paths spacing. Some browsers insert spaces around letters,
 * others do not.
 * @param {string} str
 * @returns {string}
 */
function normalizePath(str) {
	let len = str.length;
	let out = '';
	for (let i = 0; i < len; i++) {
		const char = str[i];
		if (/[A-Za-z]/.test(char)) {
			if (i == 0) out += char + ' ';
			else
				out += (str[i - 1] == ' ' ? '' : ' ') + char + (i < len - 1 ? ' ' : '');
		} else if (char == '-' && str[i - 1] !== ' ') out += ' ' + char;
		else out += char;
	}

	return out.replace(/\s\s+/g, ' ').replace(/z/g, 'Z');
}

export function serializeHtml(node) {
	let str = '';
	let child = node.firstChild;
	while (child) {
		str += serializeDomTree(child);
		child = child.nextSibling;
	}
	return str;
}

/**
 * Serialize a DOM tree.
 * Uses deterministic sorting where necessary to ensure consistent tests.
 * @param {Element|Node} node	The root node to serialize
 * @returns {string} html
 */
function serializeDomTree(node) {
	if (node.nodeType === 3) {
		return encodeEntities(node.data);
	} else if (node.nodeType === 8) {
		return '';
	} else if (node.nodeType === 1 || node.nodeType === 9) {
		let str = '<' + node.localName;
		const attrs = [];
		for (let i = 0; i < node.attributes.length; i++) {
			attrs.push(node.attributes[i].name);
		}
		attrs.sort();
		for (let i = 0; i < attrs.length; i++) {
			const name = attrs[i];
			let value = node.getAttribute(name);
			if (value == null) continue;
			if (!value && name === 'class') continue;
			str += ' ' + name;
			value = encodeEntities(value);

			// normalize svg <path d="value">
			if (node.localName === 'path' && name === 'd') {
				value = normalizePath(value);
			}
			str += '="' + value + '"';
		}
		str += '>';
		if (!VOID_ELEMENTS.test(node.localName)) {
			let child = node.firstChild;
			while (child) {
				str += serializeDomTree(child);
				child = child.nextSibling;
			}
			str += '</' + node.localName + '>';
		}
		return str;
	}
}

/**
 * Normalize event creation in browsers
 * @param {string} name
 * @returns {Event}
 */
export function createEvent(name) {
	// Modern browsers
	if (typeof Event === 'function') {
		return new Event(name);
	}

	// IE 11...
	let event = document.createEvent('Event');
	event.initEvent(name, true, true);
	return event;
}

/**
 * Sort a cssText alphabetically.
 * @param {string} cssText
 */
export function sortCss(cssText) {
	return (
		cssText
			.split(';')
			.filter(Boolean)
			.map(s => s.replace(/^\s+|\s+$/g, '').replace(/(\s*:\s*)/g, ': '))
			.sort((a, b) => {
				// CSS Variables are typically positioned at the start
				if (a[0] === '-') {
					// If both are a variable we just compare them
					if (b[0] === '-') return a.localeCompare(b);
					return -1;
				}
				// b is a css var
				if (b[0] === '-') return 1;

				return a.localeCompare(b);
			})
			.join('; ') + ';'
	);
}

/**
 * Setup the test environment
 * @returns {HTMLDivElement}
 */
export function setupScratch() {
	const scratch = document.createElement('div');
	scratch.id = 'scratch';
	(document.body || document.documentElement).appendChild(scratch);
	return scratch;
}

let oldOptions = null;
export function clearOptions() {
	oldOptions = assign({}, options);
	delete options.vnode;
	delete options.diffed;
	delete options.unmount;
	delete options._diff;
}

/**
 * Teardown test environment and reset preact's internal state
 * @param {HTMLDivElement} scratch
 */
export function teardown(scratch) {
	if (scratch) {
		scratch.parentNode.removeChild(scratch);
	}

	if (oldOptions != null) {
		assign(options, oldOptions);
		oldOptions = null;
	}

	testUtilTeardown();

	if (getLog().length > 0) {
		clearLog();
	}
}

const Foo = () => 'd';
export const getMixedArray = () =>
	// Make it a function so each test gets a new copy of the array
	[0, 'a', 'b', c, <Foo />, null, undefined, false, ['e', 'f'], 1];
export const mixedArrayHTML = '0abcdef1';

/**
 * Reset obj to empty to keep reference
 * @param {object} obj
 */
export function clear(obj) {
	Object.keys(obj).forEach(key => delete obj[key]);
}

/**
 * Hacky normalization of attribute order across browsers.
 * @param {string} html
 */
export function sortAttributes(html) {
	return html.replace(
		/<([a-z0-9-]+)((?:\s[a-z0-9:_.-]+=".*?")+)((?:\s*\/)?>)/gi,
		(s, pre, attrs, after) => {
			let list = attrs
				.match(/\s[a-z0-9:_.-]+=".*?"/gi)
				.sort((a, b) => (a > b ? 1 : -1));
			if (~after.indexOf('/')) after = '></' + pre + '>';
			return '<' + pre + list.join('') + after;
		}
	);
}

export const spyAll = obj =>
	Object.keys(obj).forEach(key => sinon.spy(obj, key));
export const resetAllSpies = obj =>
	Object.keys(obj).forEach(key => {
		if (obj[key].args) {
			obj[key].resetHistory();
		}
	});


import { initDebug } from './debug';
import { initDevTools } from './devtools';

if (process.env.NODE_ENV === 'development') {
	initDebug();
	initDevTools();
}


import {
	createElement as h,
	render,
	createPortal,
	useState,
	Component
} from '../../src';
import { setupScratch, teardown } from '../../../test/_util/helpers';
import { setupRerender } from 'preact/test-utils';
/* eslint-disable react/jsx-boolean-value, react/display-name, prefer-arrow-callback */

/** @jsx h */
describe('Portal', () => {
	/** @type {HTMLDivElement} */
	let scratch;
	let rerender;

	beforeEach(() => {
		scratch = setupScratch();
		rerender = setupRerender();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it('should render into a different root node', () => {
		let root = document.createElement('div');
		document.body.appendChild(root);

		function Foo(props) {
			return
{createPortal(props.children, root)}
;
		}
		render(<Foo>foobar</Foo>, scratch);

		expect(root.innerHTML).to.equal('foobar');

		root.parentNode.removeChild(root);
	});

	it('should insert the portal', () => {
		let setFalse;
		function Foo(props) {
			const [mounted, setMounted] = useState(true);
			setFalse = () => setMounted(() => false);
			return (

Hello

					{mounted && createPortal(props.children, scratch)}

			);
		}
		render(<Foo>foobar</Foo>, scratch);
		expect(scratch.innerHTML).to.equal('foobar

Hello

');

		setFalse();
		rerender();
		expect(scratch.innerHTML).to.equal('

Hello

');
	});

	it('should toggle the portal', () => {
		let toggle;

		function Foo(props) {
			const [mounted, setMounted] = useState(true);
			toggle = () => setMounted(s => !s);
			return (

Hello

					{mounted && createPortal(props.children, scratch)}

			);
		}

		render(
			<Foo>

foobar

			</Foo>,
			scratch
		);
		expect(scratch.innerHTML).to.equal(
			'
foobar

Hello

'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal('

Hello

');

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar
'
		);
	});

	it('should notice prop changes on the portal', () => {
		let set;

		function Foo(props) {
			const [additionalProps, setProps] = useState({
				style: { backgroundColor: 'red' }
			});
			set = c => setProps(c);
			return (

Hello

					{createPortal(
Foo
, scratch)}

			);
		}

		render(<Foo />, scratch);
		expect(scratch.firstChild.style.backgroundColor).to.equal('red');

		set({});
		rerender();
		expect(scratch.firstChild.style.backgroundColor).to.equal('');
	});

	it('should not unmount the portal component', () => {
		let spy = sinon.spy();
		let set;
		class Child extends Component {
			componentWillUnmount() {
				spy();
			}

			render(props) {
				return props.children;
			}
		}

		function Foo(props) {
			const [additionalProps, setProps] = useState({
				style: { background: 'red' }
			});
			set = c => setProps(c);
			return (

Hello

					{createPortal(<Child {...additionalProps}>Foo</Child>, scratch)}

			);
		}

		render(<Foo />, scratch);
		expect(spy).not.to.be.called;

		set({});
		rerender();
		expect(spy).not.to.be.called;
	});

	it('should not render <undefined> for Portal nodes', () => {
		let root = document.createElement('div');
		let dialog = document.createElement('div');
		dialog.id = 'container';

		scratch.appendChild(root);
		scratch.appendChild(dialog);

		function Dialog() {
			return
Dialog content
;
		}

		function App() {
			return
{createPortal(<Dialog />, dialog)}
;
		}

		render(<App />, root);
		expect(scratch.firstChild.firstChild.childNodes.length).to.equal(0);
	});

	it('should unmount Portal', () => {
		let root = document.createElement('div');
		let dialog = document.createElement('div');
		dialog.id = 'container';

		scratch.appendChild(root);
		scratch.appendChild(dialog);

		function Dialog() {
			return
Dialog content
;
		}

		function App() {
			return
{createPortal(<Dialog />, dialog)}
;
		}

		render(<App />, root);
		expect(dialog.childNodes.length).to.equal(2);
		render(null, root);
		expect(dialog.childNodes.length).to.equal(0);
	});

	it('should leave a working root after the portal', () => {
		let toggle, toggle2;

		function Foo(props) {
			const [mounted, setMounted] = useState(false);
			const [mounted2, setMounted2] = useState(true);
			toggle = () => setMounted(s => !s);
			toggle2 = () => setMounted2(s => !s);
			return (

					{mounted && createPortal(props.children, scratch)}
					{mounted2 &&
Hello
}

			);
		}

		render(
			<Foo>

foobar

			</Foo>,
			scratch
		);
		expect(scratch.innerHTML).to.equal('

Hello

');

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar
'
		);

		toggle2();
		rerender();
		expect(scratch.innerHTML).to.equal('

foobar
');

		toggle2();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar
'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal('

Hello

');

		toggle2();
		rerender();
		expect(scratch.innerHTML).to.equal('

');
	});

	it('should work with stacking portals', () => {
		let toggle, toggle2;

		function Foo(props) {
			const [mounted, setMounted] = useState(false);
			const [mounted2, setMounted2] = useState(false);
			toggle = () => setMounted(s => !s);
			toggle2 = () => setMounted2(s => !s);
			return (

Hello

					{mounted && createPortal(props.children, scratch)}
					{mounted2 && createPortal(props.children2, scratch)}

			);
		}

		render(
			<Foo children2={
foobar2
}>

foobar

			</Foo>,
			scratch
		);
		expect(scratch.innerHTML).to.equal('

Hello

');

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar
'
		);

		toggle2();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar

foobar2
'
		);

		toggle2();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar
'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal('

Hello

');
	});

	it('should work with changing the container', () => {
		let set, ref;

		function Foo(props) {
			const [container, setContainer] = useState(scratch);
			set = setContainer;

			return (

 {
						ref = r;
					}}
				>

Hello

					{createPortal(props.children, container)}

			);
		}

		render(
			<Foo>

foobar

			</Foo>,
			scratch
		);
		expect(scratch.innerHTML).to.equal(
			'
foobar

Hello

'
		);

		set(() => ref);
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar

'
		);
	});

	it('should work with replacing placeholder portals', () => {
		let toggle, toggle2;

		function Foo(props) {
			const [mounted, setMounted] = useState(false);
			const [mounted2, setMounted2] = useState(false);
			toggle = () => setMounted(s => !s);
			toggle2 = () => setMounted2(s => !s);
			return (

Hello

					{createPortal(mounted && props.children, scratch)}
					{createPortal(mounted2 && props.children, scratch)}

			);
		}

		render(
			<Foo>

foobar

			</Foo>,
			scratch
		);
		expect(scratch.innerHTML).to.equal('

Hello

');

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar
'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal('

Hello

');

		toggle2();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

foobar
'
		);

		toggle2();
		rerender();
		expect(scratch.innerHTML).to.equal('

Hello

');
	});

	it('should work with removing an element from stacked container to new one', () => {
		let toggle, root2;

		function Foo(props) {
			const [root, setRoot] = useState(scratch);
			toggle = () => setRoot(() => root2);
			return (

 {
						root2 = r;
					}}
				>

Hello

					{createPortal(props.children, scratch)}
					{createPortal(props.children, root)}

			);
		}

		render(
			<Foo>

foobar

			</Foo>,
			scratch
		);
		expect(scratch.innerHTML).to.equal(
			'
foobar

foobar

Hello

'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'
foobar

Hello

foobar

'
		);
	});

	it('should support nested portals', () => {
		let toggle, toggle2, inner;

		function Bar() {
			const [mounted, setMounted] = useState(false);
			toggle2 = () => setMounted(s => !s);
			return (

 {
						inner = r;
					}}
				>

Inner

					{mounted && createPortal(
hiFromBar
, scratch)}
					{mounted && createPortal(
innerPortal
, inner)}

			);
		}

		function Foo(props) {
			const [mounted, setMounted] = useState(false);
			toggle = () => setMounted(s => !s);
			return (

Hello

					{mounted && createPortal(<Bar />, scratch)}

			);
		}

		render(<Foo />, scratch);
		expect(scratch.innerHTML).to.equal('

Hello

');

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

Inner

'
		);

		toggle2();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Hello

Inner

innerPortal

hiFromBar
'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal('

Hello

');
	});

	it('should not unmount when parent renders', () => {
		let root = document.createElement('div');
		let dialog = document.createElement('div');
		dialog.id = 'container';

		scratch.appendChild(root);
		scratch.appendChild(dialog);

		let spy = sinon.spy();
		class Child extends Component {
			componentDidMount() {
				spy();
			}

			render() {
				return
child
;
			}
		}

		let spyParent = sinon.spy();
		class App extends Component {
			componentDidMount() {
				spyParent();
			}
			render() {
				return
{createPortal(<Child />, dialog)}
;
			}
		}

		render(<App />, root);
		let dom = document.getElementById('child');
		expect(spyParent).to.be.calledOnce;
		expect(spy).to.be.calledOnce;

		// Render twice to trigger update scenario
		render(<App />, root);
		render(<App />, root);

		let domNew = document.getElementById('child');
		expect(dom).to.equal(domNew);
		expect(spyParent).to.be.calledOnce;
		expect(spy).to.be.calledOnce;
	});

	it('should switch between non portal and portal node (Modal as lastChild)', () => {
		let toggle;
		const Modal = ({ children, open }) =>
			open ? createPortal(
{children}
, scratch) :
Closed
;

		const App = () => {
			const [open, setOpen] = useState(false);
			toggle = setOpen.bind(this, x => !x);
			return (

					<button onClick={() => setOpen(!open)}>Show</button>
					{open ? 'Open' : 'Closed'}
					<Modal open={open}>Hello</Modal>

			);
		};

		render(<App />, scratch);
		expect(scratch.innerHTML).to.equal(
			'
<button>Show</button>Closed
Closed

'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'
<button>Show</button>Open

Hello
'
		);
	});

	it('should switch between non portal and portal node (Modal as firstChild)', () => {
		let toggle;
		const Modal = ({ children, open }) =>
			open ? createPortal(
{children}
, scratch) :
Closed
;

		const App = () => {
			const [open, setOpen] = useState(false);
			toggle = setOpen.bind(this, x => !x);
			return (

					<Modal open={open}>Hello</Modal>
					<button onClick={() => setOpen(!open)}>Show</button>
					{open ? 'Open' : 'Closed'}

			);
		};

		render(<App />, scratch);
		expect(scratch.innerHTML).to.equal(
			'

Closed
<button>Show</button>Closed
'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'
<button>Show</button>Open

Hello
'
		);

		toggle();
		rerender();
		expect(scratch.innerHTML).to.equal(
			'

Closed
<button>Show</button>Closed
'
		);
	});
});


import { IS_NON_DIMENSIONAL } from '../constants';
import options from '../options';

/**
 * Diff the old and new properties of a VNode and apply changes to the DOM node
 * @param {import('../internal').PreactElement} dom The DOM node to apply
 * changes to
 * @param {object} newProps The new props
 * @param {object} oldProps The old props
 * @param {boolean} isSvg Whether or not this node is an SVG node
 * @param {boolean} hydrate Whether or not we are in hydration mode
 */
export function diffProps(dom, newProps, oldProps, isSvg, hydrate) {
	let i;

	for (i in oldProps) {
		if (!(i in newProps)) {
			setProperty(dom, i, null, oldProps[i], isSvg);
		}
	}

	for (i in newProps) {
		if (
			(!hydrate || typeof newProps[i] == 'function') &&
			i !== 'value' &&
			i !== 'checked' &&
			oldProps[i] !== newProps[i]
		) {
			setProperty(dom, i, newProps[i], oldProps[i], isSvg);
		}
	}
}

function setStyle(style, key, value) {
	if (key[0] === '-') {
		style.setProperty(key, value);
	} else {
		style[key] =
			typeof value === 'number' && IS_NON_DIMENSIONAL.test(key) === false
				? value + 'px'
				: value == null
				? ''
				: value;
	}
}

/**
 * Set a property value on a DOM node
 * @param {import('../internal').PreactElement} dom The DOM node to modify
 * @param {string} name The name of the property to set
 * @param {*} value The value to set the property to
 * @param {*} oldValue The old value the property had
 * @param {boolean} isSvg Whether or not this DOM node is an SVG node or not
 */
function setProperty(dom, name, value, oldValue, isSvg) {
	name = isSvg
		? name === 'className'
			? 'class'
			: name
		: name === 'class'
		? 'className'
		: name;

	if (name === 'key' || name === 'children') {
	} else if (name === 'style') {
		const s = dom.style;

		if (typeof value === 'string') {
			s.cssText = value;
		} else {
			if (typeof oldValue === 'string') {
				s.cssText = '';
				oldValue = null;
			}

			if (oldValue)
				for (let i in oldValue) {
					if (!(value && i in value)) {
						setStyle(s, i, '');
					}
				}

			if (value)
				for (let i in value) {
					if (!oldValue || value[i] !== oldValue[i]) {
						setStyle(s, i, value[i]);
					}
				}
		}
	}
	// Benchmark for comparison: https://esbench.com/bench/574c954bdb965b9a00965ac6
	else if (name[0] === 'o' && name[1] === 'n') {
		let useCapture = name !== (name = name.replace(/Capture$/, ''));
		let nameLower = name.toLowerCase();
		name = (nameLower in dom ? nameLower : name).slice(2);

		if (value) {
			if (!oldValue) dom.addEventListener(name, eventProxy, useCapture);
			(dom._listeners || (dom._listeners = {}))[name] = value;
		} else {
			dom.removeEventListener(name, eventProxy, useCapture);
		}
	} else if (
		name !== 'list' &&
		name !== 'tagName' &&
		// HTMLButtonElement.form and HTMLInputElement.form are read-only but can be set using
		// setAttribute
		name !== 'form' &&
		!isSvg &&
		name in dom
	) {
		dom[name] = value == null ? '' : value;
	} else if (
		typeof value !== 'function' &&
		name !== 'dangerouslySetInnerHTML'
	) {
		if (name !== (name = name.replace(/^xlink:?/, ''))) {
			if (value == null || value === false) {
				dom.removeAttributeNS(
					'http://www.w3.org/1999/xlink',
					name.toLowerCase()
				);
			} else {
				dom.setAttributeNS(
					'http://www.w3.org/1999/xlink',
					name.toLowerCase(),
					value
				);
			}
		} else if (value == null || value === false) {
			dom.removeAttribute(name);
		} else {
			dom.setAttribute(name, value);
		}
	}
}

/**
 * Proxy an event to hooked event handlers
 * @param {Event} e The event object from the browser
 * @private
 */
function eventProxy(e) {
	this._listeners[e.type](options.event ? options.event(e) : e);
}


import { createElement, hydrate, Fragment } from '../../src/index';
import {
	setupScratch,
	teardown,
	sortAttributes,
	serializeHtml
} from '../_util/helpers';
import { ul, li, div } from '../_util/dom';
import { logCall, clearLog, getLog } from '../_util/logCall';

/** @jsx createElement */

describe('hydrate()', () => {
	let scratch;

	const List = ({ children }) =>
{children}
;
	const ListItem = ({ children }) =>
{children}
;

	before(() => {
		logCall(Element.prototype, 'appendChild');
		logCall(Element.prototype, 'insertBefore');
		logCall(Element.prototype, 'removeChild');
		logCall(Element.prototype, 'remove');
		logCall(Element.prototype, 'setAttribute');
		logCall(Element.prototype, 'removeAttribute');
	});

	beforeEach(() => {
		scratch = setupScratch();
	});

	afterEach(() => {
		teardown(scratch);
		clearLog();
	});

	it('should reuse existing DOM', () => {
		const html = ul([li('1'), li('2'), li('3')].join(''));

		scratch.innerHTML = html;
		clearLog();

		hydrate(

1

2

3

,
			scratch
		);

		expect(scratch.innerHTML).to.equal(html);
		expect(getLog()).to.deep.equal([]);
	});

	it('should reuse existing DOM when given components', () => {
		const html = ul([li('1'), li('2'), li('3')].join(''));

		scratch.innerHTML = html;
		clearLog();

		hydrate(
			<List>
				<ListItem>1</ListItem>
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>,
			scratch
		);

		expect(scratch.innerHTML).to.equal(html);
		expect(getLog()).to.deep.equal([]);
	});

	it('should add missing nodes to existing DOM when hydrating', () => {
		const html = ul([li('1')].join(''));

		scratch.innerHTML = html;
		clearLog();

		hydrate(
			<List>
				<ListItem>1</ListItem>
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>,
			scratch
		);

		expect(scratch.innerHTML).to.equal(
			ul([li('1'), li('2'), li('3')].join(''))
		);
		expect(getLog()).to.deep.equal([
			'
.appendChild(#text)',
			'
1.appendChild(
2)',
			'
.appendChild(#text)',
			'
12.appendChild(
3)'
		]);
	});

	it('should remove extra nodes from existing DOM when hydrating', () => {
		const html = ul([li('1'), li('2'), li('3'), li('4')].join(''));

		scratch.innerHTML = html;
		clearLog();

		hydrate(
			<List>
				<ListItem>1</ListItem>
				<ListItem>2</ListItem>
				<ListItem>3</ListItem>
			</List>,
			scratch
		);

		expect(scratch.innerHTML).to.equal(
			ul([li('1'), li('2'), li('3')].join(''))
		);
		expect(getLog()).to.deep.equal(['
4.remove()']);
	});

	it('should not update attributes on existing DOM', () => {
		scratch.innerHTML =
			'
Test
';
		let vnode = (

					Test

		);

		clearLog();
		hydrate(vnode, scratch);

		expect(serializeHtml(scratch)).to.equal(
			sortAttributes(
				'
Test
'
			)
		);
		expect(getLog()).to.deep.equal([]);
	});

	it('should update class attribute via className prop', () => {
		scratch.innerHTML = '
bar
';
		hydrate(
bar
, scratch);
		expect(scratch.innerHTML).to.equal('
bar
');
	});

	it('should correctly hydrate with Fragments', () => {
		const html = ul([li('1'), li('2'), li('3'), li('4')].join(''));

		scratch.innerHTML = html;
		clearLog();

		hydrate(
			<List>
				<ListItem>1</ListItem>
				<Fragment>
					<ListItem>2</ListItem>
					<ListItem>3</ListItem>
				</Fragment>
				<ListItem>4</ListItem>
			</List>,
			scratch
		);

		expect(scratch.innerHTML).to.equal(html);
		expect(getLog()).to.deep.equal([]);
	});

	it('should correctly hydrate root Fragments', () => {
		const html = [
			ul([li('1'), li('2'), li('3'), li('4')].join('')),
			div('sibling')
		].join('');

		scratch.innerHTML = html;
		clearLog();

		hydrate(
			<Fragment>
				<List>
					<Fragment>
						<ListItem>1</ListItem>
						<ListItem>2</ListItem>
					</Fragment>
					<ListItem>3</ListItem>
					<ListItem>4</ListItem>
				</List>

sibling

			</Fragment>,
			scratch
		);

		expect(scratch.innerHTML).to.equal(html);
		expect(getLog()).to.deep.equal([]);
	});

	// Failing because the following condition in diffElementNodes doesn't evaluate to true
	// when hydrating a dom node which is not correct
	//		dom===d && newVNode.text!==oldVNode.text
	// We don't set `d` when hydrating. If we did, then newVNode.text would never equal
	// oldVNode.text since oldVNode is always EMPTY_OBJ when hydrating
	it.skip('should override incorrect pre-existing DOM with VNodes passed into render', () => {
		const initialHtml = [
			div('sibling'),
			ul([li('1'), li('4'), li('3'), li('2')].join(''))
		].join('');

		scratch.innerHTML = initialHtml;
		clearLog();

		hydrate(
			<Fragment>
				<List>
					<Fragment>
						<ListItem>1</ListItem>
						<ListItem>2</ListItem>
					</Fragment>
					<ListItem>3</ListItem>
					<ListItem>4</ListItem>
				</List>

sibling

			</Fragment>,
			scratch
		);

		const finalHtml = [
			ul([li('1'), li('2'), li('3'), li('4')].join('')),
			div('sibling')
		].join('');

		expect(scratch.innerHTML).to.equal(finalHtml);
		// TODO: Fill in with proper log once this test is passing
		expect(getLog()).to.deep.equal([]);
	});

	it('should not merge attributes with node created by the DOM', () => {
		const html = htmlString => {
			const div = document.createElement('div');
			div.innerHTML = htmlString;
			return div.firstChild;
		};

		// prettier-ignore
		const DOMElement = html`<div><a foo="bar"></a></div>`;
		scratch.appendChild(DOMElement);

		const preactElement = (

		);

		hydrate(preactElement, scratch);
		expect(scratch).to.have.property(
			'innerHTML',
			'

'
		);
	});

	it('should attach event handlers', () => {
		let spy = sinon.spy();
		scratch.innerHTML = 'Test';
		let vnode = Test;

		hydrate(vnode, scratch);

		scratch.firstChild.click();
		expect(spy).to.be.calledOnce;
	});
});


import { createElement } from 'react';
import { Link } from './simple-router';

/** @jsx createElement */

export default function Hello() {
	return (
		<div>
			Hello! <Link to="/bye">Go to Bye!</Link>
		</div>
	);
}


import { computed, observable } from "mobx"
import { observer } from "mobx-react"
import { Component, h } from "preact"
import { RouteChildProps } from "./router"
import { store } from "./store"

export type ProfileProps = RouteChildProps
@observer
export class Profile extends Component<ProfileProps> {
  @observable id = ""
  @observable busy = false

  componentDidMount() {
    this.id = this.props.route
  }

  componentWillReceiveProps(props: ProfileProps) {
    this.id = props.route
  }

  render() {
    const user = this.user
    if (user == null) return null
    return (

          {user.name.first} {user.name.last}

            {user.gender === "female" ? "👩" : "👨"} {user.id}

🖂 {user.email}

          <button
            class={this.busy ? "secondary busy" : "secondary"}
            disabled={this.busy}
            onClick={this.remove}
          >
            Remove contact
          </button>

    )
  }

  @computed get user() {
    return store.users.find(u => u.id === this.id)
  }

  remove = async () => {
    this.busy = true
    await new Promise<void>(cb => setTimeout(cb, 1500))
    store.deleteUser(this.id)
    this.busy = false
  }
}


typeof value === 'number' && IS_NON_DIMENSIONAL.test(key) === false

keep replace replace replace replace replace replace keep keep keep


/**
 * Assign properties from `props` to `obj`
 * @template O, P The obj and props types
 * @param {O} obj The object to copy properties to
 * @param {P} props The object to copy properties from
 * @returns {O & P}
 */
export function assign(obj, props) {
	for (let i in props) obj[i] = props[i];
	return /** @type {O & P} */ (obj);
}

/**
 * Remove a child node from its parent if attached. This is a workaround for
 * IE11 which doesn't support `Element.prototype.remove()`. Using this function
 * is smaller than including a dedicated polyfill.
 * @param {Node} node The node to remove
 */
export function removeNode(node) {
	let parentNode = node.parentNode;
	if (parentNode) parentNode.removeChild(node);
}


import React, {
	render,
	createElement,
	cloneElement,
	findDOMNode,
	Component,
	unmountComponentAtNode,
	createFactory,
	unstable_batchedUpdates
} from '../../src';
import { createElement as preactH } from 'preact';
import {
	setupScratch,
	teardown,
	createEvent
} from '../../../test/_util/helpers';

let ce = type => document.createElement(type);
let text = text => document.createTextNode(text);

describe('preact-compat', () => {
	/** @type {HTMLDivElement} */
	let scratch, proto;

	beforeEach(() => {
		scratch = setupScratch();
		proto = document.createElement('div').constructor.prototype;
		sinon.spy(proto, 'addEventListener');
		sinon.spy(proto, 'removeEventListener');
	});

	afterEach(() => {
		proto.addEventListener.restore();
		proto.removeEventListener.restore();
		teardown(scratch);
	});

	describe('render()', () => {
		it('should be exported', () => {
			expect(React)
				.to.have.property('render')
				.that.is.a('function')
				.that.equals(render);
		});

		it('should replace isomorphic content', () => {
			let root = ce('div');
			let initialChild = ce('div');
			initialChild.appendChild(text('initial content'));
			root.appendChild(initialChild);

			render(
dynamic content
, root);
			expect(root)
				.to.have.property('textContent')
				.that.is.a('string')
				.that.equals('dynamic content');
		});

		it('should remove extra elements', () => {
			let root = ce('div');
			let inner = ce('div');

			root.appendChild(inner);

			let c1 = ce('div');
			c1.appendChild(text('isomorphic content'));
			inner.appendChild(c1);

			let c2 = ce('div');
			c2.appendChild(text('extra content'));
			inner.appendChild(c2);

			render(
dynamic content
, root);
			expect(root)
				.to.have.property('textContent')
				.that.is.a('string')
				.that.equals('dynamic content');
		});

		// Note: Replacing text nodes inside the root itself is currently unsupported.
		// We do replace them everywhere else, though.
		it('should remove text nodes', () => {
			let root = ce('div');

			let div = ce('div');
			root.appendChild(div);
			div.appendChild(text('Text Content'));
			div.appendChild(text('More Text Content'));

			render(
dynamic content
, root);
			expect(root)
				.to.have.property('textContent')
				.that.is.a('string')
				.that.equals('dynamic content');
		});

		it('should support onAnimationEnd', () => {
			const func = () => {};
			render(
, scratch);

			expect(
				proto.addEventListener
			).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
				'animationend',
				sinon.match.func,
				false
			);

			expect(scratch.firstChild._listeners).to.deep.equal({
				animationend: func
			});

			render(
, scratch);
			expect(
				proto.removeEventListener
			).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
				'animationend',
				sinon.match.func,
				false
			);
		});

		it('should support onTransitionEnd', () => {
			const func = () => {};
			render(
, scratch);

			expect(
				proto.addEventListener
			).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
				'transitionend',
				sinon.match.func,
				false
			);

			expect(scratch.firstChild._listeners).to.deep.equal({
				transitionend: func
			});

			render(
, scratch);
			expect(
				proto.removeEventListener
			).to.have.been.calledOnce.and.to.have.been.calledWithExactly(
				'transitionend',
				sinon.match.func,
				false
			);
		});

		it('should support defaultValue', () => {
			render(<input defaultValue="foo" />, scratch);
			expect(scratch.firstElementChild).to.have.property('value', 'foo');
		});

		it('should ignore defaultValue when value is 0', () => {
			render(<input defaultValue={2} value={0} />, scratch);
			expect(scratch.firstElementChild.value).to.equal('0');
		});

		it('should call the callback', () => {
			let spy = sinon.spy();
			render(
, scratch, spy);
			expect(spy).to.be.calledOnce;
			expect(spy).to.be.calledWithExactly();
		});

		// Issue #1727
		it('should destroy the any existing DOM nodes inside the container', () => {
			scratch.appendChild(document.createElement('div'));
			scratch.appendChild(document.createElement('div'));

			render(foo, scratch);
			expect(scratch.innerHTML).to.equal('foo');
		});

		it('should only destroy existing DOM nodes on first render', () => {
			scratch.appendChild(document.createElement('div'));
			scratch.appendChild(document.createElement('div'));

			render(<input />, scratch);

			let child = scratch.firstChild;
			child.focus();
			render(<input />, scratch);
			expect(document.activeElement.nodeName).to.equal('INPUT');
		});
	});

	describe('createFactory', () => {
		it('should create a DOM element', () => {
			render(createFactory('span')({ class: 'foo' }, '1'), scratch);
			expect(scratch.innerHTML).to.equal('1');
		});

		it('should create a component', () => {
			const Foo = ({ id, children }) =>
foo {children}
;
			render(createFactory(Foo)({ id: 'value' }, 'bar'), scratch);
			expect(scratch.innerHTML).to.equal('
foo bar
');
		});
	});

	describe('createElement()', () => {
		it('should be exported', () => {
			expect(React)
				.to.have.property('createElement')
				.that.is.a('function')
				.that.equals(createElement);
		});

		it('should normalize vnodes', () => {
			let vnode = (

					t

			);
			let $$typeof = 0xeac7;
			try {
				// eslint-disable-next-line
				if (
					Function.prototype.toString
						.call(eval('Symbol.for'))
						.match(/\[native code\]/)
				) {
					// eslint-disable-next-line
					$$typeof = eval('Sym' + 'bol.for("react.element")');
				}
			} catch (e) {}
			expect(vnode).to.have.property('$$typeof', $$typeof);
			expect(vnode).to.have.property('type', 'div');
			expect(vnode)
				.to.have.property('props')
				.that.is.an('object');
			expect(vnode.props).to.have.property('children');
			expect(vnode.props.children).to.have.property('$$typeof', $$typeof);
			expect(vnode.props.children).to.have.property('type', 'a');
			expect(vnode.props.children)
				.to.have.property('props')
				.that.is.an('object');
			expect(vnode.props.children.props).to.eql({ children: 't' });
		});

		it('should normalize onChange', () => {
			let props = { onChange() {} };

			function expectToBeNormalized(vnode, desc) {
				expect(vnode, desc)
					.to.have.property('props')
					.with.all.keys(['oninput'].concat(vnode.props.type ? 'type' : []))
					.and.property('oninput')
					.that.is.a('function');
			}

			function expectToBeUnmodified(vnode, desc) {
				expect(vnode, desc)
					.to.have.property('props')
					.eql({
						...props,
						...(vnode.props.type ? { type: vnode.props.type } : {})
					});
			}

			expectToBeUnmodified(
, '
');
			expectToBeUnmodified(
				<input {...props} type="radio" />,
				'<input type="radio">'
			);
			expectToBeUnmodified(
				<input {...props} type="checkbox" />,
				'<input type="checkbox">'
			);
			expectToBeUnmodified(
				<input {...props} type="file" />,
				'<input type="file">'
			);

			expectToBeNormalized(<textarea {...props} />, '<textarea>');
			expectToBeNormalized(<input {...props} />, '<input>');
			expectToBeNormalized(
				<input {...props} type="text" />,
				'<input type="text">'
			);
		});

		it('should normalize beforeinput event listener', () => {
			let spy = sinon.spy();
			render(<input onBeforeInput={spy} />, scratch);
			scratch.firstChild.dispatchEvent(createEvent('beforeinput'));
			expect(spy).to.be.calledOnce;
		});
	});

	describe('Component', () => {
		it('should be exported', () => {
			expect(React)
				.to.have.property('Component')
				.that.is.a('function')
				.that.equals(Component);
		});
	});

	describe('cloneElement', () => {
		it('should clone elements', () => {
			let element = (
				<foo a="b" c="d">
					ab
				</foo>
			);
			expect(cloneElement(element)).to.eql(element);
		});

		it('should support props.children', () => {
			let element = <foo children={b} />;
			let clone = cloneElement(element);
			expect(clone).to.eql(element);
			expect(cloneElement(clone).props.children).to.eql(element.props.children);
		});

		it('children take precedence over props.children', () => {
			let element = (
				<foo children={c}>

b

				</foo>
			);
			let clone = cloneElement(element);
			expect(clone).to.eql(element);
			expect(clone.props.children.type).to.eql('div');
		});

		it('should support children in prop argument', () => {
			let element = <foo />;
			let children = [b];
			let clone = cloneElement(element, { children });
			expect(clone.props.children).to.eql(children);
		});

		it('children argument takes precedence over props.children', () => {
			let element = <foo />;
			let childrenA = [b];
			let childrenB = [
c
];
			let clone = cloneElement(element, { children: childrenA }, ...childrenB);
			expect(clone.props.children).to.eql(childrenB);
		});

		it('children argument takes precedence over props.children even if falsey', () => {
			let element = <foo />;
			let childrenA = [b];
			let clone = cloneElement(element, { children: childrenA }, undefined);
			expect(clone.children).to.eql(undefined);
		});

		it('should skip cloning on invalid element', () => {
			let element = { foo: 42 };
			let clone = cloneElement(element);
			expect(clone).to.eql(element);
		});

		it('should work with jsx constructor from core', () => {
			function Foo(props) {
				return
{props.value}
;
			}

			let clone = cloneElement(preactH(Foo), { value: 'foo' });
			render(clone, scratch);
			expect(scratch.textContent).to.equal('foo');
		});
	});

	describe('findDOMNode()', () => {
		class Helper extends React.Component {
			render({ something }) {
				if (something == null) return null;
				if (something === false) return null;
				return
;
			}
		}

		it.skip('should return DOM Node if render is not false nor null', () => {
			const helper = React.render(<Helper />, scratch);
			expect(findDOMNode(helper)).to.be.instanceof(Node);
		});

		it('should return null if given null', () => {
			expect(findDOMNode(null)).to.be.null;
		}),
			it('should return a regular DOM Element if given a regular DOM Element', () => {
				let scratch = document.createElement('div');
				expect(findDOMNode(scratch)).to.equalNode(scratch);
			}),
			// NOTE: React.render() returning false or null has the component pointing
			// 			to no DOM Node, in contrast, Preact always render an empty Text DOM Node.
			it('should return null if render returns false', () => {
				const helper = React.render(<Helper something={false} />, scratch);
				expect(findDOMNode(helper)).to.be.null;
			});

		// NOTE: React.render() returning false or null has the component pointing
		// 			to no DOM Node, in contrast, Preact always render an empty Text DOM Node.
		it('should return null if render returns null', () => {
			const helper = React.render(<Helper something={null} />, scratch);
			expect(findDOMNode(helper)).to.be.null;
		});
	});

	describe('unmountComponentAtNode', () => {
		it('should unmount a root node', () => {
			const App = () =>
foo
;
			render(<App />, scratch);

			expect(unmountComponentAtNode(scratch)).to.equal(true);
			expect(scratch.innerHTML).to.equal('');
		});

		it('should do nothing if root is not mounted', () => {
			expect(unmountComponentAtNode(scratch)).to.equal(false);
			expect(scratch.innerHTML).to.equal('');
		});
	});

	describe('unstable_batchedUpdates', () => {
		it('should call the callback', () => {
			const spy = sinon.spy();
			unstable_batchedUpdates(spy);
			expect(spy).to.be.calledOnce;
		});

		it('should call callback with only one arg', () => {
			const spy = sinon.spy();
			unstable_batchedUpdates(spy, 'foo', 'bar');
			expect(spy).to.be.calledWithExactly('foo');
		});
	});

	it('should patch events', () => {
		let spy = sinon.spy();
		render(
, scratch);
		scratch.firstChild.click();

		expect(spy).to.be.calledOnce;
		expect(spy.args[0][0]).to.haveOwnProperty('persist');
		expect(spy.args[0][0]).to.haveOwnProperty('nativeEvent');
	});

	it('should normalize ondoubleclick event', () => {
		let vnode =
 null} />;
		expect(vnode.props).to.haveOwnProperty('ondblclick');
	});

	it('should normalize onChange for textarea', () => {
		let vnode = <textarea onChange={() => null} />;
		expect(vnode.props).to.haveOwnProperty('oninput');
		expect(vnode.props).to.not.haveOwnProperty('onchange');

		vnode = <textarea oninput={() => null} onChange={() => null} />;
		expect(vnode.props).to.haveOwnProperty('oninput');
		expect(vnode.props).to.not.haveOwnProperty('onchange');
	});

	it('should not normalize onChange for range', () => {
		render(<input type="range" onChange={() => null} />, scratch);
		expect(scratch.firstChild._listeners).to.haveOwnProperty('change');
		expect(scratch.firstChild._listeners).to.not.haveOwnProperty('input');
	});

	it('should normalize class+className even on components', () => {
		function Foo(props) {
			return (

					foo

			);
		}
		render(<Foo class="foo" />, scratch);
		expect(scratch.firstChild.className).to.equal('foo');
		render(null, scratch);

		render(<Foo className="foo" />, scratch);
		expect(scratch.firstChild.className).to.equal('foo');
	});
});


root = true

[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[{package.json,.*rc,*.yml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false

# Uglify (or some other tool) always rewrites this file
# without a final newline on build, so disabling that
# editorconfig feature specifically for this file
[{mangle.json,**/mangle.json}]
indent_style = space
insert_final_newline = false


* @param {*} value The value to set the property to

* @param {*} oldValue The old value the property had

* @param {boolean} isSvg Whether or not this DOM node is an SVG node or not

function setProperty(dom, name, value, oldValue, isSvg) {

if (name === 'key' || name === 'children') {

keep keep keep keep keep replace replace replace replace replace replace replace keep keep keep keep

if (isSvg) {
if (name === 'className') {
name = 'class';
}
} else if (name === 'class') {
name = 'className';
}

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 =
		(this._nextState !== this.state && this._nextState) ||
		(this._nextState = assign({}, this.state));

	// if update() mutates state in-place, skip the copy:
	if (typeof update !== 'function' || (update = update(s, this.props))) {
		assign(s, update);
	}

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

	if (this._vnode) {
		this._force = false;
		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 = [];
		let newDom = diff(
			parentDom,
			vnode,
			assign({}, vnode),
			component._context,
			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 q = [];

/**
 * Asynchronously schedule a callback
 * @type {(cb) => void}
 */
/* istanbul ignore next */
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 = options.debounceRendering;

/**
 * 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) && q.push(c) === 1) ||
		prevDebounce !== options.debounceRendering
	) {
		prevDebounce = options.debounceRendering;
		(options.debounceRendering || defer)(process);
	}
}

/** Flush the render queue by rerendering all queued components */
function process() {
	let p;
	q.sort((a, b) => b._vnode._depth - a._vnode._depth);
	while ((p = q.pop())) {
		// forceUpdate's callback argument is reused here to indicate a non-forced update.
		if (p._dirty) renderComponent(p);
	}
}


import {
	setupScratch,
	teardown,
	serializeHtml
} from '../../../test/_util/helpers';
import React, { isValidElement } from '../../src';
import { h as preactH } from 'preact';

describe('jsx', () => {
	/** @type {HTMLDivElement} */
	let scratch;

	beforeEach(() => {
		scratch = setupScratch();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it('should render react-style', () => {
		let jsx = (

				inner!
				{['a', 'b']}

		);

		expect(jsx.props).to.have.property('className', 'foo bar');

		React.render(jsx, scratch);
		expect(serializeHtml(scratch)).to.equal(
			'
inner!ab
'
		);
	});

	describe('isValidElement', () => {
		it('should check return false for invalid arguments', () => {
			expect(isValidElement(null)).to.equal(false);
			expect(isValidElement(false)).to.equal(false);
			expect(isValidElement(true)).to.equal(false);
			expect(isValidElement('foo')).to.equal(false);
			expect(isValidElement(123)).to.equal(false);
		});

		it('should detect a preact vnode', () => {
			expect(isValidElement(preactH('div'))).to.equal(true);
		});

		it('should detect a compat vnode', () => {
			expect(isValidElement(React.createElement('div'))).to.equal(true);
		});
	});
});


import { createElement, Component } from 'preact';
import { select as d3select, mouse as d3mouse } from 'd3-selection';
import { scaleLinear } from 'd3-scale';
import Pythagoras from './pythagoras';

export default class PythagorasDemo extends Component {
	svg = {
		width: 1280,
		height: 600
	};

	state = {
		currentMax: 0,
		baseW: 80,
		heightFactor: 0,
		lean: 0
	};

	realMax = 11;

	svgRef = c => {
		this.svgElement = c;
	};

	scaleFactor = scaleLinear()
		.domain([this.svg.height, 0])
		.range([0, 0.8]);

	scaleLean = scaleLinear()
		.domain([0, this.svg.width / 2, this.svg.width])
		.range([0.5, 0, -0.5]);

	onMouseMove = event => {
		let [x, y] = d3mouse(this.svgElement);

		this.setState({
			heightFactor: this.scaleFactor(y),
			lean: this.scaleLean(x)
		});
	};

	restart = () => {
		this.setState({ currentMax: 0 });
		this.next();
	};

	next = () => {
		let { currentMax } = this.state;

		if (currentMax < this.realMax) {
			this.setState({ currentMax: currentMax + 1 });
			this.timer = setTimeout(this.next, 500);
		}
	};

	componentDidMount() {
		this.selected = d3select(this.svgElement).on('mousemove', this.onMouseMove);
		this.next();
	}

	componentWillUnmount() {
		this.selected.on('mousemove', null);
		clearTimeout(this.timer);
	}

	render({}, { currentMax, baseW, heightFactor, lean }) {
		let { width, height } = this.svg;

		return (
			<div class="App">
				<svg width={width} height={height} ref={this.svgRef}>
					<Pythagoras
						w={baseW}
						h={baseW}
						heightFactor={heightFactor}
						lean={lean}
						x={width / 2 - 40}
						y={height - baseW}
						lvl={0}
						maxlvl={currentMax}
					/>
				</svg>
			</div>
		);
	}
}


/*global coverage, ENABLE_PERFORMANCE */
/*eslint no-console:0*/
/** @jsx createElement */

import { setupScratch, teardown } from '../_util/helpers';
import bench from '../_util/bench';
const preact = require('../fixtures/preact');
const ceviche = require('../../dist/preact');
const MULTIPLIER = ENABLE_PERFORMANCE ? (coverage ? 5 : 1) : 999999;

describe('benchmarks', function() {
	let scratch;

	this.timeout(100000);

	before(function() {
		if (!ENABLE_PERFORMANCE) this.skip();
		if (coverage) {
			console.warn(
				'WARNING: Code coverage is enabled, which dramatically reduces performance. Do not pay attention to these numbers.'
			);
		}
	});

	beforeEach(() => {
		scratch = setupScratch();
	});

	afterEach(() => {
		teardown(scratch);
	});

	it('in-place text update', done => {
		function createTest({ createElement, render }) {
			const parent = document.createElement('div');
			scratch.appendChild(parent);

			function component(randomValue) {
				return (

Test {randomValue}

==={randomValue}===

				);
			}

			return value => {
				const t = value % 100;
				render(component(t), parent);
			};
		}

		function createVanillaTest() {
			const parent = document.createElement('div');
			let div, h1, h2, text1, text2;
			parent.appendChild((div = document.createElement('div')));
			div.appendChild((h2 = document.createElement('h2')));
			h2.appendChild(document.createTextNode('Vanilla '));
			h2.appendChild((text1 = document.createTextNode('0')));
			div.appendChild((h1 = document.createElement('h1')));
			h1.appendChild(document.createTextNode('==='));
			h1.appendChild((text2 = document.createTextNode('0')));
			h1.appendChild(document.createTextNode('==='));
			scratch.appendChild(parent);

			return value => {
				const t = value % 100;
				text1.data = '' + t;
				text2.data = '' + t;
			};
		}

		const preactTest = createTest(preact);
		const cevicheTest = createTest(ceviche);
		const vanillaTest = createVanillaTest();

		for (let i = 100; i--; ) {
			preactTest(i);
			cevicheTest(i);
			vanillaTest(i);
		}

		bench(
			{
				vanilla: vanillaTest,
				preact: preactTest,
				ceviche: cevicheTest
			},
			({ text, results }) => {
				const THRESHOLD = 10 * MULTIPLIER;
				// const slowdown = Math.sqrt(results.ceviche.hz * results.vanilla.hz);
				const slowdown = results.vanilla.hz / results.ceviche.hz;
				console.log(
					`in-place text update is ${slowdown.toFixed(2)}x slower:` + text
				);
				expect(slowdown).to.be.below(THRESHOLD);
				done();
			}
		);
	});
});


obb_pos_worldspace = numpy.array([modelmatrix[3, 0], modelmatrix[3, 1], modelmatrix[3, 2]])

# test intersection with 2 planes perpendicular to OBB's x-axis

keep keep keep keep keep replace replace keep keep keep

obb_pos_worldspace = numpy.array([modelmatrix[0, 3], modelmatrix[1, 3], modelmatrix[2, 3]])

import numpy

def translation(displacement):
  t = numpy.identity(4)
  t[3, 0] = displacement[0]
  t[3, 1] = displacement[1]
  t[3, 2] = displacement[2]
  return t

def scaling(scale):
  s = numpy.identity(4)
  s[0, 0] = scale[0]
  s[1, 1] = scale[1]
  s[2, 2] = scale[2]
  return s

def make_perspective(fov, aspect, near, far):
    fov = fov * math.pi / 180;
    f = 1/tan(fov/2);
    persp_mat = numpy.zeros((4, 4))
    persp_mat[0][0] = f/aspect;
    persp_mat[0][1] = 0;
    persp_mat[0][2] = 0;
    persp_mat[0][3] = 0;

    persp_mat[1][0] = 0;
    persp_mat[1][1] = f;
    persp_mat[1][2] = 0;
    persp_mat[1][3] = 0;

    persp_mat[2][0] = 0;
    persp_mat[2][1] = 0;
    persp_mat[2][2] = (far+near)/(near-far);
    persp_mat[2][3] = (2*far*near)/(near-far);

    persp_mat[3][0] = 0;
    persp_mat[3][1] = 0;
    persp_mat[3][2] = -1;
    persp_mat[3][3] = 0;

    return numpy.transpose(persp_mat)


This version:

*   adds HTTP error codes for missing items;
*   does path normalization to prevent users fetching files that aren't
    below the specified root directory; and
*   has some logging built in.

If nothing corresponds to the requested path, a 404 (File Not Found)
error is returned.  If the thing corresponding to the path can't be
read, a 403 (No Permissions) error is returned.  If something else
goes wrong, a 500 (Internal) error is returned.


Author: Kresten Krab Thorup
Project: Torrent Client
Requirements: Erlang

This directory holds a simple torrent client in Erlang. The client only works
for single-file torrents that use a http tracker.

In building this, the major challenge is to keep the project under 500
lines, since we're building it almost from first principles.  Right
now it is ~542 lines (excluding blank or comments lines).

The easiest way to get Erlang, is to download it from www.erlang-solutions.org.
Don't use the Erlang distributed with Ubuntu.

compile:
  ./rebar get-deps
  ./rebar compile

run:
  erl -pa ebin -pa deps/*/ebin
  1> torrent_client:download("../path/to.torrent")


from collections import defaultdict
from protocol import Ballot
from member import Component

class Acceptor(Component):

    def __init__(self, member):
        super(Acceptor, self).__init__(member)
        self.ballot_num = Ballot(-1, -1)
        self.accepted = defaultdict()  # { (b,s) : p }

    def do_PREPARE(self, scout_id, ballot_num):  # p1a
        if ballot_num > self.ballot_num:
            self.ballot_num = ballot_num
        self.send([scout_id.address], 'PROMISE',  # p1b
                         scout_id=scout_id,
                         acceptor=self.address,
                         ballot_num=self.ballot_num,
                         accepted=self.accepted)

    def do_ACCEPT(self, commander_id, ballot_num, slot, proposal):  # p2a
        if ballot_num >= self.ballot_num:
            self.ballot_num = ballot_num
            self.accepted[(ballot_num, slot)] = proposal
        self.send([commander_id.address], 'ACCEPTED',  # p2b
                         commander_id=commander_id,
                         acceptor=self.address,
                         ballot_num=self.ballot_num)


xaxis = numpy.array((modelmatrix[0, 0], modelmatrix[1, 0], modelmatrix[2, 0]))

keep keep keep replace keep keep keep keep

xaxis = numpy.array((modelmatrix[0, 0], modelmatrix[0, 1], modelmatrix[0, 2]))

import sys
import numpy
from node import Sphere, Cube
class Scene(object):
    """ Base class for scene nodes.
        Scene nodes currently only include primitives """

    # the default depth from the camera to place an object at
    PLACE_DEPTH = 15.0

    def __init__(self):
        """ Initialize the Scene """
        # The scene keeps a list of nodes that are displayed
        self.node_list = list()
        # Keep track of the currently selected node.
        # Actions may depend on whether or not something is selected
        self.selected_node = None

    def render(self):
        """ Render the scene. This function simply calls the render function for each node. """
        for node in self.node_list:
            node.render()

    def add_node(self, node):
        """ Add a new node to the scene """
        self.node_list.append(node)

    def picking(self, start, direction, inv_modelview):
        """ Execute selection.
            Consume: start, direction describing a Ray
                     mat              is the inverse of the current modelview matrix for the scene """
        if self.selected_node is not None:
            self.selected_node.select(False)
            self.selected_node = None

        # Keep track of the closest hit.
        mindist, closest_node  = sys.maxint, None
        for node in self.node_list:
            hit, distance = node.picking(start, direction, inv_modelview)
            if hit and distance < mindist:
                mindist, closest_node = distance, node

        # If we hit something, keep track of it.
        if closest_node is not None:
            closest_node.select()
            closest_node.depth = mindist
            closest_node.selected_loc = start + direction * mindist
            self.selected_node = closest_node

    def move(self, start, direction, inv_modelview):
        """ Move the selected node, if there is one.
            Consume:  start, direction  describes the Ray to move to
                      mat               is the modelview matrix for the scene """
        if self.selected_node is None: return

        # Find the current depth and location of the selected node
        node = self.selected_node
        depth = node.depth
        oldloc = node.selected_loc

        # The new location of the node is the same depth along the new ray
        newloc = (start + direction * depth)

        # transform the translation with the modelview matrix
        translation = newloc - oldloc
        pre_tran = numpy.array([translation[0], translation[1], translation[2], 0])
        translation = inv_modelview.dot(pre_tran)

        # translate the node and track its location
        node.translate(translation[0], translation[1], translation[2])
        node.selected_loc = newloc

    def place(self, shape, start, direction, inv_modelview):
        """ Place a new node.
            Consume:  shape             the shape to add
                      start, direction  describes the Ray to move to
                      mat               is the modelview matrix for the scene """
        new_node = None
        if shape == 'sphere': new_node = Sphere()
        elif shape == 'cube': new_node = Cube()

        self.add_node(new_node)

        # place the node at the cursor in camera-space
        translation = (start + direction * self.PLACE_DEPTH)

        # convert the translation to world-space
        pre_tran = numpy.array([translation[0], translation[1], translation[2], 1])
        translation = inv_modelview.dot(pre_tran)

        new_node.translate(translation[0], translation[1], translation[2])

    def rotate_color(self, forwards):
        """ Rotate the color of the currently selected node """
        if self.selected_node is None: return
        self.selected_node.rotate_color(forwards)


Author: Dustin J. Mitchell
Project: Cluster (a working title!)
Requirements: Python

This directory holds a simple implementation of a replicated state machine
that can also feed clients information on cluster membership.

* statemachine.py -- illustrates the state machine client API
* network.py -- handles network communication
* deterministic_network.py -- similar, but deterministic
* client.py -- a simple client
* member_single.py -- a non-clustered member server, talking to the client
* member_replicated.py -- a replicated state machine with consensus and a fixed membership
  This is based on "Paxos Made Moderately Complex" (van Renesse, 2011)


markdown        : redcarpet
pygments        : true
contact         : "aosa@aosabook.org"


'''Server that echoes data back until there is no more.'''

import sys, socket

size, host, port = 1024, '', int(sys.argv[1])

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
s.listen(True)
conn, addr = s.accept()
print 'Connected by', addr

result = ''
while True:
    data = conn.recv(size)
    print '...server:', `data`
    if not data:
        break
    result += data
print 'server saw', `result`

conn.close()


if (-e + aabb_min[0] > 0.0 + EPSILON) or (-e+aabb_max[0] < 0.0 - EPSILON):

yaxis = numpy.array((modelmatrix[0, 1], modelmatrix[1, 1], modelmatrix[2, 1]))

keep keep keep replace keep keep keep keep keep

yaxis = numpy.array((modelmatrix[1, 0], modelmatrix[1, 1], modelmatrix[1, 2]))

#! /usr/bin/env python
from OpenGLContext import testingcontext, quaternion, contextdefinition
BaseContext = testingcontext.getInteractive()

from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
from OpenGLContext.arrays import *
from numpy.linalg import norm
import numpy

from interaction import Interaction
from primitive import InitPrimitives, G_OBJ_PLANE
from node import Sphere, Cube
from scene import Scene
from transformation import make_perspective

class TestContext(BaseContext):
    def OnInit(self):
        """ Initialize the context. """
        InitPrimitives()
        self.interaction = Interaction()
        self.interaction.register()
        self.scene = Scene()

        self.interaction.registerCallback('picking', self.picking)
        self.interaction.registerCallback('move', self.move)
        self.interaction.registerCallback('place', self.place)
        self.interaction.registerCallback('color', self.color)

        self.InitialScene()
        self.inverseModelView = numpy.identity(4)

    def Render(self, mode = None):
        """ The render pass for the scene """
        BaseContext.Render(self, mode)

        self.initView()

        # Enable lighting and color
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        glLightfv(GL_LIGHT0, GL_POSITION, GLfloat_4(0, 0, 1, 0))
        glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, GLfloat_3(0, 0, -1))

        glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE)
        glEnable( GL_COLOR_MATERIAL)

        glClearColor(0.4, 0.4, 0.4, 0.0);
        glClear(GL_COLOR_BUFFER_BIT)

        # Load the modelview matrix from the current state of the trackball
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix()
        glLoadIdentity()
        loc = self.interaction.camera_loc
        glTranslated(-loc[0], -loc[1], -loc[2])
        glMultMatrixf(self.interaction.rotation.matrix(inverse=False))

        # store the inverse of the current modelview.
        mat = numpy.array(glGetFloatv( GL_MODELVIEW_MATRIX ))
        self.inverseModelView = numpy.linalg.inv(numpy.transpose(mat))

        # Render the scene. This will call the render function for each object in the scene
        self.scene.render()

        # draw the grid
        glDisable(GL_LIGHTING)
        glCallList(G_OBJ_PLANE)
        glPopMatrix()

    def initView(self):
        xSize, ySize = glutGet( GLUT_WINDOW_WIDTH ), glutGet( GLUT_WINDOW_HEIGHT )
        aspect_rat = float(xSize) / float(ySize)

        # load the projection matrix. Always the same
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        glViewport(0, 0, xSize, ySize);
        gluPerspective(70, aspect_rat , 0.1, 1000.0)
        glTranslated(0, 0, -15);

    def InitialScene(self):
        cube_node = Cube()
        cube_node.translate(2, 0, 2)
        cube_node.color_index = 2
        self.scene.add_node(cube_node)

        cube_node = Sphere()
        cube_node.translate(-2, 0, 2)
        cube_node.color_index = 3
        self.scene.add_node(cube_node)

        cube_node = Sphere()
        cube_node.translate(-2, 0, -2)
        cube_node.color_index = 1
        self.scene.add_node(cube_node)

    def getRay(self, x, y):
        """ Generate a ray beginning at the near plane, in the direction that the x, y coordinates are facing
            Consumes: x, y coordinates of mouse on screen
            Return: start, direction of the ray """
        self.initView()

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity()

        # get two points on the line.
        start = array(gluUnProject(x, y, 0.001))
        end = array(gluUnProject(x, y, 0.999))

        # convert those points into a ray
        direction = end - start
        direction = direction / norm(direction)

        return (start, direction)

    def picking(self, x, y):
        """ Execute picking of an object. Selects an object in the scene.
            Consumes: x, y coordinates of the mouse on the screen """
        start, direction = self.getRay(x, y)
        self.scene.picking(start, direction, self.inverseModelView)

    def move(self, x, y):
        """ Execute a move command on the scene.
            Consumes: x, y coordinates of the mouse on the screen """
        start, direction = self.getRay(x, y)
        self.scene.move(start, direction, self.inverseModelView)

    def place(self, shape, x, y):
        """ Execute a placement of a new primitive into the scene.
            Consumes: x, y coordinates of the mouse on the screen """
        start, direction = self.getRay(x, y)
        self.scene.place(shape, start, direction, self.inverseModelView)

    def color(self, forwards):
        self.scene.rotate_color(forwards)

if __name__=="__main__":
    TestContext.ContextMainLoop( definition = contextdefinition.ContextDefinition(size = (500,500),))


import sys, os, BaseHTTPServer

class RequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    # Root of files being served.
    Root_Directory = None

    # Is debugging output on?
    Debug = False

    # HTTP error codes.
    ERR_NO_PERM   = 403
    ERR_NOT_FOUND = 404
    ERR_INTERNAL  = 500

    # How to display a single item in a directory listing.
    Listing_Item = "
%s
"

    # How to display a whole page of listings.
    Listing_Page = """\

Listing for %(path)s

        %(filler)s

        """

    # Classify and handle request.
    def do_GET(self):

        self.log("path is '%s'" % self.path)

        # Handle any errors that arise.
        try:

            # Class not yet initialized.
            if self.Root_Directory is None:
                self.err_internal("Root directory not set")
                return

            # Figure out what exactly is being requested.
            abs_path = self.create_abs_path()
            self.log("abs_path is '%s'" % abs_path)

            # It isn't below the root path.
            if not self.is_parent_dir(self.Root_Directory, abs_path):
                self.log("abs_path not below root directory")
                msg = "Path '%s' not below root directory '%s'" % \
                      (abs_path, self.Root_Directory)
                self.err_no_perm(msg)

            # It doesn't exist.
            elif not os.path.exists(abs_path):
                self.log("abs_path doesn't exist")
                self.err_not_found(abs_path)

            # It's a file.
            elif os.path.isfile(abs_path):
                self.log("abs_path is a file")
                self.handle_file(abs_path)

            # It's a directory.
            elif os.path.isdir(abs_path):
                self.log("abs_path is a directory")
                self.handle_dir(abs_path)

            # ...we can't tell.
            else:
                self.log("can't tell what abs_path is")
                self.err_not_found(abs_path)

        # Handle general errors.
        except Exception, msg:
            self.err_internal("Unexpected exception: %s" % msg)

    def create_abs_path(self):
        head = os.path.abspath(self.Root_Directory)
        result = os.path.normpath(head + self.path)
        return result

    def is_parent_dir(self, left, right):
        return os.path.commonprefix([left, right]) == left

    def handle_file(self, abs_path):
        try:
            input = file(abs_path, "r")
            content = input.read()
            input.close()
            self.send_content(content)
        except IOError, msg:
            msg = "'%s' cannot be read: %s" % (self.path, msg)
            self.err_no_perm(msg)

    def handle_dir(self, abs_path):
        try:
            listing = os.listdir(abs_path)
            filler = '\n'.join([(self.Listing_Item % item) for item in listing])
            content = self.Listing_Page % {'path'   : self.path,
                                           'filler' : filler}
            self.send_content(content)
        except IOError, msg:
            msg = "'%s' cannot be listed: %s" % (self.path, msg)
            self.send_error(ERR_NO_PERM, msg)

    # Send actual content.
    def send_content(self, content):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.send_header("Content-Length", str(len(content)))
        self.end_headers()
        self.wfile.write(content)

    # Report internal errors.
    def err_internal(self, msg):
        self.send_error(self.ERR_INTERNAL, msg)

    # Handle missing object errors.
    def err_not_found(self, abs_path):
        self.send_error(self.ERR_NOT_FOUND, "'%s' not found" % self.path)

    # Handle no permission errors.
    def err_no_perm(self, msg):
        self.send_error(self.ERR_NO_PERM, msg)

    # Write a log message if in debugging mode
    def log(self, msg):
        if self.Debug:
            print msg

#----------------------------------------------------------------------

if __name__ == '__main__':

    # Main libraries
    import getopt

    # How to use
    Usage = "server.py [-v] root_directory"

    # Handle command-line arguments
    options, rest = getopt.getopt(sys.argv[1:], "v")

    for (flag, arg) in options:
        if flag == "-v":
            RequestHandler.Debug = True
        else:
            print >> sys.stderr, Usage
            sys.exit(1)

    if not rest:
        print >> sys.stderr, Usage
        sys.exit(1)
    root = os.path.abspath(rest[0])
    if not os.path.isdir(root):
        print >> sys.stderr, "No such directory '%s'" % root
        sys.exit(1)
    RequestHandler.Root_Directory = root

    # Create and run server.
    server_address = ('', 8080)
    server = BaseHTTPServer.HTTPServer(server_address, RequestHandler)
    server.serve_forever()


---
---
<!DOCTYPE html>

    {% include header.html %}

{{page.title}}

          {{content}}

      {% include footer.html %}


import fake_network
import member
import unittest

class ComponentTestCase(unittest.TestCase):

    def setUp(self):
        self.node = fake_network.FakeNode()
        self.member = member.Member(self.node)

    def tearDown(self):
        if self.node.sent:
            self.fail("extra messages from node: %r" % (self.node.sent,))

    def assertMessage(self, destinations, action, **kwargs):
        destinations.sort()
        got = self.node.sent.pop(0)
        self.assertEqual((sorted(got[0]), got[1], got[2]),
                         (destinations, action, kwargs))


if (-e + aabb_min[1] > 0.0 + EPSILON) or (-e+aabb_max[1] < 0.0 - EPSILON):

zaxis = numpy.array((modelmatrix[0, 2], modelmatrix[1, 2], modelmatrix[2, 2]))

keep keep keep keep keep replace keep keep keep

zaxis = numpy.array((modelmatrix[2, 0], modelmatrix[2, 1], modelmatrix[2, 2]))

from OpenGL.GL import *
from numpy import array, matrix
import numpy
from primitive import G_OBJ_SPHERE, G_OBJ_CUBE, MakeCube
from aabb import AABB
from transformation import scaling, translation
import color

class Node(object):
    """ Base class for scene elements """
    def __init__(self):
        self.scale = array([1, 1, 1])
        self.location = [0, 0, 0]
        self.color_index = 0
        self.call_list = None
        self.aabb = None
        self.translation = numpy.identity(4)
        self.scalemat = numpy.identity(4)
        self.selected = False

    def render(self):
        """ renders the item to the screen """
        glPushMatrix()
        glMultMatrixf(self.scalemat)
        glMultMatrixf(self.translation)
        cur_color = color.COLORS[self.color_index]
        glColor3f(cur_color[0], cur_color[1], cur_color[2])
        if self.selected: # emit light if the node is selected
            glMaterialfv(GL_FRONT, GL_EMISSION, [0.3, 0.3, 0.3])
        glCallList(self.call_list)
        if self.selected:
            glMaterialfv(GL_FRONT, GL_EMISSION, [0.0, 0.0, 0.0])
        glPopMatrix()

    def translate(self, x, y, z):
        self.translation = numpy.dot(self.translation , translation([x, y, z]))

    def scale(self, x, y, z):
        self.scalemat = numpy.dot(self.scalemat , scaling([x, y, z]))

    def rotate_color(self, forwards):
        self.color_index += 1 if forwards else -1
        if self.color_index > color.MAX_COLOR:
            self.color_index = color.MIN_COLOR
        if self.color_index < color.MIN_COLOR:
            self.color_index = color.MAX_COLOR

    def picking(self, start, direction, mat):
        """ Return whether or not the ray hits the object
           Consume:  start, direction    the ray to check
                     mat                 the modelview matrix to transform the ray by """

        glPushMatrix()
        glMultMatrixf(self.scalemat)
        glMultMatrixf(self.translation)
        glCallList(self.call_list)
        glPopMatrix()

        # transform the modelview matrix by the current scale and translation
        newmat = numpy.dot(self.translation, numpy.dot(mat, self.scalemat))
        results = self.aabb.ray_hit(start, direction, newmat)
        return results

    def select(self, select=None):
        """ Toggles or sets selected state """
        if select is not None:
            self.selected = select
        else:
            self.selected = not self.selected

class Sphere(Node):
    """ Sphere primitive """
    def __init__(self):
        super(Sphere, self).__init__()
        self.call_list = G_OBJ_SPHERE
        self.aabb = AABB([0.0, 0.0, 0.0], [0.5, 0.5, 0.5])

class Cube(Node):
    """ Cube primitive """
    def __init__(self):
        super(Cube, self).__init__()
        self.call_list = G_OBJ_CUBE
        self.aabb = AABB([0.0, 0.0, 0.0], [0.5, 0.5, 0.5])


<title>Nitinat Test Page</title>

Nitinat Test Page

This is an HTML page which displays an image.


from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGLContext.scenegraph.basenodes import Sphere

G_OBJ_PLANE = 1
G_OBJ_SPHERE = 2
G_OBJ_CUBE = 3

def MakePlane():
    glNewList(G_OBJ_PLANE, GL_COMPILE)
    glBegin(GL_LINES)
    glColor3d(0,0,0)
    for i in xrange(41):
        glVertex3f(-10.0 + 0.5 * i, 0, -10)
        glVertex3f(-10.0 + 0.5 * i, 0, 10)
        glVertex3f(-10.0 , 0, -10 + 0.5 * i)
        glVertex3f(10.0 , 0, -10 + 0.5 * i)

    # Axes
    glEnd()
    glLineWidth(5)

    glBegin(GL_LINES)
    glColor3f(0.5, 0.7, 0.5)
    glVertex3f(0.0, 0.0, 0.0)
    glVertex3f(5, 0.0, 0.0)
    glEnd()

    glBegin(GL_LINES)
    glColor3f(0.5, 0.7, 0.5)
    glVertex3f(0.0, 0.0, 0.0)
    glVertex3f(0.0, 5, 0.0)
    glEnd()

    glBegin(GL_LINES)
    glColor3f(0.5, 0.7, 0.5)
    glVertex3f(0.0, 0.0, 0.0)
    glVertex3f(0.0, 0.0, 5)
    glEnd()

    # Draw the Y.
    glBegin(GL_LINES)
    glColor3f(0.0, 0.0, 0.0)
    glVertex3f(0.0, 5.0, 0.0)
    glVertex3f(0.0, 5.5, 0.0)
    glVertex3f(0.0, 5.5, 0.0)
    glVertex3f(-0.5, 6.0, 0.0)
    glVertex3f(0.0, 5.5, 0.0)
    glVertex3f(0.5, 6.0, 0.0)

    # Draw the Z.
    glVertex3f(-0.5, 0.0, 5.0)
    glVertex3f(0.5, 0.0, 5.0)
    glVertex3f(0.5, 0.0, 5.0)
    glVertex3f(-0.5, 0.0, 6.0)
    glVertex3f(-0.5, 0.0, 6.0)
    glVertex3f(0.5, 0.0, 6.0)

    # Draw the X.
    glVertex3f(5.0, 0.0, 0.5)
    glVertex3f(6.0, 0.0, -0.5)
    glVertex3f(5.0, 0.0, -0.5)
    glVertex3f(6.0, 0.0, 0.5)

    glEnd()
    glLineWidth(1)
    glEndList()

def MakeSphere():
    glNewList(G_OBJ_SPHERE, GL_COMPILE)
    quad = gluNewQuadric();
    gluSphere(quad, 0.5, 30, 30);
    gluDeleteQuadric(quad);
    glEndList();

def MakeCube():
    glNewList(G_OBJ_CUBE, GL_COMPILE)

    glBegin(GL_QUADS);

    glNormal3d(-1.0, 0.0, 0.0)
    glVertex3d(-0.5, -0.5, -0.5)
    glVertex3d(-0.5, -0.5, 0.5)
    glVertex3d(-0.5, 0.5, 0.5)
    glVertex3d(-0.5, 0.5, -0.5)

    glNormal3d(0.0, 0.0, -1.0)
    glVertex3d(-0.5, -0.5, -0.5)
    glVertex3d(-0.5, 0.5, -0.5)
    glVertex3d(0.5, 0.5, -0.5)
    glVertex3d(0.5, -0.5, -0.5)

    glNormal3d(1.0, 0.0, 0.0)
    glVertex3d(0.5, -0.5, -0.5)
    glVertex3d(0.5, 0.5, -0.5)
    glVertex3d(0.5, 0.5, 0.5)
    glVertex3d(0.5, -0.5, 0.5)

    glNormal3d(0.0, 0.0, 1.0)
    glVertex3d(-0.5, -0.5, 0.5)
    glVertex3d(0.5, -0.5, 0.5)
    glVertex3d(0.5, 0.5, 0.5)
    glVertex3d(-0.5, 0.5, 0.5)

    glNormal3d(0.0, -1.0, 0.0)
    glVertex3d(-0.5, -0.5, 0.5)
    glVertex3d(-0.5, -0.5, -0.5)
    glVertex3d(0.5, -0.5, -0.5)
    glVertex3d(0.5, -0.5, 0.5)

    glNormal3d(0.0, 1.0, 0.0)
    glVertex3d(-0.5, 0.5, -0.5)
    glVertex3d(-0.5, 0.5, 0.5)
    glVertex3d(0.5, 0.5, 0.5)
    glVertex3d(0.5, 0.5, -0.5)

    glEnd()
    glEndList()

def InitPrimitives():
    MakePlane()
    MakeSphere()
    MakeCube()