(function () {
	'use strict';

	function unwrapExports (x) {
		return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
	}

	function createCommonjsModule(fn, module) {
		return module = { exports: {} }, fn(module, module.exports), module.exports;
	}

	var maquette_cjs = createCommonjsModule(function (module, exports) {

	Object.defineProperty(exports, '__esModule', { value: true });

	/* tslint:disable no-http-string */
	var NAMESPACE_W3 = 'http://www.w3.org/';
	/* tslint:enable no-http-string */
	var NAMESPACE_SVG = NAMESPACE_W3 + "2000/svg";
	var NAMESPACE_XLINK = NAMESPACE_W3 + "1999/xlink";
	var emptyArray = [];
	var extend = function (base, overrides) {
	    var result = {};
	    Object.keys(base).forEach(function (key) {
	        result[key] = base[key];
	    });
	    if (overrides) {
	        Object.keys(overrides).forEach(function (key) {
	            result[key] = overrides[key];
	        });
	    }
	    return result;
	};
	var same = function (vnode1, vnode2) {
	    if (vnode1.vnodeSelector !== vnode2.vnodeSelector) {
	        return false;
	    }
	    if (vnode1.properties && vnode2.properties) {
	        if (vnode1.properties.key !== vnode2.properties.key) {
	            return false;
	        }
	        return vnode1.properties.bind === vnode2.properties.bind;
	    }
	    return !vnode1.properties && !vnode2.properties;
	};
	var checkStyleValue = function (styleValue) {
	    if (typeof styleValue !== 'string') {
	        throw new Error('Style values must be strings');
	    }
	};
	var findIndexOfChild = function (children, sameAs, start) {
	    if (sameAs.vnodeSelector !== '') {
	        // Never scan for text-nodes
	        for (var i = start; i < children.length; i++) {
	            if (same(children[i], sameAs)) {
	                return i;
	            }
	        }
	    }
	    return -1;
	};
	var checkDistinguishable = function (childNodes, indexToCheck, parentVNode, operation) {
	    var childNode = childNodes[indexToCheck];
	    if (childNode.vnodeSelector === '') {
	        return; // Text nodes need not be distinguishable
	    }
	    var properties = childNode.properties;
	    var key = properties ? (properties.key === undefined ? properties.bind : properties.key) : undefined;
	    if (!key) { // A key is just assumed to be unique
	        for (var i = 0; i < childNodes.length; i++) {
	            if (i !== indexToCheck) {
	                var node = childNodes[i];
	                if (same(node, childNode)) {
	                    throw new Error(parentVNode.vnodeSelector + " had a " + childNode.vnodeSelector + " child " + (operation === 'added' ? operation : 'removed') + ", but there is now more than one. You must add unique key properties to make them distinguishable.");
	                }
	            }
	        }
	    }
	};
	var nodeAdded = function (vNode) {
	    if (vNode.properties) {
	        var enterAnimation = vNode.properties.enterAnimation;
	        if (enterAnimation) {
	            enterAnimation(vNode.domNode, vNode.properties);
	        }
	    }
	};
	var removedNodes = [];
	var requestedIdleCallback = false;
	var visitRemovedNode = function (node) {
	    (node.children || []).forEach(visitRemovedNode);
	    if (node.properties && node.properties.afterRemoved) {
	        node.properties.afterRemoved.apply(node.properties.bind || node.properties, [node.domNode]);
	    }
	};
	var processPendingNodeRemovals = function () {
	    requestedIdleCallback = false;
	    removedNodes.forEach(visitRemovedNode);
	    removedNodes.length = 0;
	};
	var scheduleNodeRemoval = function (vNode) {
	    removedNodes.push(vNode);
	    if (!requestedIdleCallback) {
	        requestedIdleCallback = true;
	        if (typeof window !== 'undefined' && 'requestIdleCallback' in window) {
	            window.requestIdleCallback(processPendingNodeRemovals, { timeout: 16 });
	        }
	        else {
	            setTimeout(processPendingNodeRemovals, 16);
	        }
	    }
	};
	var nodeToRemove = function (vNode) {
	    var domNode = vNode.domNode;
	    if (vNode.properties) {
	        var exitAnimation = vNode.properties.exitAnimation;
	        if (exitAnimation) {
	            domNode.style.pointerEvents = 'none';
	            var removeDomNode = function () {
	                if (domNode.parentNode) {
	                    domNode.parentNode.removeChild(domNode);
	                    scheduleNodeRemoval(vNode);
	                }
	            };
	            exitAnimation(domNode, removeDomNode, vNode.properties);
	            return;
	        }
	    }
	    if (domNode.parentNode) {
	        domNode.parentNode.removeChild(domNode);
	        scheduleNodeRemoval(vNode);
	    }
	};
	var setProperties = function (domNode, properties, projectionOptions) {
	    if (!properties) {
	        return;
	    }
	    var eventHandlerInterceptor = projectionOptions.eventHandlerInterceptor;
	    var propNames = Object.keys(properties);
	    var propCount = propNames.length;
	    var _loop_1 = function (i) {
	        var propName = propNames[i];
	        var propValue = properties[propName];
	        if (propName === 'className') {
	            throw new Error('Property "className" is not supported, use "class".');
	        }
	        else if (propName === 'class') {
	            propValue.split(/\s+/).forEach(function (token) { return domNode.classList.add(token); });
	        }
	        else if (propName === 'classes') {
	            // object with string keys and boolean values
	            var classNames = Object.keys(propValue);
	            var classNameCount = classNames.length;
	            for (var j = 0; j < classNameCount; j++) {
	                var className = classNames[j];
	                if (propValue[className]) {
	                    domNode.classList.add(className);
	                }
	            }
	        }
	        else if (propName === 'styles') {
	            // object with string keys and string (!) values
	            var styleNames = Object.keys(propValue);
	            var styleCount = styleNames.length;
	            for (var j = 0; j < styleCount; j++) {
	                var styleName = styleNames[j];
	                var styleValue = propValue[styleName];
	                if (styleValue) {
	                    checkStyleValue(styleValue);
	                    projectionOptions.styleApplyer(domNode, styleName, styleValue);
	                }
	            }
	        }
	        else if (propName !== 'key' && propValue !== null && propValue !== undefined) {
	            var type = typeof propValue;
	            if (type === 'function') {
	                if (propName.lastIndexOf('on', 0) === 0) { // lastIndexOf(,0)===0 -> startsWith
	                    if (eventHandlerInterceptor) {
	                        propValue = eventHandlerInterceptor(propName, propValue, domNode, properties); // intercept eventhandlers
	                    }
	                    if (propName === 'oninput') {
	                        /* tslint:disable no-this-keyword no-invalid-this only-arrow-functions no-void-expression */
	                        (function () {
	                            // record the evt.target.value, because IE and Edge sometimes do a requestAnimationFrame between changing value and running oninput
	                            var oldPropValue = propValue;
	                            propValue = function (evt) {
	                                oldPropValue.apply(this, [evt]);
	                                evt.target['oninput-value'] = evt.target.value; // may be HTMLTextAreaElement as well
	                            };
	                        }());
	                        /* tslint:enable */
	                    }
	                    domNode[propName] = propValue;
	                }
	            }
	            else if (projectionOptions.namespace === NAMESPACE_SVG) {
	                if (propName === 'href') {
	                    domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue);
	                }
	                else {
	                    // all SVG attributes are read-only in DOM, so...
	                    domNode.setAttribute(propName, propValue);
	                }
	            }
	            else if (type === 'string' && propName !== 'value' && propName !== 'innerHTML') {
	                domNode.setAttribute(propName, propValue);
	            }
	            else {
	                domNode[propName] = propValue;
	            }
	        }
	    };
	    for (var i = 0; i < propCount; i++) {
	        _loop_1(i);
	    }
	};
	var addChildren = function (domNode, children, projectionOptions) {
	    if (!children) {
	        return;
	    }
	    for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
	        var child = children_1[_i];
	        createDom(child, domNode, undefined, projectionOptions);
	    }
	};
	var initPropertiesAndChildren = function (domNode, vnode, projectionOptions) {
	    addChildren(domNode, vnode.children, projectionOptions); // children before properties, needed for value property of <select>.
	    if (vnode.text) {
	        domNode.textContent = vnode.text;
	    }
	    setProperties(domNode, vnode.properties, projectionOptions);
	    if (vnode.properties && vnode.properties.afterCreate) {
	        vnode.properties.afterCreate.apply(vnode.properties.bind || vnode.properties, [domNode, projectionOptions, vnode.vnodeSelector, vnode.properties, vnode.children]);
	    }
	};
	var createDom = function (vnode, parentNode, insertBefore, projectionOptions) {
	    var domNode;
	    var start = 0;
	    var vnodeSelector = vnode.vnodeSelector;
	    var doc = parentNode.ownerDocument;
	    if (vnodeSelector === '') {
	        domNode = vnode.domNode = doc.createTextNode(vnode.text);
	        if (insertBefore !== undefined) {
	            parentNode.insertBefore(domNode, insertBefore);
	        }
	        else {
	            parentNode.appendChild(domNode);
	        }
	    }
	    else {
	        for (var i = 0; i <= vnodeSelector.length; ++i) {
	            var c = vnodeSelector.charAt(i);
	            if (i === vnodeSelector.length || c === '.' || c === '#') {
	                var type = vnodeSelector.charAt(start - 1);
	                var found = vnodeSelector.slice(start, i);
	                if (type === '.') {
	                    domNode.classList.add(found);
	                }
	                else if (type === '#') {
	                    domNode.id = found;
	                }
	                else {
	                    if (found === 'svg') {
	                        projectionOptions = extend(projectionOptions, { namespace: NAMESPACE_SVG });
	                    }
	                    if (projectionOptions.namespace !== undefined) {
	                        domNode = vnode.domNode = doc.createElementNS(projectionOptions.namespace, found);
	                    }
	                    else {
	                        domNode = vnode.domNode = (vnode.domNode || doc.createElement(found));
	                        if (found === 'input' && vnode.properties && vnode.properties.type !== undefined) {
	                            // IE8 and older don't support setting input type after the DOM Node has been added to the document
	                            domNode.setAttribute('type', vnode.properties.type);
	                        }
	                    }
	                    if (insertBefore !== undefined) {
	                        parentNode.insertBefore(domNode, insertBefore);
	                    }
	                    else if (domNode.parentNode !== parentNode) {
	                        parentNode.appendChild(domNode);
	                    }
	                }
	                start = i + 1;
	            }
	        }
	        initPropertiesAndChildren(domNode, vnode, projectionOptions);
	    }
	};
	var updateDom;
	/**
	 * Adds or removes classes from an Element
	 * @param domNode the element
	 * @param classes a string separated list of classes
	 * @param on true means add classes, false means remove
	 */
	var toggleClasses = function (domNode, classes, on) {
	    if (!classes) {
	        return;
	    }
	    classes.split(' ').forEach(function (c) { return domNode.classList.toggle(c, on); });
	};
	var updateProperties = function (domNode, previousProperties, properties, projectionOptions) {
	    if (!properties) {
	        return;
	    }
	    var propertiesUpdated = false;
	    var propNames = Object.keys(properties);
	    var propCount = propNames.length;
	    for (var i = 0; i < propCount; i++) {
	        var propName = propNames[i];
	        // assuming that properties will be nullified instead of missing is by design
	        var propValue = properties[propName];
	        var previousValue = previousProperties[propName];
	        if (propName === 'class') {
	            if (previousValue !== propValue) {
	                toggleClasses(domNode, previousValue, false);
	                toggleClasses(domNode, propValue, true);
	            }
	        }
	        else if (propName === 'classes') {
	            var classList = domNode.classList;
	            var classNames = Object.keys(propValue);
	            var classNameCount = classNames.length;
	            for (var j = 0; j < classNameCount; j++) {
	                var className = classNames[j];
	                var on = !!propValue[className];
	                var previousOn = !!previousValue[className];
	                if (on === previousOn) {
	                    continue;
	                }
	                propertiesUpdated = true;
	                if (on) {
	                    classList.add(className);
	                }
	                else {
	                    classList.remove(className);
	                }
	            }
	        }
	        else if (propName === 'styles') {
	            var styleNames = Object.keys(propValue);
	            var styleCount = styleNames.length;
	            for (var j = 0; j < styleCount; j++) {
	                var styleName = styleNames[j];
	                var newStyleValue = propValue[styleName];
	                var oldStyleValue = previousValue[styleName];
	                if (newStyleValue === oldStyleValue) {
	                    continue;
	                }
	                propertiesUpdated = true;
	                if (newStyleValue) {
	                    checkStyleValue(newStyleValue);
	                    projectionOptions.styleApplyer(domNode, styleName, newStyleValue);
	                }
	                else {
	                    projectionOptions.styleApplyer(domNode, styleName, '');
	                }
	            }
	        }
	        else {
	            if (!propValue && typeof previousValue === 'string') {
	                propValue = '';
	            }
	            if (propName === 'value') { // value can be manipulated by the user directly and using event.preventDefault() is not an option
	                var domValue = domNode[propName];
	                if (domValue !== propValue // The 'value' in the DOM tree !== newValue
	                    && (domNode['oninput-value']
	                        ? domValue === domNode['oninput-value'] // If the last reported value to 'oninput' does not match domValue, do nothing and wait for oninput
	                        : propValue !== previousValue // Only update the value if the vdom changed
	                    )) {
	                    // The edge cases are described in the tests
	                    domNode[propName] = propValue; // Reset the value, even if the virtual DOM did not change
	                    domNode['oninput-value'] = undefined;
	                } // else do not update the domNode, otherwise the cursor position would be changed
	                if (propValue !== previousValue) {
	                    propertiesUpdated = true;
	                }
	            }
	            else if (propValue !== previousValue) {
	                var type = typeof propValue;
	                if (type !== 'function' || !projectionOptions.eventHandlerInterceptor) { // Function updates are expected to be handled by the EventHandlerInterceptor
	                    if (projectionOptions.namespace === NAMESPACE_SVG) {
	                        if (propName === 'href') {
	                            domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue);
	                        }
	                        else {
	                            // all SVG attributes are read-only in DOM, so...
	                            domNode.setAttribute(propName, propValue);
	                        }
	                    }
	                    else if (type === 'string' && propName !== 'innerHTML') {
	                        if (propName === 'role' && propValue === '') {
	                            domNode.removeAttribute(propName);
	                        }
	                        else {
	                            domNode.setAttribute(propName, propValue);
	                        }
	                    }
	                    else if (domNode[propName] !== propValue) { // Comparison is here for side-effects in Edge with scrollLeft and scrollTop
	                        domNode[propName] = propValue;
	                    }
	                    propertiesUpdated = true;
	                }
	            }
	        }
	    }
	    return propertiesUpdated;
	};
	var updateChildren = function (vnode, domNode, oldChildren, newChildren, projectionOptions) {
	    if (oldChildren === newChildren) {
	        return false;
	    }
	    oldChildren = oldChildren || emptyArray;
	    newChildren = newChildren || emptyArray;
	    var oldChildrenLength = oldChildren.length;
	    var newChildrenLength = newChildren.length;
	    var oldIndex = 0;
	    var newIndex = 0;
	    var i;
	    var textUpdated = false;
	    while (newIndex < newChildrenLength) {
	        var oldChild = (oldIndex < oldChildrenLength) ? oldChildren[oldIndex] : undefined;
	        var newChild = newChildren[newIndex];
	        if (oldChild !== undefined && same(oldChild, newChild)) {
	            textUpdated = updateDom(oldChild, newChild, projectionOptions) || textUpdated;
	            oldIndex++;
	        }
	        else {
	            var findOldIndex = findIndexOfChild(oldChildren, newChild, oldIndex + 1);
	            if (findOldIndex >= 0) {
	                // Remove preceding missing children
	                for (i = oldIndex; i < findOldIndex; i++) {
	                    nodeToRemove(oldChildren[i]);
	                    checkDistinguishable(oldChildren, i, vnode, 'removed');
	                }
	                textUpdated = updateDom(oldChildren[findOldIndex], newChild, projectionOptions) || textUpdated;
	                oldIndex = findOldIndex + 1;
	            }
	            else {
	                // New child
	                createDom(newChild, domNode, (oldIndex < oldChildrenLength) ? oldChildren[oldIndex].domNode : undefined, projectionOptions);
	                nodeAdded(newChild);
	                checkDistinguishable(newChildren, newIndex, vnode, 'added');
	            }
	        }
	        newIndex++;
	    }
	    if (oldChildrenLength > oldIndex) {
	        // Remove child fragments
	        for (i = oldIndex; i < oldChildrenLength; i++) {
	            nodeToRemove(oldChildren[i]);
	            checkDistinguishable(oldChildren, i, vnode, 'removed');
	        }
	    }
	    return textUpdated;
	};
	updateDom = function (previous, vnode, projectionOptions) {
	    var domNode = previous.domNode;
	    var textUpdated = false;
	    if (previous === vnode) {
	        return false; // By contract, VNode objects may not be modified anymore after passing them to maquette
	    }
	    var updated = false;
	    if (vnode.vnodeSelector === '') {
	        if (vnode.text !== previous.text) {
	            var newTextNode = domNode.ownerDocument.createTextNode(vnode.text);
	            domNode.parentNode.replaceChild(newTextNode, domNode);
	            vnode.domNode = newTextNode;
	            textUpdated = true;
	            return textUpdated;
	        }
	        vnode.domNode = domNode;
	    }
	    else {
	        if (vnode.vnodeSelector.lastIndexOf('svg', 0) === 0) { // lastIndexOf(needle,0)===0 means StartsWith
	            projectionOptions = extend(projectionOptions, { namespace: NAMESPACE_SVG });
	        }
	        if (previous.text !== vnode.text) {
	            updated = true;
	            if (vnode.text === undefined) {
	                domNode.removeChild(domNode.firstChild); // the only textnode presumably
	            }
	            else {
	                domNode.textContent = vnode.text;
	            }
	        }
	        vnode.domNode = domNode;
	        updated = updateChildren(vnode, domNode, previous.children, vnode.children, projectionOptions) || updated;
	        updated = updateProperties(domNode, previous.properties, vnode.properties, projectionOptions) || updated;
	        if (vnode.properties && vnode.properties.afterUpdate) {
	            vnode.properties.afterUpdate.apply(vnode.properties.bind || vnode.properties, [domNode, projectionOptions, vnode.vnodeSelector, vnode.properties, vnode.children]);
	        }
	    }
	    if (updated && vnode.properties && vnode.properties.updateAnimation) {
	        vnode.properties.updateAnimation(domNode, vnode.properties, previous.properties);
	    }
	    return textUpdated;
	};
	var createProjection = function (vnode, projectionOptions) {
	    return {
	        getLastRender: function () { return vnode; },
	        update: function (updatedVnode) {
	            if (vnode.vnodeSelector !== updatedVnode.vnodeSelector) {
	                throw new Error('The selector for the root VNode may not be changed. (consider using dom.merge and add one extra level to the virtual DOM)');
	            }
	            var previousVNode = vnode;
	            vnode = updatedVnode;
	            updateDom(previousVNode, updatedVnode, projectionOptions);
	        },
	        domNode: vnode.domNode
	    };
	};

	var DEFAULT_PROJECTION_OPTIONS = {
	    namespace: undefined,
	    performanceLogger: function () { return undefined; },
	    eventHandlerInterceptor: undefined,
	    styleApplyer: function (domNode, styleName, value) {
	        // Provides a hook to add vendor prefixes for browsers that still need it.
	        domNode.style[styleName] = value;
	    }
	};
	var applyDefaultProjectionOptions = function (projectorOptions) {
	    return extend(DEFAULT_PROJECTION_OPTIONS, projectorOptions);
	};
	var dom = {
	    /**
	     * Creates a real DOM tree from `vnode`. The [[Projection]] object returned will contain the resulting DOM Node in
	     * its [[Projection.domNode|domNode]] property.
	     * This is a low-level method. Users will typically use a [[Projector]] instead.
	     * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
	     * objects may only be rendered once.
	     * @param projectionOptions - Options to be used to create and update the projection.
	     * @returns The [[Projection]] which also contains the DOM Node that was created.
	     */
	    create: function (vnode, projectionOptions) {
	        projectionOptions = applyDefaultProjectionOptions(projectionOptions);
	        createDom(vnode, document.createElement('div'), undefined, projectionOptions);
	        return createProjection(vnode, projectionOptions);
	    },
	    /**
	     * Appends a new child node to the DOM which is generated from a [[VNode]].
	     * This is a low-level method. Users will typically use a [[Projector]] instead.
	     * @param parentNode - The parent node for the new child node.
	     * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
	     * objects may only be rendered once.
	     * @param projectionOptions - Options to be used to create and update the [[Projection]].
	     * @returns The [[Projection]] that was created.
	     */
	    append: function (parentNode, vnode, projectionOptions) {
	        projectionOptions = applyDefaultProjectionOptions(projectionOptions);
	        createDom(vnode, parentNode, undefined, projectionOptions);
	        return createProjection(vnode, projectionOptions);
	    },
	    /**
	     * Inserts a new DOM node which is generated from a [[VNode]].
	     * This is a low-level method. Users wil typically use a [[Projector]] instead.
	     * @param beforeNode - The node that the DOM Node is inserted before.
	     * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function.
	     * NOTE: [[VNode]] objects may only be rendered once.
	     * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]].
	     * @returns The [[Projection]] that was created.
	     */
	    insertBefore: function (beforeNode, vnode, projectionOptions) {
	        projectionOptions = applyDefaultProjectionOptions(projectionOptions);
	        createDom(vnode, beforeNode.parentNode, beforeNode, projectionOptions);
	        return createProjection(vnode, projectionOptions);
	    },
	    /**
	     * Merges a new DOM node which is generated from a [[VNode]] with an existing DOM Node.
	     * This means that the virtual DOM and the real DOM will have one overlapping element.
	     * Therefore the selector for the root [[VNode]] will be ignored, but its properties and children will be applied to the Element provided.
	     * This is a low-level method. Users wil typically use a [[Projector]] instead.
	     * @param element - The existing element to adopt as the root of the new virtual DOM. Existing attributes and child nodes are preserved.
	     * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]] objects
	     * may only be rendered once.
	     * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]].
	     * @returns The [[Projection]] that was created.
	     */
	    merge: function (element, vnode, projectionOptions) {
	        projectionOptions = applyDefaultProjectionOptions(projectionOptions);
	        vnode.domNode = element;
	        initPropertiesAndChildren(element, vnode, projectionOptions);
	        return createProjection(vnode, projectionOptions);
	    },
	    /**
	     * Replaces an existing DOM node with a node generated from a [[VNode]].
	     * This is a low-level method. Users will typically use a [[Projector]] instead.
	     * @param element - The node for the [[VNode]] to replace.
	     * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
	     * objects may only be rendered once.
	     * @param projectionOptions - Options to be used to create and update the [[Projection]].
	     * @returns The [[Projection]] that was created.
	     */
	    replace: function (element, vnode, projectionOptions) {
	        projectionOptions = applyDefaultProjectionOptions(projectionOptions);
	        createDom(vnode, element.parentNode, element, projectionOptions);
	        element.parentNode.removeChild(element);
	        return createProjection(vnode, projectionOptions);
	    }
	};

	/* tslint:disable function-name */
	var toTextVNode = function (data) {
	    return {
	        vnodeSelector: '',
	        properties: undefined,
	        children: undefined,
	        text: data.toString(),
	        domNode: null
	    };
	};
	var appendChildren = function (parentSelector, insertions, main) {
	    for (var i = 0, length_1 = insertions.length; i < length_1; i++) {
	        var item = insertions[i];
	        if (Array.isArray(item)) {
	            appendChildren(parentSelector, item, main);
	        }
	        else {
	            if (item !== null && item !== undefined && item !== false) {
	                if (typeof item === 'string') {
	                    item = toTextVNode(item);
	                }
	                main.push(item);
	            }
	        }
	    }
	};
	function h(selector, properties, children) {
	    if (Array.isArray(properties)) {
	        children = properties;
	        properties = undefined;
	    }
	    else if ((properties && (typeof properties === 'string' || properties.hasOwnProperty('vnodeSelector'))) ||
	        (children && (typeof children === 'string' || children.hasOwnProperty('vnodeSelector')))) {
	        throw new Error('h called with invalid arguments');
	    }
	    var text;
	    var flattenedChildren;
	    // Recognize a common special case where there is only a single text node
	    if (children !== undefined && children.length === 1 && typeof children[0] === 'string') {
	        text = children[0];
	    }
	    else if (children) {
	        flattenedChildren = [];
	        appendChildren(selector, children, flattenedChildren);
	        if (flattenedChildren.length === 0) {
	            flattenedChildren = undefined;
	        }
	    }
	    return {
	        vnodeSelector: selector,
	        properties: properties,
	        children: flattenedChildren,
	        text: (text === '') ? undefined : text,
	        domNode: null
	    };
	}

	var createParentNodePath = function (node, rootNode) {
	    var parentNodePath = [];
	    while (node !== rootNode) {
	        parentNodePath.push(node);
	        node = node.parentNode;
	    }
	    return parentNodePath;
	};
	var find;
	if (Array.prototype.find) {
	    find = function (items, predicate) { return items.find(predicate); };
	}
	else {
	    find = function (items, predicate) { return items.filter(predicate)[0]; };
	}
	var findVNodeByParentNodePath = function (vnode, parentNodePath) {
	    var result = vnode;
	    parentNodePath.forEach(function (node) {
	        result = (result && result.children) ? find(result.children, function (child) { return child.domNode === node; }) : undefined;
	    });
	    return result;
	};
	var createEventHandlerInterceptor = function (projector, getProjection, performanceLogger) {
	    var modifiedEventHandler = function (evt) {
	        performanceLogger('domEvent', evt);
	        var projection = getProjection();
	        var parentNodePath = createParentNodePath(evt.currentTarget, projection.domNode);
	        parentNodePath.reverse();
	        var matchingVNode = findVNodeByParentNodePath(projection.getLastRender(), parentNodePath);
	        projector.scheduleRender();
	        var result;
	        if (matchingVNode) {
	            /* tslint:disable no-invalid-this */
	            result = matchingVNode.properties["on" + evt.type].apply(matchingVNode.properties.bind || this, arguments);
	            /* tslint:enable no-invalid-this */
	        }
	        performanceLogger('domEventProcessed', evt);
	        return result;
	    };
	    return function (propertyName, eventHandler, domNode, properties) { return modifiedEventHandler; };
	};
	/**
	 * Creates a [[Projector]] instance using the provided projectionOptions.
	 *
	 * For more information, see [[Projector]].
	 *
	 * @param projectorOptions   Options that influence how the DOM is rendered and updated.
	 */
	var createProjector = function (projectorOptions) {
	    var projector;
	    var projectionOptions = applyDefaultProjectionOptions(projectorOptions);
	    var performanceLogger = projectionOptions.performanceLogger;
	    var renderCompleted = true;
	    var scheduled;
	    var stopped = false;
	    var projections = [];
	    var renderFunctions = []; // matches the projections array
	    var addProjection = function (
	    /* one of: dom.append, dom.insertBefore, dom.replace, dom.merge */
	    domFunction, 
	    /* the parameter of the domFunction */
	    node, renderFunction) {
	        var projection;
	        var getProjection = function () { return projection; };
	        projectionOptions.eventHandlerInterceptor = createEventHandlerInterceptor(projector, getProjection, performanceLogger);
	        projection = domFunction(node, renderFunction(), projectionOptions);
	        projections.push(projection);
	        renderFunctions.push(renderFunction);
	    };
	    var doRender = function () {
	        scheduled = undefined;
	        if (!renderCompleted) {
	            return; // The last render threw an error, it should have been logged in the browser console.
	        }
	        renderCompleted = false;
	        performanceLogger('renderStart', undefined);
	        for (var i = 0; i < projections.length; i++) {
	            var updatedVnode = renderFunctions[i]();
	            performanceLogger('rendered', undefined);
	            projections[i].update(updatedVnode);
	            performanceLogger('patched', undefined);
	        }
	        performanceLogger('renderDone', undefined);
	        renderCompleted = true;
	    };
	    projector = {
	        renderNow: doRender,
	        scheduleRender: function () {
	            if (!scheduled && !stopped) {
	                scheduled = requestAnimationFrame(doRender);
	            }
	        },
	        stop: function () {
	            if (scheduled) {
	                cancelAnimationFrame(scheduled);
	                scheduled = undefined;
	            }
	            stopped = true;
	        },
	        resume: function () {
	            stopped = false;
	            renderCompleted = true;
	            projector.scheduleRender();
	        },
	        append: function (parentNode, renderFunction) {
	            addProjection(dom.append, parentNode, renderFunction);
	        },
	        insertBefore: function (beforeNode, renderFunction) {
	            addProjection(dom.insertBefore, beforeNode, renderFunction);
	        },
	        merge: function (domNode, renderFunction) {
	            addProjection(dom.merge, domNode, renderFunction);
	        },
	        replace: function (domNode, renderFunction) {
	            addProjection(dom.replace, domNode, renderFunction);
	        },
	        detach: function (renderFunction) {
	            for (var i = 0; i < renderFunctions.length; i++) {
	                if (renderFunctions[i] === renderFunction) {
	                    renderFunctions.splice(i, 1);
	                    return projections.splice(i, 1)[0];
	                }
	            }
	            throw new Error('renderFunction was not found');
	        }
	    };
	    return projector;
	};

	/**
	 * Creates a [[CalculationCache]] object, useful for caching [[VNode]] trees.
	 * In practice, caching of [[VNode]] trees is not needed, because achieving 60 frames per second is almost never a problem.
	 * For more information, see [[CalculationCache]].
	 *
	 * @param <Result> The type of the value that is cached.
	 */
	var createCache = function () {
	    var cachedInputs;
	    var cachedOutcome;
	    return {
	        invalidate: function () {
	            cachedOutcome = undefined;
	            cachedInputs = undefined;
	        },
	        result: function (inputs, calculation) {
	            if (cachedInputs) {
	                for (var i = 0; i < inputs.length; i++) {
	                    if (cachedInputs[i] !== inputs[i]) {
	                        cachedOutcome = undefined;
	                    }
	                }
	            }
	            if (!cachedOutcome) {
	                cachedOutcome = calculation();
	                cachedInputs = inputs;
	            }
	            return cachedOutcome;
	        }
	    };
	};

	/**
	 * Creates a {@link Mapping} instance that keeps an array of result objects synchronized with an array of source objects.
	 * See {@link http://maquettejs.org/docs/arrays.html|Working with arrays}.
	 *
	 * @param <Source>       The type of source items. A database-record for instance.
	 * @param <Target>       The type of target items. A [[MaquetteComponent]] for instance.
	 * @param getSourceKey   `function(source)` that must return a key to identify each source object. The result must either be a string or a number.
	 * @param createResult   `function(source, index)` that must create a new result object from a given source. This function is identical
	 *                       to the `callback` argument in `Array.map(callback)`.
	 * @param updateResult   `function(source, target, index)` that updates a result to an updated source.
	 */
	var createMapping = function (getSourceKey, createResult, updateResult) {
	    var keys = [];
	    var results = [];
	    return {
	        results: results,
	        map: function (newSources) {
	            var newKeys = newSources.map(getSourceKey);
	            var oldTargets = results.slice();
	            var oldIndex = 0;
	            for (var i = 0; i < newSources.length; i++) {
	                var source = newSources[i];
	                var sourceKey = newKeys[i];
	                if (sourceKey === keys[oldIndex]) {
	                    results[i] = oldTargets[oldIndex];
	                    updateResult(source, oldTargets[oldIndex], i);
	                    oldIndex++;
	                }
	                else {
	                    var found = false;
	                    for (var j = 1; j < keys.length + 1; j++) {
	                        var searchIndex = (oldIndex + j) % keys.length;
	                        if (keys[searchIndex] === sourceKey) {
	                            results[i] = oldTargets[searchIndex];
	                            updateResult(newSources[i], oldTargets[searchIndex], i);
	                            oldIndex = searchIndex + 1;
	                            found = true;
	                            break;
	                        }
	                    }
	                    if (!found) {
	                        results[i] = createResult(source, i);
	                    }
	                }
	            }
	            results.length = newSources.length;
	            keys = newKeys;
	        }
	    };
	};

	exports.dom = dom;
	exports.h = h;
	exports.createProjector = createProjector;
	exports.createCache = createCache;
	exports.createMapping = createMapping;
	});

	unwrapExports(maquette_cjs);
	var maquette_cjs_1 = maquette_cjs.dom;
	var maquette_cjs_2 = maquette_cjs.h;
	var maquette_cjs_3 = maquette_cjs.createProjector;
	var maquette_cjs_4 = maquette_cjs.createCache;
	var maquette_cjs_5 = maquette_cjs.createMapping;

	function _random(max) {
		return Math.round(Math.random()*1000)%max;
	}

	function Store() {
		this.data = [];
		this.backup = null;
		this.selected = null;
		this.id = 1;
	}

	Store.prototype = {
		constructor: Store,

		buildData: function(count) {
			count = count || 1000;

			var adjectives = ["pretty", "large", "big", "small", "tall", "short", "long", "handsome", "plain", "quaint", "clean", "elegant", "easy", "angry", "crazy", "helpful", "mushy", "odd", "unsightly", "adorable", "important", "inexpensive", "cheap", "expensive", "fancy"];
			var colours = ["red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black", "orange"];
			var nouns = ["table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger", "pizza", "mouse", "keyboard"];
			var data = [];
			for (var i = 0; i < count; i++)
				{ data.push({id: this.id++, label: adjectives[_random(adjectives.length)] + " " + colours[_random(colours.length)] + " " + nouns[_random(nouns.length)] }); }
			return data;
		},

		updateData: function(mod) {
			mod = mod || 10;

			for (var i=0;i<this.data.length;i+=10) {
				this.data[i].label += ' !!!';
			//	this.data[i] = Object.assign({}, this.data[i], {label: this.data[i].label +' !!!'});
			}
		},

		delete: function(id) {
			var idx = this.data.findIndex(function (d) { return d.id==id; });
			this.data = this.data.filter(function (e,i) { return i!=idx; });
			return this;
		},

		run: function() {
			this.data = this.buildData();
			this.selected = null;
		},

		add: function() {
			this.data = this.data.concat(this.buildData(1000));
		},

		update: function() {
			this.updateData();
		},

		select: function(id) {
			this.selected = id;
		},

		hideAll: function() {
			this.backup = this.data;
			this.data = [];
		},

		showAll: function() {
			this.data = this.backup;
			this.backup = null;
		},

		runLots: function() {
			this.data = this.buildData(10000);
			this.selected = null;
		},

		clear: function() {
			this.data = [];
			this.selected = null;
		},

		swapRows: function() {
			if(this.data.length > 998) {
				var a = this.data[1];
				this.data[1] = this.data[998];
				this.data[998] = a;
			}
		},
	};

	var projector = maquette_cjs_3({});

	var store = new Store();
	var app = App();

	projector.append(document.body, app.render);

	function App() {
		var jumbo = Jumbotron();
		var table = Table();

		return {
			render: function () { return maquette_cjs_2("div#main", [
					maquette_cjs_2("div.container", [
						jumbo.render(),
						table.render(),
						maquette_cjs_2("span.preloadicon.glyphicon.glyphicon-remove", {"aria-hidden": "true"})
					])
				]); }
		};
	}

	function Jumbotron() {
		var exec = function (name) { return function (e) {
			store[name]();
		}; };

		var run			= exec("run");
		var runLots		= exec("runLots");
		var add			= exec("add");
		var update		= exec("update");
		var clear		= exec("clear");
		var swapRows	= exec("swapRows");

		return {
			render: function () { return maquette_cjs_2("div.jumbotron", [
					maquette_cjs_2("div.row", [
						maquette_cjs_2("div.col-md-6", [
							maquette_cjs_2("h1", ["maquette v3.0.1 (keyed)"])
						]),
						maquette_cjs_2("div.col-md-6", [
							maquette_cjs_2("div.row", [
								maquette_cjs_2("div.col-sm-6.smallpad", [
									maquette_cjs_2("button.btn.btn-primary.btn-block#run", {type: "button", onclick: run}, ["Create 1,000 rows"])
								]),
								maquette_cjs_2("div.col-sm-6.smallpad", [
									maquette_cjs_2("button.btn.btn-primary.btn-block#runlots", {type: "button", onclick: runLots}, ["Create 10,000 rows"])
								]),
								maquette_cjs_2("div.col-sm-6.smallpad", [
									maquette_cjs_2("button.btn.btn-primary.btn-block#add", {type: "button", onclick: add}, ["Append 1,000 rows"])
								]),
								maquette_cjs_2("div.col-sm-6.smallpad", [
									maquette_cjs_2("button.btn.btn-primary.btn-block#update", {type: "button", onclick: update}, ["Update every 10th row"])
								]),
								maquette_cjs_2("div.col-sm-6.smallpad", [
									maquette_cjs_2("button.btn.btn-primary.btn-block#clear", {type: "button", onclick: clear}, ["Clear"])
								]),
								maquette_cjs_2("div.col-sm-6.smallpad", [
									maquette_cjs_2("button.btn.btn-primary.btn-block#swaprows", {type: "button", onclick: swapRows}, ["Swap Rows"])
								])
							])
						])
					])
				]); }
		};
	}

	function Table() {
		// delegated handler
		function tableClick(e) {
			var node = e.target;

			if (node.matches(".remove, .remove *")) {
				while (node.nodeName != "TR")
					{ node = node.parentNode; }
				store.delete(+node.firstChild.textContent);
				e.stopPropagation();
			}
			else if (node.matches(".lbl")) {
				while (node.nodeName != "TR")
					{ node = node.parentNode; }
				store.select(+node.firstChild.textContent);
				e.stopPropagation();
			}
		}

		return {
			render: function () { return maquette_cjs_2("table.table.table-hover.table-striped.test-data", {onclick: tableClick}, [
					maquette_cjs_2("tbody", store.data.map(function (item) { return maquette_cjs_2("tr" + (item.id === store.selected ? '.danger' : ''), {key: item.id}, [
							maquette_cjs_2("td.col-md-1", [""+item.id]),
							maquette_cjs_2("td.col-md-4", [
								maquette_cjs_2("a.lbl", [item.label])
							]),
							maquette_cjs_2("td.col-md-1", [
								maquette_cjs_2("a.remove", [
									maquette_cjs_2("span.glyphicon.glyphicon-remove", {"aria-hidden": "true"})
								])
							]),
							maquette_cjs_2("td.col-md-6")
						]); }
					))
				]); }
		};
	}

}());
