text:
if (typeof DEBUG === "undefined")
    DEBUG = true;
b = (function (window, document) {
    function assert(shoudBeTrue, messageIfFalse) {
        if (DEBUG && !shoudBeTrue)
            throw Error(messageIfFalse || "assertion failed");
    }
    var isArray = Array.isArray;
    function createTextNode(content) {
        return document.createTextNode(content);
    }
    function createElement(name) {
        return document.createElement(name);
    }
    var hasTextContent = "textContent" in createTextNode("");
    function isObject(value) {
        return typeof value === "object";
    }
    function flatten(a) {
        if (!isArray(a)) {
            if (a == null || a === false || a === true)
                return [];
            return [a];
        }
        a = a.slice(0);
        var alen = a.length;
        for (var i = 0; i < alen;) {
            var item = a[i];
            if (isArray(item)) {
                a.splice.apply(a, [i, 1].concat(item));
                alen = a.length;
                continue;
            }
            if (item == null || item === false || item === true) {
                a.splice(i, 1);
                alen--;
                continue;
            }
            i++;
        }
        return a;
    }
    var inSvg = false;
    var updateCall = [];
    var updateInstance = [];
    var setValueCallback = function (el, node, newValue, oldValue) {
        if (newValue !== oldValue)
            el["value"] = newValue;
    };
    function setSetValue(callback) {
        var prev = setValueCallback;
        setValueCallback = callback;
        return prev;
    }
    function newHashObj() {
        return Object.create(null);
    }
    var vendors = ["Webkit", "Moz", "ms", "O"];
    var testingDivStyle = document.createElement("div").style;
    function testPropExistence(name) {
        return typeof testingDivStyle[name] === "string";
    }
    var mapping = newHashObj();
    var isUnitlessNumber = {
        boxFlex: true,
        boxFlexGroup: true,
        columnCount: true,
        flex: true,
        flexGrow: true,
        flexNegative: true,
        flexPositive: true,
        flexShrink: true,
        fontWeight: true,
        lineClamp: true,
        lineHeight: true,
        opacity: true,
        order: true,
        orphans: true,
        strokeDashoffset: true,
        widows: true,
        zIndex: true,
        zoom: true
    };
    function renamer(newName) {
        return function (style, value, oldName) {
            style[newName] = value;
            style[oldName] = undefined;
        };
    }
    function renamerpx(newName) {
        return function (style, value, oldName) {
            if (typeof value === "number") {
                style[newName] = value + "px";
            }
            else {
                style[newName] = value;
            }
            style[oldName] = undefined;
        };
    }
    function pxadder(style, value, name) {
        if (typeof value === "number")
            style[name] = value + "px";
    }
    function ieVersion() {
        return document.documentMode;
    }
    function shimStyle(newValue) {
        var k = Object.keys(newValue);
        for (var i = 0, l = k.length; i < l; i++) {
            var ki = k[i];
            var mi = mapping[ki];
            var vi = newValue[ki];
            if (vi === undefined)
                continue; // don't want to map undefined
            if (mi === undefined) {
                if (DEBUG) {
                    if (ki === "float" && window.console && console.error)
                        console.error("In style instead of 'float' you have to use 'cssFloat'");
                    if (/-/.test(ki) && window.console && console.warn)
                        console.warn("Style property " + ki + " contains dash (must use JS props instead of css names)");
                }
                if (testPropExistence(ki)) {
                    mi = isUnitlessNumber[ki] === true ? null : pxadder;
                }
                else {
                    var titleCaseKi = ki.replace(/^\w/, function (match) { return match.toUpperCase(); });
                    for (var j = 0; j < vendors.length; j++) {
                        if (testPropExistence(vendors[j] + titleCaseKi)) {
                            mi = (isUnitlessNumber[ki] === true ? renamer : renamerpx)(vendors[j] + titleCaseKi);
                            break;
                        }
                    }
                    if (mi === undefined) {
                        mi = isUnitlessNumber[ki] === true ? null : pxadder;
                        if (DEBUG && window.console && console.warn)
                            console.warn("Style property " + ki + " is not supported in this browser");
                    }
                }
                mapping[ki] = mi;
            }
            if (mi !== null)
                mi(newValue, vi, ki);
        }
    }
    function removeProperty(s, name) {
        s[name] = "";
    }
    function updateStyle(n, el, newStyle, oldStyle) {
        var s = el.style;
        if (isObject(newStyle)) {
            shimStyle(newStyle);
            var rule;
            if (isObject(oldStyle)) {
                for (rule in oldStyle) {
                    if (!(rule in newStyle))
                        removeProperty(s, rule);
                }
                for (rule in newStyle) {
                    var v = newStyle[rule];
                    if (v !== undefined) {
                        if (oldStyle[rule] !== v)
                            s[rule] = v;
                    }
                    else {
                        removeProperty(s, rule);
                    }
                }
            }
            else {
                if (oldStyle)
                    s.cssText = "";
                for (rule in newStyle) {
                    var v = newStyle[rule];
                    if (v !== undefined)
                        s[rule] = v;
                }
            }
        }
        else if (newStyle) {
            s.cssText = newStyle;
        }
        else {
            if (isObject(oldStyle)) {
                for (rule in oldStyle) {
                    removeProperty(s, rule);
                }
            }
            else if (oldStyle) {
                s.cssText = "";
            }
        }
    }
    function setClassName(el, className) {
        if (inSvg)
            el.setAttribute("class", className);
        else
            el.className = className;
    }
    function updateElement(n, el, newAttrs, oldAttrs) {
        var attrName, newAttr, oldAttr, valueOldAttr, valueNewAttr;
        for (attrName in newAttrs) {
            newAttr = newAttrs[attrName];
            oldAttr = oldAttrs[attrName];
            if (attrName === "value" && !inSvg) {
                valueOldAttr = oldAttr;
                valueNewAttr = newAttr;
                oldAttrs[attrName] = newAttr;
                continue;
            }
            if (oldAttr !== newAttr) {
                oldAttrs[attrName] = newAttr;
                if (inSvg) {
                    if (attrName === "href")
                        el.setAttributeNS("http://www.w3.org/1999/xlink", "href", newAttr);
                    else
                        el.setAttribute(attrName, newAttr);
                }
                else if (attrName in el && !(attrName === "list" || attrName === "form")) {
                    el[attrName] = newAttr;
                }
                else
                    el.setAttribute(attrName, newAttr);
            }
        }
        for (attrName in oldAttrs) {
            if (oldAttrs[attrName] !== undefined && !(attrName in newAttrs)) {
                oldAttrs[attrName] = undefined;
                el.removeAttribute(attrName);
            }
        }
        if (valueNewAttr !== undefined) {
            setValueCallback(el, n, valueNewAttr, valueOldAttr);
        }
        return oldAttrs;
    }
    function pushInitCallback(c, aupdate) {
        var cc = c.component;
        if (cc) {
            if (cc[aupdate ? "postUpdateDom" : "postInitDom"]) {
                updateCall.push(aupdate);
                updateInstance.push(c);
            }
        }
    }
    function findCfg(parent) {
        var cfg;
        while (parent) {
            cfg = parent.cfg;
            if (cfg !== undefined)
                break;
            if (parent.ctx) {
                cfg = parent.ctx.cfg;
                break;
            }
            parent = parent.parent;
        }
        return cfg;
    }
    function setRef(ref, value) {
        if (ref == null)
            return;
        if (typeof ref === "function") {
            ref(value);
            return;
        }
        var ctx = ref[0];
        var refs = ctx.refs;
        if (!refs) {
            refs = newHashObj();
            ctx.refs = refs;
        }
        refs[ref[1]] = value;
    }
    var currentCtx;
    function getCurrentCtx() {
        return currentCtx;
    }
    function setCurrentCtx(ctx) {
        currentCtx = ctx;
    }
    var currentCtxWithEvents;
    function getCurrentCtxWithEvents() {
        return currentCtxWithEvents;
    }
    function setCurrentCtxWithEvents(ctx) {
        currentCtxWithEvents = ctx;
    }
    function createNode(n, parentNode, createInto, createBefore) {
        var c = {
            // This makes CacheNode just one object class = fast
            tag: n.tag,
            key: n.key,
            ref: n.ref,
            className: n.className,
            style: n.style,
            attrs: n.attrs,
            children: n.children,
            component: n.component,
            data: n.data,
            cfg: n.cfg,
            parent: parentNode,
            element: undefined,
            ctx: undefined
        };
        var backupInSvg = inSvg;
        var component = c.component;
        var el;
        setRef(c.ref, c);
        if (component) {
            var ctx = { data: c.data || {}, me: c, cfg: findCfg(parentNode) };
            c.ctx = ctx;
            currentCtx = ctx;
            currentCtxWithEvents = ctx;
            if (component.init) {
                component.init(ctx, c);
            }
            if (component.render) {
                component.render(ctx, c);
            }
            currentCtxWithEvents = undefined;
            currentCtx = undefined;
        }
        var tag = c.tag;
        var children = c.children;
        if (tag === undefined) {
            if (typeof children === "string") {
                el = createTextNode(children);
                c.element = el;
                createInto.insertBefore(el, createBefore);
            }
            else {
                createChildren(c, createInto, createBefore);
            }
            if (component) {
                if (component.postRender) {
                    component.postRender(c.ctx, c);
                }
                pushInitCallback(c, false);
            }
            return c;
        }
        else if (tag === "/") {
            var htmltext = children;
            if (htmltext === "") {
                // nothing needs to be created
            }
            else if (createBefore == null) {
                var before = createInto.lastChild;
                createInto.insertAdjacentHTML("beforeend", htmltext);
                c.element = [];
                if (before) {
                    before = before.nextSibling;
                }
                else {
                    before = createInto.firstChild;
                }
                while (before) {
                    c.element.push(before);
                    before = before.nextSibling;
                }
            }
            else {
                el = createBefore;
                var elprev = createBefore.previousSibling;
                var removeEl = false;
                var parent = createInto;
                if (!el.insertAdjacentHTML) {
                    el = parent.insertBefore(createElement("i"), el);
                    removeEl = true;
                }
                el.insertAdjacentHTML("beforebegin", htmltext);
                if (elprev) {
                    elprev = elprev.nextSibling;
                }
                else {
                    elprev = parent.firstChild;
                }
                var newElements = [];
                while (elprev !== el) {
                    newElements.push(elprev);
                    elprev = elprev.nextSibling;
                }
                c.element = newElements;
                if (removeEl) {
                    parent.removeChild(el);
                }
            }
            if (component) {
                if (component.postRender) {
                    component.postRender(c.ctx, c);
                }
                pushInitCallback(c, false);
            }
            return c;
        }
        else if (inSvg || tag === "svg") {
            el = document.createElementNS("http://www.w3.org/2000/svg", tag);
            inSvg = true;
        }
        else if (!el) {
            el = createElement(tag);
        }
        createInto.insertBefore(el, createBefore);
        c.element = el;
        createChildren(c, el, null);
        if (component) {
            if (component.postRender) {
                component.postRender(c.ctx, c);
            }
        }
        if (c.attrs)
            c.attrs = updateElement(c, el, c.attrs, {});
        if (c.style)
            updateStyle(c, el, c.style, undefined);
        var className = c.className;
        if (className)
            setClassName(el, className);
        inSvg = backupInSvg;
        pushInitCallback(c, false);
        return c;
    }
    function normalizeNode(n) {
        var t = typeof n;
        if (t === "string") {
            return { children: n };
        }
        if (t === "boolean")
            return null;
        return n;
    }
    function createChildren(c, createInto, createBefore) {
        var ch = c.children;
        if (!ch)
            return;
        if (!isArray(ch)) {
            if (typeof ch === "string") {
                if (hasTextContent) {
                    createInto.textContent = ch;
                }
                else {
                    createInto.innerText = ch;
                }
                return;
            }
            ch = [ch];
        }
        ch = ch.slice(0);
        var i = 0, l = ch.length;
        while (i < l) {
            var item = ch[i];
            if (isArray(item)) {
                ch.splice.apply(ch, [i, 1].concat(item));
                l = ch.length;
                continue;
            }
            item = normalizeNode(item);
            if (item == null) {
                ch.splice(i, 1);
                l--;
                continue;
            }
            ch[i] = createNode(item, c, createInto, createBefore);
            i++;
        }
        c.children = ch;
    }
    function destroyNode(c) {
        setRef(c.ref, null);
        var ch = c.children;
        if (isArray(ch)) {
            for (var i = 0, l = ch.length; i < l; i++) {
                destroyNode(ch[i]);
            }
        }
        var component = c.component;
        if (component) {
            if (component.destroy) {
                var ctx = c.ctx;
                currentCtxWithEvents = ctx;
                component.destroy(ctx, c, c.element);
                currentCtxWithEvents = undefined;
            }
        }
    }
    function removeNodeRecursive(c) {
        var el = c.element;
        if (isArray(el)) {
            var pa = el[0].parentNode;
            if (pa) {
                for (var i = 0; i < el.length; i++) {
                    pa.removeChild(el[i]);
                }
            }
        }
        else if (el != null) {
            var p = el.parentNode;
            if (p)
                p.removeChild(el);
        }
        else {
            var ch = c.children;
            if (isArray(ch)) {
                for (var i = 0, l = ch.length; i < l; i++) {
                    removeNodeRecursive(ch[i]);
                }
            }
        }
    }
    function removeNode(c) {
        destroyNode(c);
        removeNodeRecursive(c);
    }
    var roots = Object.create(null);
    function nodeContainsNode(c, n, resIndex, res) {
        var el = c.element;
        var ch = c.children;
        if (isArray(el)) {
            for (var ii = 0; ii < el.length; ii++) {
                if (el[ii] === n) {
                    res.push(c);
                    if (isArray(ch)) {
                        return ch;
                    }
                    return null;
                }
            }
        }
        else if (el == null) {
            if (isArray(ch)) {
                for (var i = 0; i < ch.length; i++) {
                    var result = nodeContainsNode(ch[i], n, resIndex, res);
                    if (result !== undefined) {
                        res.splice(resIndex, 0, c);
                        return result;
                    }
                }
            }
        }
        else if (el === n) {
            res.push(c);
            if (isArray(ch)) {
                return ch;
            }
            return null;
        }
        return undefined;
    }
    function vdomPath(n) {
        var res = [];
        if (n == null)
            return res;
        var rootIds = Object.keys(roots);
        var rootElements = rootIds.map(function (i) { return roots[i].e || document.body; });
        var nodeStack = [];
        rootFound: while (n) {
            for (var j = 0; j < rootElements.length; j++) {
                if (n === rootElements[j])
                    break rootFound;
            }
            nodeStack.push(n);
            n = n.parentNode;
        }
        if (!n || nodeStack.length === 0)
            return res;
        var currentCacheArray = null;
        var currentNode = nodeStack.pop();
        rootFound2: for (j = 0; j < rootElements.length; j++) {
            if (n === rootElements[j]) {
                var rc = roots[rootIds[j]].c;
                for (var k = 0; k < rc.length; k++) {
                    var rck = rc[k];
                    var findResult = nodeContainsNode(rck, currentNode, res.length, res);
                    if (findResult !== undefined) {
                        currentCacheArray = findResult;
                        break rootFound2;
                    }
                }
            }
        }
        while (nodeStack.length) {
            currentNode = nodeStack.pop();
            if (currentCacheArray && currentCacheArray.length)
                for (var i = 0, l = currentCacheArray.length; i < l; i++) {
                    var bn = currentCacheArray[i];
                    var findResult = nodeContainsNode(bn, currentNode, res.length, res);
                    if (findResult !== undefined) {
                        currentCacheArray = findResult;
                        currentNode = null;
                        break;
                    }
                }
            if (currentNode) {
                res.push(null);
                break;
            }
        }
        return res;
    }
    function getCacheNode(n) {
        var p = vdomPath(n);
        var currentNode = null;
        while (currentNode === null && p.length > 0) {
            currentNode = p.pop();
        }
        return currentNode;
    }
    function finishUpdateNode(n, c, component) {
        if (component) {
            if (component.postRender) {
                currentCtx = c.ctx;
                currentCtxWithEvents = c.ctx;
                component.postRender(c.ctx, n, c);
                currentCtx = undefined;
                currentCtxWithEvents = undefined;
            }
        }
        c.data = n.data;
        pushInitCallback(c, true);
    }
    function updateNode(n, c, createInto, createBefore, deepness) {
        var component = n.component;
        var backupInSvg = inSvg;
        var bigChange = false;
        var ctx = c.ctx;
        if (component != null && ctx != null) {
            if (ctx[ctxInvalidated] === frameCounter) {
                deepness = Math.max(deepness, ctx[ctxDeepness]);
            }
            if (component.id !== c.component.id) {
                bigChange = true;
            }
            else {
                currentCtx = ctx;
                currentCtxWithEvents = ctx;
                if (c.parent != undefined)
                    ctx.cfg = findCfg(c.parent);
                if (component.shouldChange)
                    if (!component.shouldChange(ctx, n, c) && !ignoringShouldChange) {
                        if (isArray(c.children))
                            selectedUpdate(c.children, c.element || createInto, c.element != null ? null : createBefore);
                        return c;
                    }
                ctx.data = n.data || {};
                c.component = component;
                if (component.render) {
                    n = assign({}, n); // need to clone me because it should not be modified for next updates
                    component.render(ctx, n, c);
                }
                c.cfg = n.cfg;
                currentCtx = undefined;
                currentCtxWithEvents = undefined;
            }
        }
        var newChildren = n.children;
        var cachedChildren = c.children;
        var tag = n.tag;
        if (bigChange || (component != null && ctx == null) || (component == null && ctx != null)) {
            // it is big change of component.id or old one was not even component or old one was component and new is not anymore => recreate
        }
        else if (tag === "/") {
            if (c.tag === "/" && cachedChildren === newChildren) {
                finishUpdateNode(n, c, component);
                return c;
            }
        }
        else if (tag === c.tag) {
            if (tag === undefined) {
                if (typeof newChildren === "string" && typeof cachedChildren === "string") {
                    if (newChildren !== cachedChildren) {
                        var el = c.element;
                        if (hasTextContent) {
                            el.textContent = newChildren;
                        }
                        else {
                            el.nodeValue = newChildren;
                        }
                        c.children = newChildren;
                    }
                }
                else {
                    if (deepness <= 0) {
                        if (isArray(cachedChildren))
                            selectedUpdate(c.children, createInto, createBefore);
                    }
                    else {
                        c.children = updateChildren(createInto, newChildren, cachedChildren, c, createBefore, deepness - 1);
                    }
                }
                finishUpdateNode(n, c, component);
                return c;
            }
            else {
                if (tag === "svg") {
                    inSvg = true;
                }
                var el = c.element;
                if (typeof newChildren === "string" && !isArray(cachedChildren)) {
                    if (newChildren !== cachedChildren) {
                        if (hasTextContent) {
                            el.textContent = newChildren;
                        }
                        else {
                            el.innerText = newChildren;
                        }
                        cachedChildren = newChildren;
                    }
                }
                else {
                    if (deepness <= 0) {
                        if (isArray(cachedChildren))
                            selectedUpdate(c.children, el, createBefore);
                    }
                    else {
                        cachedChildren = updateChildren(el, newChildren, cachedChildren, c, null, deepness - 1);
                    }
                }
                c.children = cachedChildren;
                finishUpdateNode(n, c, component);
                if (c.attrs || n.attrs)
                    c.attrs = updateElement(c, el, n.attrs || {}, c.attrs || {});
                updateStyle(c, el, n.style, c.style);
                c.style = n.style;
                var className = n.className;
                if (className !== c.className) {
                    setClassName(el, className || "");
                    c.className = className;
                }
                inSvg = backupInSvg;
                return c;
            }
        }
        var parEl = c.element;
        if (isArray(parEl))
            parEl = parEl[0];
        if (parEl == null)
            parEl = createInto;
        else
            parEl = parEl.parentNode;
        var r = createNode(n, c.parent, parEl, getDomNode(c));
        removeNode(c);
        return r;
    }
    function getDomNode(c) {
        var el = c.element;
        if (el != null) {
            if (isArray(el))
                return el[0];
            return el;
        }
        var ch = c.children;
        if (!isArray(ch))
            return null;
        for (var i = 0; i < ch.length; i++) {
            el = getDomNode(ch[i]);
            if (el)
                return el;
        }
        return null;
    }
    function findNextNode(a, i, len, def) {
        while (++i < len) {
            var ai = a[i];
            if (ai == null)
                continue;
            var n = getDomNode(ai);
            if (n != null)
                return n;
        }
        return def;
    }
    function callPostCallbacks() {
        var count = updateInstance.length;
        for (var i = 0; i < count; i++) {
            var n = updateInstance[i];
            currentCtx = n.ctx;
            currentCtxWithEvents = n.ctx;
            if (updateCall[i]) {
                n.component.postUpdateDom(n.ctx, n, n.element);
            }
            else {
                n.component.postInitDom(n.ctx, n, n.element);
            }
        }
        currentCtx = undefined;
        currentCtxWithEvents = undefined;
        updateCall = [];
        updateInstance = [];
    }
    function updateNodeInUpdateChildren(newNode, cachedChildren, cachedIndex, cachedLength, createBefore, element, deepness) {
        cachedChildren[cachedIndex] = updateNode(newNode, cachedChildren[cachedIndex], element, findNextNode(cachedChildren, cachedIndex, cachedLength, createBefore), deepness);
    }
    function reorderInUpdateChildrenRec(c, element, before) {
        var el = c.element;
        if (el != null) {
            if (isArray(el)) {
                for (var i = 0; i < el.length; i++) {
                    element.insertBefore(el[i], before);
                }
            }
            else
                element.insertBefore(el, before);
            return;
        }
        var ch = c.children;
        if (!isArray(ch))
            return null;
        for (var i = 0; i < ch.length; i++) {
            reorderInUpdateChildrenRec(ch[i], element, before);
        }
    }
    function reorderInUpdateChildren(cachedChildren, cachedIndex, cachedLength, createBefore, element) {
        var before = findNextNode(cachedChildren, cachedIndex, cachedLength, createBefore);
        var cur = cachedChildren[cachedIndex];
        var what = getDomNode(cur);
        if (what != null && what !== before) {
            reorderInUpdateChildrenRec(cur, element, before);
        }
    }
    function reorderAndUpdateNodeInUpdateChildren(newNode, cachedChildren, cachedIndex, cachedLength, createBefore, element, deepness) {
        var before = findNextNode(cachedChildren, cachedIndex, cachedLength, createBefore);
        var cur = cachedChildren[cachedIndex];
        var what = getDomNode(cur);
        if (what != null && what !== before) {
            reorderInUpdateChildrenRec(cur, element, before);
        }
        cachedChildren[cachedIndex] = updateNode(newNode, cur, element, before, deepness);
    }
    function updateChildren(element, newChildren, cachedChildren, parentNode, createBefore, deepness) {
        if (newChildren == null)
            newChildren = [];
        if (!isArray(newChildren)) {
            newChildren = [newChildren];
        }
        if (cachedChildren == null)
            cachedChildren = [];
        if (!isArray(cachedChildren)) {
            if (element.firstChild)
                element.removeChild(element.firstChild);
            cachedChildren = [];
        }
        var newCh = newChildren;
        newCh = newCh.slice(0);
        var newLength = newCh.length;
        var newIndex;
        for (newIndex = 0; newIndex < newLength;) {
            var item = newCh[newIndex];
            if (isArray(item)) {
                newCh.splice.apply(newCh, [newIndex, 1].concat(item));
                newLength = newCh.length;
                continue;
            }
            item = normalizeNode(item);
            if (item == null) {
                newCh.splice(newIndex, 1);
                newLength--;
                continue;
            }
            newCh[newIndex] = item;
            newIndex++;
        }
        return updateChildrenCore(element, newCh, cachedChildren, parentNode, createBefore, deepness);
    }
    function updateChildrenCore(element, newChildren, cachedChildren, parentNode, createBefore, deepness) {
        var newEnd = newChildren.length;
        var cachedLength = cachedChildren.length;
        var cachedEnd = cachedLength;
        var newIndex = 0;
        var cachedIndex = 0;
        while (newIndex < newEnd && cachedIndex < cachedEnd) {
            if (newChildren[newIndex].key === cachedChildren[cachedIndex].key) {
                updateNodeInUpdateChildren(newChildren[newIndex], cachedChildren, cachedIndex, cachedLength, createBefore, element, deepness);
                newIndex++;
                cachedIndex++;
                continue;
            }
            while (true) {
                if (newChildren[newEnd - 1].key === cachedChildren[cachedEnd - 1].key) {
                    newEnd--;
                    cachedEnd--;
                    updateNodeInUpdateChildren(newChildren[newEnd], cachedChildren, cachedEnd, cachedLength, createBefore, element, deepness);
                    if (newIndex < newEnd && cachedIndex < cachedEnd)
                        continue;
                }
                break;
            }
            if (newIndex < newEnd && cachedIndex < cachedEnd) {
                if (newChildren[newIndex].key === cachedChildren[cachedEnd - 1].key) {
                    cachedChildren.splice(cachedIndex, 0, cachedChildren[cachedEnd - 1]);
                    cachedChildren.splice(cachedEnd, 1);
                    reorderAndUpdateNodeInUpdateChildren(newChildren[newIndex], cachedChildren, cachedIndex, cachedLength, createBefore, element, deepness);
                    newIndex++;
                    cachedIndex++;
                    continue;
                }
                if (newChildren[newEnd - 1].key === cachedChildren[cachedIndex].key) {
                    cachedChildren.splice(cachedEnd, 0, cachedChildren[cachedIndex]);
                    cachedChildren.splice(cachedIndex, 1);
                    cachedEnd--;
                    newEnd--;
                    reorderAndUpdateNodeInUpdateChildren(newChildren[newEnd], cachedChildren, cachedEnd, cachedLength, createBefore, element, deepness);
                    continue;
                }
            }
            break;
        }
        if (cachedIndex === cachedEnd) {
            if (newIndex === newEnd) {
                return cachedChildren;
            }
            // Only work left is to add new nodes
            while (newIndex < newEnd) {
                cachedChildren.splice(cachedIndex, 0, createNode(newChildren[newIndex], parentNode, element, findNextNode(cachedChildren, cachedIndex - 1, cachedLength, createBefore)));
                cachedIndex++;
                cachedEnd++;
                cachedLength++;
                newIndex++;
            }
            return cachedChildren;
        }
        if (newIndex === newEnd) {
            // Only work left is to remove old nodes
            while (cachedIndex < cachedEnd) {
                cachedEnd--;
                removeNode(cachedChildren[cachedEnd]);
                cachedChildren.splice(cachedEnd, 1);
            }
            return cachedChildren;
        }
        // order of keyed nodes ware changed => reorder keyed nodes first
        var cachedKeys = newHashObj();
        var newKeys = newHashObj();
        var key;
        var node;
        var backupNewIndex = newIndex;
        var backupCachedIndex = cachedIndex;
        var deltaKeyless = 0;
        for (; cachedIndex < cachedEnd; cachedIndex++) {
            node = cachedChildren[cachedIndex];
            key = node.key;
            if (key != null) {
                assert(!(key in cachedKeys));
                cachedKeys[key] = cachedIndex;
            }
            else
                deltaKeyless--;
        }
        var keyLess = -deltaKeyless - deltaKeyless;
        for (; newIndex < newEnd; newIndex++) {
            node = newChildren[newIndex];
            key = node.key;
            if (key != null) {
                assert(!(key in newKeys));
                newKeys[key] = newIndex;
            }
            else
                deltaKeyless++;
        }
        keyLess += deltaKeyless;
        var delta = 0;
        newIndex = backupNewIndex;
        cachedIndex = backupCachedIndex;
        var cachedKey;
        while (cachedIndex < cachedEnd && newIndex < newEnd) {
            if (cachedChildren[cachedIndex] === null) {
                // already moved somethere else
                cachedChildren.splice(cachedIndex, 1);
                cachedEnd--;
                cachedLength--;
                delta--;
                continue;
            }
            cachedKey = cachedChildren[cachedIndex].key;
            if (cachedKey == null) {
                cachedIndex++;
                continue;
            }
            key = newChildren[newIndex].key;
            if (key == null) {
                newIndex++;
                while (newIndex < newEnd) {
                    key = newChildren[newIndex].key;
                    if (key != null)
                        break;
                    newIndex++;
                }
                if (key == null)
                    break;
            }
            var akpos = cachedKeys[key];
            if (akpos === undefined) {
                // New key
                cachedChildren.splice(cachedIndex, 0, createNode(newChildren[newIndex], parentNode, element, findNextNode(cachedChildren, cachedIndex - 1, cachedLength, createBefore)));
                delta++;
                newIndex++;
                cachedIndex++;
                cachedEnd++;
                cachedLength++;
                continue;
            }
            if (!(cachedKey in newKeys)) {
                // Old key
                removeNode(cachedChildren[cachedIndex]);
                cachedChildren.splice(cachedIndex, 1);
                delta--;
                cachedEnd--;
                cachedLength--;
                continue;
            }
            if (cachedIndex === akpos + delta) {
                // Inplace update
                updateNodeInUpdateChildren(newChildren[newIndex], cachedChildren, cachedIndex, cachedLength, createBefore, element, deepness);
                newIndex++;
                cachedIndex++;
            }
            else {
                // Move
                cachedChildren.splice(cachedIndex, 0, cachedChildren[akpos + delta]);
                delta++;
                cachedChildren[akpos + delta] = null;
                reorderAndUpdateNodeInUpdateChildren(newChildren[newIndex], cachedChildren, cachedIndex, cachedLength, createBefore, element, deepness);
                cachedIndex++;
                cachedEnd++;
                cachedLength++;
                newIndex++;
            }
        }
        // remove old keyed cached nodes
        while (cachedIndex < cachedEnd) {
            if (cachedChildren[cachedIndex] === null) {
                // already moved somethere else
                cachedChildren.splice(cachedIndex, 1);
                cachedEnd--;
                cachedLength--;
                continue;
            }
            if (cachedChildren[cachedIndex].key != null) {
                // this key is only in old
                removeNode(cachedChildren[cachedIndex]);
                cachedChildren.splice(cachedIndex, 1);
                cachedEnd--;
                cachedLength--;
                continue;
            }
            cachedIndex++;
        }
        // add new keyed nodes
        while (newIndex < newEnd) {
            key = newChildren[newIndex].key;
            if (key != null) {
                cachedChildren.splice(cachedIndex, 0, createNode(newChildren[newIndex], parentNode, element, findNextNode(cachedChildren, cachedIndex - 1, cachedLength, createBefore)));
                cachedEnd++;
                cachedLength++;
                delta++;
                cachedIndex++;
            }
            newIndex++;
        }
        // Without any keyless nodes we are done
        if (!keyLess)
            return cachedChildren;
        // calculate common (old and new) keyless
        keyLess = (keyLess - Math.abs(deltaKeyless)) >> 1;
        // reorder just nonkeyed nodes
        newIndex = backupNewIndex;
        cachedIndex = backupCachedIndex;
        while (newIndex < newEnd) {
            if (cachedIndex < cachedEnd) {
                cachedKey = cachedChildren[cachedIndex].key;
                if (cachedKey != null) {
                    cachedIndex++;
                    continue;
                }
            }
            key = newChildren[newIndex].key;
            if (newIndex < cachedEnd && key === cachedChildren[newIndex].key) {
                if (key != null) {
                    newIndex++;
                    continue;
                }
                updateNodeInUpdateChildren(newChildren[newIndex], cachedChildren, newIndex, cachedLength, createBefore, element, deepness);
                keyLess--;
                newIndex++;
                cachedIndex = newIndex;
                continue;
            }
            if (key != null) {
                assert(newIndex === cachedIndex);
                if (keyLess === 0 && deltaKeyless < 0) {
                    while (true) {
                        removeNode(cachedChildren[cachedIndex]);
                        cachedChildren.splice(cachedIndex, 1);
                        cachedEnd--;
                        cachedLength--;
                        deltaKeyless++;
                        assert(cachedIndex !== cachedEnd, "there still need to exist key node");
                        if (cachedChildren[cachedIndex].key != null)
                            break;
                    }
                    continue;
                }
                while (cachedChildren[cachedIndex].key == null)
                    cachedIndex++;
                assert(key === cachedChildren[cachedIndex].key);
                cachedChildren.splice(newIndex, 0, cachedChildren[cachedIndex]);
                cachedChildren.splice(cachedIndex + 1, 1);
                reorderInUpdateChildren(cachedChildren, newIndex, cachedLength, createBefore, element);
                // just moving keyed node it was already updated before
                newIndex++;
                cachedIndex = newIndex;
                continue;
            }
            if (cachedIndex < cachedEnd) {
                cachedChildren.splice(newIndex, 0, cachedChildren[cachedIndex]);
                cachedChildren.splice(cachedIndex + 1, 1);
                reorderAndUpdateNodeInUpdateChildren(newChildren[newIndex], cachedChildren, newIndex, cachedLength, createBefore, element, deepness);
                keyLess--;
                newIndex++;
                cachedIndex++;
            }
            else {
                cachedChildren.splice(newIndex, 0, createNode(newChildren[newIndex], parentNode, element, findNextNode(cachedChildren, newIndex - 1, cachedLength, createBefore)));
                cachedEnd++;
                cachedLength++;
                newIndex++;
                cachedIndex++;
            }
        }
        while (cachedEnd > newIndex) {
            cachedEnd--;
            removeNode(cachedChildren[cachedEnd]);
            cachedChildren.splice(cachedEnd, 1);
        }
        return cachedChildren;
    }
    var hasNativeRaf = false;
    var nativeRaf = window.requestAnimationFrame;
    if (nativeRaf) {
        nativeRaf(function (param) {
            if (param === +param)
                hasNativeRaf = true;
        });
    }
    var now = Date.now || (function () { return new Date().getTime(); });
    var startTime = now();
    var lastTickTime = 0;
    function requestAnimationFrame(callback) {
        if (hasNativeRaf) {
            nativeRaf(callback);
        }
        else {
            var delay = 50 / 3 + lastTickTime - now();
            if (delay < 0)
                delay = 0;
            window.setTimeout(function () {
                lastTickTime = now();
                callback(lastTickTime - startTime);
            }, delay);
        }
    }
    var ctxInvalidated = "$invalidated";
    var ctxDeepness = "$deepness";
    var fullRecreateRequested = true;
    var scheduled = false;
    var initializing = true;
    var uptime = 0;
    var frameCounter = 0;
    var lastFrameDuration = 0;
    var renderFrameBegin = 0;
    var regEvents = {};
    var registryEvents;
    var isPassiveEventHandlerSupported = false;
    try {
        var options = Object.defineProperty({}, "passive", {
            get: function () {
                isPassiveEventHandlerSupported = true;
            }
        });
        window.addEventListener("test", options, options);
        window.removeEventListener("test", options, options);
    }
    catch (err) {
        isPassiveEventHandlerSupported = false;
    }
    function addEvent(name, priority, callback) {
        if (registryEvents == null)
            registryEvents = {};
        var list = registryEvents[name] || [];
        list.push({ priority: priority, callback: callback });
        registryEvents[name] = list;
    }
    function emitEvent(name, ev, target, node) {
        var events = regEvents[name];
        if (events)
            for (var i = 0; i < events.length; i++) {
                if (events[i](ev, target, node))
                    return true;
            }
        return false;
    }
    function addListener(el, name) {
        if (name[0] == "!")
            return;
        var capture = name[0] == "^";
        var eventName = name;
        if (capture) {
            eventName = name.slice(1);
        }
        function enhanceEvent(ev) {
            ev = ev || window.event;
            var t = ev.target || ev.srcElement || el;
            var n = getCacheNode(t);
            emitEvent(name, ev, t, n);
        }
        if ("on" + eventName in window)
            el = window;
        el.addEventListener(eventName, enhanceEvent, isPassiveEventHandlerSupported ? { capture: capture, passive: false } : capture);
    }
    function initEvents() {
        if (registryEvents == null)
            return;
        var eventNames = Object.keys(registryEvents);
        for (var j = 0; j < eventNames.length; j++) {
            var eventName = eventNames[j];
            var arr = registryEvents[eventName];
            arr = arr.sort(function (a, b) { return a.priority - b.priority; });
            regEvents[eventName] = arr.map(function (v) { return v.callback; });
        }
        registryEvents = null;
        var body = document.body;
        for (var i = 0; i < eventNames.length; i++) {
            addListener(body, eventNames[i]);
        }
    }
    function selectedUpdate(cache, element, createBefore) {
        var len = cache.length;
        for (var i = 0; i < len; i++) {
            var node = cache[i];
            var ctx = node.ctx;
            if (ctx != null && ctx[ctxInvalidated] === frameCounter) {
                var cloned = { data: ctx.data, component: node.component };
                cache[i] = updateNode(cloned, node, element, createBefore, ctx[ctxDeepness]);
            }
            else if (isArray(node.children)) {
                var backupInSvg = inSvg;
                if (node.tag === "svg")
                    inSvg = true;
                selectedUpdate(node.children, node.element || element, findNextNode(cache, i, len, createBefore));
                inSvg = backupInSvg;
            }
        }
    }
    var beforeFrameCallback = function () { };
    var afterFrameCallback = function () { };
    function setBeforeFrame(callback) {
        var res = beforeFrameCallback;
        beforeFrameCallback = callback;
        return res;
    }
    function setAfterFrame(callback) {
        var res = afterFrameCallback;
        afterFrameCallback = callback;
        return res;
    }
    function findLastNode(children) {
        for (var i = children.length - 1; i >= 0; i--) {
            var c = children[i];
            var el = c.element;
            if (el != null) {
                if (isArray(el)) {
                    var l = el.length;
                    if (l === 0)
                        continue;
                    return el[l - 1];
                }
                return el;
            }
            var ch = c.children;
            if (!isArray(ch))
                continue;
            var res = findLastNode(ch);
            if (res != null)
                return res;
        }
        return null;
    }
    function syncUpdate() {
        invalidate();
        update(now() - startTime);
    }
    function update(time) {
        renderFrameBegin = now();
        initEvents();
        frameCounter++;
        ignoringShouldChange = nextIgnoreShouldChange;
        nextIgnoreShouldChange = false;
        uptime = time;
        scheduled = false;
        beforeFrameCallback();
        var fullRefresh = false;
        if (fullRecreateRequested) {
            fullRecreateRequested = false;
            fullRefresh = true;
        }
        var rootIds = Object.keys(roots);
        for (var i = 0; i < rootIds.length; i++) {
            var r = roots[rootIds[i]];
            if (!r)
                continue;
            var rc = r.c;
            var insertBefore = findLastNode(rc);
            if (insertBefore != null)
                insertBefore = insertBefore.nextSibling;
            if (fullRefresh) {
                var newChildren = r.f();
                if (newChildren === undefined)
                    break;
                r.e = r.e || document.body;
                r.c = updateChildren(r.e, newChildren, rc, null, insertBefore, 1e6);
            }
            else {
                selectedUpdate(rc, r.e, insertBefore);
            }
        }
        callPostCallbacks();
        var r0 = roots["0"];
        afterFrameCallback(r0 ? r0.c : null);
        lastFrameDuration = now() - renderFrameBegin;
    }
    var nextIgnoreShouldChange = false;
    var ignoringShouldChange = false;
    function ignoreShouldChange() {
        nextIgnoreShouldChange = true;
        invalidate();
    }
    function invalidate(ctx, deepness) {
        if (ctx != null) {
            if (deepness == undefined)
                deepness = 1e6;
            if (ctx[ctxInvalidated] !== frameCounter + 1) {
                ctx[ctxInvalidated] = frameCounter + 1;
                ctx[ctxDeepness] = deepness;
            }
            else {
                if (deepness > ctx[ctxDeepness])
                    ctx[ctxDeepness] = deepness;
            }
        }
        else {
            fullRecreateRequested = true;
        }
        if (scheduled || initializing)
            return;
        scheduled = true;
        requestAnimationFrame(update);
    }
    var lastRootId = 0;
    function addRoot(factory, element, parent) {
        lastRootId++;
        var rootId = "" + lastRootId;
        roots[rootId] = { f: factory, e: element, c: [], p: parent };
        invalidate();
        return rootId;
    }
    function removeRoot(id) {
        var root = roots[id];
        if (!root)
            return;
        if (root.c.length) {
            root.c = updateChildren(root.e, [], root.c, null, null, 1e9);
        }
        delete roots[id];
    }
    function getRoots() {
        return roots;
    }
    function finishInitialize() {
        initializing = false;
        invalidate();
    }
    var beforeInit = finishInitialize;
    function init(factory, element) {
        removeRoot("0");
        roots["0"] = { f: factory, e: element, c: [], p: undefined };
        initializing = true;
        beforeInit();
        beforeInit = finishInitialize;
    }
    function setBeforeInit(callback) {
        var prevBeforeInit = beforeInit;
        beforeInit = function () {
            callback(prevBeforeInit);
        };
    }
    function bubbleEvent(node, name, param) {
        while (node) {
            var c = node.component;
            if (c) {
                var ctx = node.ctx;
                var prevCtx = currentCtxWithEvents;
                currentCtxWithEvents = ctx;
                var m = c[name];
                if (m) {
                    if (m.call(c, ctx, param)) {
                        currentCtxWithEvents = prevCtx;
                        return ctx;
                    }
                }
                m = c.shouldStopBubble;
                if (m) {
                    if (m.call(c, ctx, name, param)) {
                        currentCtxWithEvents = prevCtx;
                        break;
                    }
                }
                currentCtxWithEvents = prevCtx;
            }
            node = node.parent;
        }
        return null;
    }
    function broadcastEventToNode(node, name, param) {
        if (!node)
            return null;
        var c = node.component;
        if (c) {
            var ctx = node.ctx;
            var prevCtx = currentCtxWithEvents;
            currentCtxWithEvents = ctx;
            var m = c[name];
            if (m) {
                if (m.call(c, ctx, param)) {
                    currentCtxWithEvents = prevCtx;
                    return ctx;
                }
            }
            m = c.shouldStopBroadcast;
            if (m) {
                if (m.call(c, ctx, name, param)) {
                    currentCtxWithEvents = prevCtx;
                    return null;
                }
            }
            currentCtxWithEvents = prevCtx;
        }
        var ch = node.children;
        if (isArray(ch)) {
            for (var i = 0; i < ch.length; i++) {
                var res = broadcastEventToNode(ch[i], name, param);
                if (res != null)
                    return res;
            }
        }
        return null;
    }
    function broadcastEvent(name, param) {
        var k = Object.keys(roots);
        for (var i = 0; i < k.length; i++) {
            var ch = roots[k[i]].c;
            if (ch != null) {
                for (var j = 0; j < ch.length; j++) {
                    var res = broadcastEventToNode(ch[j], name, param);
                    if (res != null)
                        return res;
                }
            }
        }
        return null;
    }
    function merge(f1, f2) {
        var _this = this;
        return function () {
            var params = [];
            for (var _i = 0; _i < arguments.length; _i++) {
                params[_i] = arguments[_i];
            }
            var result = f1.apply(_this, params);
            if (result)
                return result;
            return f2.apply(_this, params);
        };
    }
    var emptyObject = {};
    function mergeComponents(c1, c2) {
        var res = Object.create(c1);
        res.super = c1;
        for (var i in c2) {
            if (!(i in emptyObject)) {
                var m = c2[i];
                var origM = c1[i];
                if (i === "id") {
                    res[i] = (origM != null ? origM : "") + "/" + m;
                }
                else if (typeof m === "function" && origM != null && typeof origM === "function") {
                    res[i] = merge(origM, m);
                }
                else {
                    res[i] = m;
                }
            }
        }
        return res;
    }
    function preEnhance(node, methods) {
        var comp = node.component;
        if (!comp) {
            node.component = methods;
            return node;
        }
        node.component = mergeComponents(methods, comp);
        return node;
    }
    function postEnhance(node, methods) {
        var comp = node.component;
        if (!comp) {
            node.component = methods;
            return node;
        }
        node.component = mergeComponents(comp, methods);
        return node;
    }
    function assign(target) {
        var sources = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            sources[_i - 1] = arguments[_i];
        }
        if (target == null)
            target = {};
        var totalArgs = arguments.length;
        for (var i = 1; i < totalArgs; i++) {
            var source = arguments[i];
            if (source == null)
                continue;
            var keys = Object.keys(source);
            var totalKeys = keys.length;
            for (var j = 0; j < totalKeys; j++) {
                var key = keys[j];
                target[key] = source[key];
            }
        }
        return target;
    }
    function preventDefault(event) {
        var pd = event.preventDefault;
        if (pd)
            pd.call(event);
        else
            event.returnValue = false;
    }
    function cloneNodeArray(a) {
        a = a.slice(0);
        for (var i = 0; i < a.length; i++) {
            var n = a[i];
            if (isArray(n)) {
                a[i] = cloneNodeArray(n);
            }
            else if (isObject(n)) {
                a[i] = cloneNode(n);
            }
        }
        return a;
    }
    function cloneNode(node) {
        var r = assign({}, node);
        if (r.attrs) {
            r.attrs = assign({}, r.attrs);
        }
        if (isObject(r.style)) {
            r.style = assign({}, r.style);
        }
        var ch = r.children;
        if (ch) {
            if (isArray(ch)) {
                r.children = cloneNodeArray(ch);
            }
            else if (isObject(ch)) {
                r.children = cloneNode(ch);
            }
        }
        return r;
    }
    function runMethod(methodId, parms) {
        var done = false;
        var roots = b.getRoots();
        var rootKeys = Object.keys(roots);
        for (var i = 0; i < rootKeys.length; i++) {
            var root = roots[rootKeys[i]];
            if (root.p)
                root.p.hasLogicChldrn = true;
        }
        runMethodFrom(getCurrentCtxWithEvents().me, methodId, parms);
        return done;
        function runMethodFrom(currentRoot, methodId, parms) {
            var previousRoot = null;
            while (currentRoot) {
                var comp = currentRoot.component;
                if (comp && comp.runMethod) {
                    var prevCtx = currentCtxWithEvents;
                    currentCtxWithEvents = currentRoot.ctx;
                    if (comp.runMethod(currentRoot.ctx, methodId, parms))
                        done = true;
                    currentCtxWithEvents = prevCtx;
                }
                var children = currentRoot.children;
                if (isArray(children) && !done)
                    loopChildNodes(children);
                if (!done) {
                    var logicalChildren = getLogicalChildren(currentRoot);
                    isArray(logicalChildren) && loopChildNodes(logicalChildren);
                }
                previousRoot = currentRoot;
                currentRoot = currentRoot.parent;
                if (done)
                    return;
            }
            for (var i = 0; i < rootKeys.length; i++) {
                var currRoot = roots[rootKeys[i]];
                var rChlds = currRoot.c;
                var logicalParent = currRoot.p;
                for (var j = 0; j < rChlds.length; j++) {
                    var root = rChlds[j];
                    if (root == previousRoot && logicalParent) {
                        runMethodFrom(logicalParent, methodId, parms);
                        if (done)
                            return;
                    }
                }
            }
            function loopChildNodes(children) {
                for (var i = 0; i < children.length; i++) {
                    var child = children[i];
                    if (child == previousRoot)
                        continue;
                    var comp = child.component;
                    if (comp && comp.runMethod) {
                        var prevCtx = currentCtxWithEvents;
                        currentCtxWithEvents = child.ctx;
                        if (comp.runMethod(child.ctx, methodId, parms)) {
                            done = true;
                            currentCtxWithEvents = prevCtx;
                            return;
                        }
                        currentCtxWithEvents = prevCtx;
                    }
                    isArray(child.children) && !done && loopChildNodes(child.children);
                    if (!done) {
                        var logicalChildren = getLogicalChildren(child);
                        isArray(logicalChildren) && loopChildNodes(logicalChildren);
                    }
                    if (done)
                        return;
                }
            }
        }
        function getLogicalChildren(elm) {
            if (!elm.hasLogicChldrn)
                return null;
            for (var i = 0; i < rootKeys.length; i++) {
                var root = roots[rootKeys[i]];
                if (elm === root.p)
                    return root.c;
            }
        }
    }
    return {
        createNode: createNode,
        updateNode: updateNode,
        updateChildren: updateChildren,
        callPostCallbacks: callPostCallbacks,
        setSetValue: setSetValue,
        setStyleShim: function (name, action) {
            return (mapping[name] = action);
        },
        init: init,
        addRoot: addRoot,
        removeRoot: removeRoot,
        getRoots: getRoots,
        setBeforeFrame: setBeforeFrame,
        setAfterFrame: setAfterFrame,
        setBeforeInit: setBeforeInit,
        isArray: isArray,
        uptime: function () { return uptime; },
        lastFrameDuration: function () { return lastFrameDuration; },
        now: now,
        frame: function () { return frameCounter; },
        assign: assign,
        ieVersion: ieVersion,
        invalidate: invalidate,
        ignoreShouldChange: ignoreShouldChange,
        invalidated: function () { return scheduled; },
        preventDefault: preventDefault,
        vdomPath: vdomPath,
        getDomNode: getDomNode,
        deref: getCacheNode,
        addEvent: addEvent,
        emitEvent: emitEvent,
        bubble: bubbleEvent,
        broadcast: broadcastEvent,
        preEnhance: preEnhance,
        postEnhance: postEnhance,
        cloneNode: cloneNode,
        shimStyle: shimStyle,
        flatten: flatten,
        syncUpdate: syncUpdate,
        mergeComponents: mergeComponents,
        runMethod: runMethod,
        getCurrentCtx: getCurrentCtx,
        setCurrentCtx: setCurrentCtx,
        getCurrentCtxWithEvents: getCurrentCtxWithEvents,
        setCurrentCtxWithEvents: setCurrentCtxWithEvents
    };
})(window, document);


text:
package org.kie.workbench.common.screens.server.management.client.navigation;

import java.util.Collections;
import javax.enterprise.event.Event;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kie.server.controller.api.model.events.ServerTemplateUpdated;
import org.kie.server.controller.api.model.spec.ServerTemplate;
import org.kie.server.controller.api.model.spec.ServerTemplateKey;
import org.kie.workbench.common.screens.server.management.client.events.AddNewServerTemplate;
import org.kie.workbench.common.screens.server.management.client.events.ServerTemplateListRefresh;
import org.kie.workbench.common.screens.server.management.client.events.ServerTemplateSelected;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.Logger;
import org.uberfire.mocks.EventSourceMock;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
public class ServerNavigationPresenterTest {

    @Mock
    Logger logger;

    @Spy
    Event<AddNewServerTemplate> addNewServerTemplateEvent = new EventSourceMock<AddNewServerTemplate>();

    @Spy
    Event<ServerTemplateListRefresh> serverTemplateListRefreshEvent = new EventSourceMock<ServerTemplateListRefresh>();

    @Spy
    Event<ServerTemplateSelected> serverTemplateSelectedEvent = new EventSourceMock<ServerTemplateSelected>();

    @Mock
    ServerNavigationPresenter.View view;

    ServerNavigationPresenter presenter;

    @Before
    public void init() {
        doNothing().when( addNewServerTemplateEvent ).fire( any( AddNewServerTemplate.class ) );
        doNothing().when( serverTemplateListRefreshEvent ).fire( any( ServerTemplateListRefresh.class ) );
        doNothing().when( serverTemplateSelectedEvent ).fire( any( ServerTemplateSelected.class ) );
        presenter = spy( new ServerNavigationPresenter(
                logger, view,
                addNewServerTemplateEvent,
                serverTemplateListRefreshEvent,
                serverTemplateSelectedEvent ) );
    }

    @Test
    public void testInit() {
        presenter.init();

        verify( view ).init( presenter );
        assertEquals( view, presenter.getView() );
    }

    @Test
    public void testClear() {
        presenter.clear();
        verify( view ).clean();
    }

    @Test
    public void testSelect() {
        final String serverId = "serverId";

        presenter.select( serverId );

        final ArgumentCaptor<ServerTemplateSelected> serverTemplateSelectedCaptor = ArgumentCaptor.forClass( ServerTemplateSelected.class );
        verify( serverTemplateSelectedEvent ).fire( serverTemplateSelectedCaptor.capture() );
        assertEquals( serverId, serverTemplateSelectedCaptor.getValue().getServerTemplateKey().getId() );
    }

    @Test
    public void testRefresh() {
        presenter.refresh();

        verify( serverTemplateListRefreshEvent ).fire( any( ServerTemplateListRefresh.class ) );
    }

    @Test
    public void testNewTemplate() {
        presenter.newTemplate();

        verify( addNewServerTemplateEvent ).fire( any( AddNewServerTemplate.class ) );
    }

    @Test
    public void testSetup() {
        final ServerTemplateKey serverTemplateKey = new ServerTemplateKey( "ServerTemplateKeyId", "ServerTemplateKeyName" );
        presenter.setup( serverTemplateKey, Collections.singletonList( serverTemplateKey ) );

        verify( view ).clean();
        verify( view ).addTemplate( serverTemplateKey.getId(), serverTemplateKey.getName() );
    }

    @Test
    public void testSetupList() {
        final ServerTemplateKey serverTemplateKey = new ServerTemplateKey( "ServerTemplateKeyId", "ServerTemplateKeyName" );
        final ServerTemplateKey serverTemplateKey2 = new ServerTemplateKey( "ServerTemplateKeyId2", "ServerTemplateKeyName2" );
        presenter.setup( serverTemplateKey, Collections.singletonList( serverTemplateKey2 ) );

        verify( view ).clean();
        verify( view ).addTemplate( serverTemplateKey.getId(), serverTemplateKey.getName() );
        verify( view ).addTemplate( serverTemplateKey2.getId(), serverTemplateKey2.getName() );
    }

    @Test
    public void testOnSelect() {
        final ServerTemplateKey serverTemplateKey = new ServerTemplateKey( "ServerTemplateKeyId", "ServerTemplateKeyName" );
        presenter.onSelect( new ServerTemplateSelected( serverTemplateKey ) );

        verify( view ).select( serverTemplateKey.getId() );
    }

    @Test
    public void testOnServerTemplateUpdated() {
        final ServerTemplate serverTemplate = new ServerTemplate( "ServerTemplateKeyId", "ServerTemplateKeyName" );
        presenter.onServerTemplateUpdated( new ServerTemplateUpdated( serverTemplate ) );

        verify( view ).addTemplate( serverTemplate.getId(), serverTemplate.getName() );
    }

}

redpajama_set_name: RedPajamaGithub


text:
- Fix for Flicker on initialisation [#425](https://github.com/nostalgiaz/bootstrap-switch/issues/425), [#422](https://github.com/nostalgiaz/bootstrap-switch/issues/422)
- Prevent horizontal misalignment inside modal in page with odd width [#414](https://github.com/nostalgiaz/bootstrap-switch/issues/414)

## 3.3.6

- Revert of switchChange event triggered only on falsy skip [#411](https://github.com/nostalgiaz/bootstrap-switch/issues/411)

## 3.3.0

- Fixed setting of correct state on drag from indeterminate state [#403](https://github.com/nostalgiaz/bootstrap-switch/issues/403)
- Fixed broken state changing on hidden switch [#392, [#383](https://github.com/nostalgiaz/bootstrap-switch/issues/383)
- Missing animation on first state change triggered by side click [#390](https://github.com/nostalgiaz/bootstrap-switch/issues/390)
- SwitchChange event always triggered after change event [#389](https://github.com/nostalgiaz/bootstrap-switch/issues/389)
- Skip check for transitionend event on init [#381](https://github.com/nostalgiaz/bootstrap-switch/issues/381)
- Added stopPropagation on element mousedown [#369](https://github.com/nostalgiaz/bootstrap-switch/issues/369)
- Fixed wrong descrition in documentation [#351](https://github.com/nostalgiaz/bootstrap-switch/issues/351)

## 3.2.2

- Fixed wrong rendering of switch on initialisation if element is hidden [#376](https://github.com/nostalgiaz/bootstrap-switch/issues/376)

## 3.2.1

- Hotfix for broken initialisation logic if $.support.transition is not set [#375](https://github.com/nostalgiaz/bootstrap-switch/issues/375)

## 3.2.0

- Added option and method handleWidth to set a specific width of the side handled [#341](https://github.com/nostalgiaz/bootstrap-switch/issues/341)
- Added option and method labelWidth to set a specific width of the center label [#341](https://github.com/nostalgiaz/bootstrap-switch/issues/341)
- Fixed broken toggling of side handles when switch is wrapped in a external label [#359](https://github.com/nostalgiaz/bootstrap-switch/issues/359)
- Minor refactoring all along the source code

## 3.1.0

- Added inverse option to swap the position of the left and right elements [#207](https://github.com/nostalgiaz/bootstrap-switch/issues/207)
- Fixed misalignment on Safari [#223](https://github.com/nostalgiaz/bootstrap-switch/issues/223)
- Added options toggleAnimate method
- Enhanced documentation with new examples

## 3.0.2

- Added radioAllOff option. allow a group of radio inputs to be all off [#322](https://github.com/nostalgiaz/bootstrap-switch/issues/322)
- Made HTML options overridable by JavaScript initalization options [#319](https://github.com/nostalgiaz/bootstrap-switch/issues/319)
- .form-control does not interfere anymore with the switch appearance [#318](https://github.com/nostalgiaz/bootstrap-switch/issues/318)
- Fixed triggering of two events in case of jQuery id selector [#317](https://github.com/nostalgiaz/bootstrap-switch/issues/317)
- Fixed internal switching loop when toggling with spacebar [#316](https://github.com/nostalgiaz/bootstrap-switch/issues/316)
- Fixed switch label toggling not working with radio inputs [#312](https://github.com/nostalgiaz/bootstrap-switch/issues/312)

## 3.0.1

- Added support for intermediate state [#218](https://github.com/nostalgiaz/bootstrap-switch/issues/218)
- Added change event triggered on label click [#299](https://github.com/nostalgiaz/bootstrap-switch/issues/299)
- Added onInit and onSwitchChange event as methods

## 3.0.0

- API redesign for a more intuitive use
- Entire code source rewriting focused on cleanliness and performance
- Initialization options can be passed as JavaScript object or written as data-*
- Plugin constructor publicly available from $.fn.bootstrapSwitch.Constructor
- Plugin instance publicly available calling .data('bootstrap-switch')
- Global overridable defaults options
- Improved flexibility with baseClass and wrapperClass options
- New onInit event
- Event namespacing
- Full Bootstrap 3 support
- A lot of fixed bug, as usual


text: search_result['441']=["topic_00000000000000DB.html","LocaleHelper.GetAllSupportCultures Method",""];


text:
#[allow(dead_code)]
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
#[allow(non_upper_case_globals)]
mod generated {
    include!(concat!(env!("OUT_DIR"), "/lua.rs"));
}

#[cfg_attr(rustfmt, rustfmt_skip)]
pub use generated::{
    /* struct */
    lua_State,
    lua_CFunction,

    /* function */
    lua_close,
    lua_getglobal,
    lua_gettop,
    lua_newuserdata,
    lua_pcallk,
    lua_pushboolean,
    lua_pushcclosure,
    lua_pushinteger,
    lua_pushlstring,
    lua_pushnil,
    lua_pushnumber,
    lua_setmetatable,
    lua_rawset,
    lua_setglobal,
    lua_settop,
    lua_toboolean,
    lua_tointegerx,
    lua_tonumberx,
    lua_touserdata,
    luaL_loadstring,
    luaL_newmetatable,
    luaL_newstate,
    luaL_tolstring,
};

mod manual {
    use super::generated::*;
    pub fn lua_upvalueindex(i: i32) -> i32 {
        LUA_REGISTRYINDEX - i
    }
}

pub use manual::lua_upvalueindex;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        unsafe {
            let lua = luaL_newstate();
            lua_close(lua);
        }
    }
}


text:
package org.xqqunit.xml.parser;

import java.io.FileNotFoundException;
import java.io.IOException;

import java.util.HashMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.w3c.dom.DOMException;

import org.xqqunit.logging.Logger;
import org.xqqunit.xml.schema.SchemaElement;

/**
 * Parser for XqqUnit schema compliant XML files.
 */
public final class Parser {
	private XqqUnit xqqUnit;

	public Parser() {
		initializeElementClasses();
	}

	/**
	 * Get XqqUnit XML input file root element.
	 * @return root element, instance of XqqUnit
	 */
	public XqqUnit getRootElement() {
		return xqqUnit;
	}

	/**
	 * Execute all test suites.
	 */
	public boolean executeSuites() {
		boolean success = true;
		for (Suite s : xqqUnit.getSuites()) {
			if (!s.execute()) {
				success = false;
			}
		}

		return success;
	}

    /**
     * Parse XqqUnit schema compliant XML file.
     * @param filename XqqUnit XML file.
     * @throws FileNotFoundException The input XML file is not found.
     * @throws SAXParseException The input XML file is not valid XML.
     */
    public void parseXml(final String filename) throws FileNotFoundException, SAXParseException {

        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);

            DocumentBuilder db = dbf.newDocumentBuilder();
            Document dom = db.parse(filename);

            Element rootElement = dom.getDocumentElement();
            if (!SchemaElement.XQQUNIT.getName().equals(rootElement.getTagName())) {
            	//TODO: better exception handing needed
            	throw new RuntimeException("Root element must be 'XqqUnit'! root_element_name:'"+rootElement.getTagName()+"'");
            }

            xqqUnit = (XqqUnit)parseElement(rootElement);
        } catch (ParserConfigurationException pce) {
        	pce.printStackTrace(Logger.err);
        } catch (SAXParseException spe) {
            throw spe;
        } catch (SAXException se) {
        	se.printStackTrace(Logger.err);
        } catch (FileNotFoundException fnfe) {
            throw fnfe;
        } catch (IOException ioe) {
        	ioe.printStackTrace(Logger.err);
        }
    }

    private HashMap<String, XmlClass> elementClassMap;

    /**
     * Check if DOM element has a mapped Class.
     * @param element the DOM element.
     * @return true is element has a mapped class otherwise false.
     */
    private boolean isElementClass(final Element element) {
    	return elementClassMap.containsKey(element.getTagName());
    }

    /**
     * Get XmlClass instance for DOM Element.
     * @param element the element which class is searched.
     * @return XmlClass instance for DOM Element.
     */
    private XmlClass getElementClass(final Element element) {
    	return elementClassMap.get(element.getTagName());
    }

    /**
     * Map XqqUnit schema elements to their corresponding classes.
     */
    private void initializeElementClasses() {
    	elementClassMap = new HashMap<String, XmlClass>();

    	initializeElementClass(Assert.class);
    	initializeElementClass(Case.class);
    	initializeElementClass(Programs.class);
    	initializeElementClass(Program.class);
    	initializeElementClass(Properties.class);
    	initializeElementClass(Property.class);
    	initializeElementClass(Stylesheet.class);
    	initializeElementClass(Stylesheets.class);
    	initializeElementClass(Suite.class);
    	initializeElementClass(XqqUnit.class);
    }

    /**
     * Initialize and map XML element to a class.
     * @param classObject class which has an XML node annotation.
     */
    private void initializeElementClass(final Class<?> classObject) {
		org.xqqunit.xml.parser.annotation.Element elementAnnotation = classObject.getAnnotation(org.xqqunit.xml.parser.annotation.Element.class);
		if (elementAnnotation != null) {
			final String elementName = elementAnnotation.value().getName();
			XmlClass xmlClass = elementClassMap.get(elementName);
			if (xmlClass != null) {
				// TODO better exception handling
				throw new RuntimeException("Element class has already been defined! element:'"+elementName+"', name:'"+xmlClass.getClassObject().getName()+"'");
			}

			xmlClass = new XmlClass(classObject);

			elementClassMap.put(elementName, xmlClass);
		} else {
			// TODO better exception handling
			throw new RuntimeException("Element class must have an org.xqqunit.xml.annotation.Element annotation! name:'"+classObject.getName()+"'");
		}
    }

    /**
     * Parse the XML DOM element structure and populate it to determined class' new instance.
     * @param element The test case assert element.
     * @return Class instance populated with XML data.
     */
    private Object parseElement(final Element element) {
    	//get element's class and create a new class instance
    	XmlClass xmlClass = getElementClass(element);
		Object instance = xmlClass.newInstance();

		xmlClass.invokeBeforeParse(instance);

		//TODO: Refactor this part of parsing. This hack should be generalized via event listener model, new annotation or something similar.
		if (instance instanceof XqqUnit) {
			xqqUnit = (XqqUnit)instance;
		}

		//parse element attributes
		if (element.hasAttributes()) {
			NamedNodeMap namedNodeMap = element.getAttributes();
			for(int i = 0; i < namedNodeMap.getLength(); i++) {
				Node attributeNode = namedNodeMap.item(i);
				if (attributeNode.getNodeType() == Node.ATTRIBUTE_NODE) {
					Attr attribute = (Attr)attributeNode;
					String attributeName = attribute.getName();

					//call attribute's setter method
					xmlClass.setDomObject(attributeName, instance, attribute);
				}
			}
		}

		//parse child elements
        NodeList filterNodeList = element.getChildNodes();
        for (int filterI = 0; filterI < filterNodeList.getLength(); filterI++) {
            Node childNode = filterNodeList.item(filterI);
            if (childNode.getNodeType() == Node.ELEMENT_NODE) {
                Element childElement = (Element) childNode;
                String childElementName = childElement.getTagName();

                //call element's setter method

                if (isElementClass(childElement)) {
                	//element is a "class element", parse it and return new instance for setter
                	xmlClass.setDomObject(childElementName, instance, parseElement(childElement));
                } else {
                	xmlClass.setDomObject(childElementName, instance, childElement);
                }
            }
        }

        xmlClass.invokeAfterParse(instance);

        //TODO: Refactor this part of parsing. This hack should be generalized via event listener model, new annotation or something similar.
    	if (instance instanceof Stylesheet) {
        	Stylesheet stylesheet = (Stylesheet)instance;

            if (!"".equals(stylesheet.getName())) {
            	xqqUnit.getStylesheets().put(stylesheet.getName(), stylesheet);
            } else if (!"".equals(stylesheet.getReference())) {
            	instance = xqqUnit.getStylesheets().get(stylesheet.getReference());
            	if (instance == null) {
            		throw new RuntimeException("couldn't find stylesheet reference! ref:'"+stylesheet.getReference()+"'");
            	}
            } else {
            	throw new DOMException(DOMException.SYNTAX_ERR, "'name' or 'reference' must be defined in stylesheet XML element!");
            }
    	} else if (instance instanceof Program) {
    		Program program = (Program)instance;
            if (!"".equals(program.getName())) {
            	xqqUnit.getPrograms().put(program.getName(), program);
            } else if (!"".equals(program.getReference())) {
            	instance = xqqUnit.getPrograms().get(program.getReference());
            	if (instance == null) {
            		throw new RuntimeException("couldn't find program reference! ref:'"+program.getReference()+"'");
            	}
            } else {
            	throw new DOMException(DOMException.SYNTAX_ERR, "'name' or 'reference' must be defined in program XML element!");
            }
        }

        return instance;
    }
}


text:
class CreateStudentsContactPeople < ActiveRecord::Migration
  def change
    create_table :students_contact_people do |t|
      t.belongs_to :student
      t.belongs_to :contact_person
    end
  end
end


text:
package com.leff.midi.util;

import com.leff.midi.event.MidiEvent;
import com.leff.midi.event.meta.TimeSignature;

/**
 * An event specifically for MidiProcessor to broadcast metronome ticks so that
 * observers need not rely on time conversions or measure tracking
 */
public class MetronomeTick extends MidiEvent
{
    private int mResolution;
    private TimeSignature mSignature;

    private int mCurrentMeasure;
    private int mCurrentBeat;

    private double mMetronomeProgress;
    private int mMetronomeFrequency;

    public MetronomeTick(TimeSignature sig, int resolution)
    {
        super(0, 0);

        mResolution = resolution;

        setTimeSignature(sig);
        mCurrentMeasure = 1;
    }

    public void setTimeSignature(TimeSignature sig)
    {
        mSignature = sig;
        mCurrentBeat = 0;

        setMetronomeFrequency(sig.getMeter());
    }

    public boolean update(double ticksElapsed)
    {
        mMetronomeProgress += ticksElapsed;

        if(mMetronomeProgress >= mMetronomeFrequency)
        {

            mMetronomeProgress %= mMetronomeFrequency;

            mCurrentBeat = (mCurrentBeat + 1) % mSignature.getNumerator();
            if(mCurrentBeat == 0)
            {
                mCurrentMeasure++;
            }

            return true;
        }
        return false;
    }

    public void setMetronomeFrequency(int meter)
    {
        switch(meter)
        {
            case TimeSignature.METER_EIGHTH:
                mMetronomeFrequency = mResolution / 2;
                break;
            case TimeSignature.METER_QUARTER:
                mMetronomeFrequency = mResolution;
                break;
            case TimeSignature.METER_HALF:
                mMetronomeFrequency = mResolution * 2;
                break;
            case TimeSignature.METER_WHOLE:
                mMetronomeFrequency = mResolution * 4;
                break;
        }
    }

    public int getBeatNumber()
    {
        return mCurrentBeat + 1;
    }

    public int getMeasure()
    {
        return mCurrentMeasure;
    }

    @Override
    public String toString()
    {
        return "Metronome: " + mCurrentMeasure + "\t" + getBeatNumber();
    }

    @Override
    public int compareTo(MidiEvent o)
    {
        return 0;
    }

    @Override
    protected int getEventSize()
    {
        return 0;
    }

    @Override
    public int getSize()
    {
        return 0;
    }
}


text:
package org.apache.hadoop.hive.hbase;

import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapred.TableMapReduceUtil;
import org.apache.hadoop.hbase.mapreduce.TableInputFormatBase;
import org.apache.hadoop.hbase.mapreduce.TableSplit;
import org.apache.hadoop.hive.hbase.ColumnMappings.ColumnMapping;
import org.apache.hadoop.hive.ql.exec.SerializationUtilities;
import org.apache.hadoop.hive.ql.index.IndexPredicateAnalyzer;
import org.apache.hadoop.hive.ql.index.IndexSearchCondition;
import org.apache.hadoop.hive.ql.plan.ExprNodeDesc;
import org.apache.hadoop.hive.ql.plan.ExprNodeGenericFuncDesc;
import org.apache.hadoop.hive.ql.plan.TableScanDesc;
import org.apache.hadoop.hive.serde.serdeConstants;
import org.apache.hadoop.hive.serde2.SerDeException;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo;
import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils;
import org.apache.hadoop.hive.shims.ShimLoader;
import org.apache.hadoop.mapred.InputFormat;
import org.apache.hadoop.mapred.InputSplit;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.RecordReader;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.JobContext;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.security.UserGroupInformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * HiveHBaseTableInputFormat implements InputFormat for HBase storage handler
 * tables, decorating an underlying HBase TableInputFormat with extra Hive logic
 * such as column pruning and filter pushdown.
 */
public class HiveHBaseTableInputFormat extends TableInputFormatBase
    implements InputFormat<ImmutableBytesWritable, ResultWritable> {

  static final Logger LOG = LoggerFactory.getLogger(HiveHBaseTableInputFormat.class);
  private static final Object HBASE_TABLE_MONITOR = new Object();

  @Override public RecordReader<ImmutableBytesWritable, ResultWritable> getRecordReader(InputSplit split,
      JobConf jobConf, final Reporter reporter) throws IOException {

    HBaseSplit hbaseSplit = (HBaseSplit) split;
    TableSplit tableSplit = hbaseSplit.getTableSplit();

    final org.apache.hadoop.mapreduce.RecordReader<ImmutableBytesWritable, Result> recordReader;

    Job job = new Job(jobConf);
    TaskAttemptContext tac = ShimLoader.getHadoopShims().newTaskAttemptContext(job.getConfiguration(), reporter);

    final Connection conn;

    synchronized (HBASE_TABLE_MONITOR) {
      conn = ConnectionFactory.createConnection(HBaseConfiguration.create(jobConf));
      initializeTable(conn, tableSplit.getTable());
      setScan(HiveHBaseInputFormatUtil.getScan(jobConf));
      recordReader = createRecordReader(tableSplit, tac);
      try {
        recordReader.initialize(tableSplit, tac);
      } catch (InterruptedException e) {
        closeTable(); // Free up the HTable connections
        conn.close();
        throw new IOException("Failed to initialize RecordReader", e);
      }
    }

    return new RecordReader<ImmutableBytesWritable, ResultWritable>() {

      @Override public void close() throws IOException {
        synchronized (HBASE_TABLE_MONITOR) {
          recordReader.close();
          closeTable();
          conn.close();
        }
      }

      @Override public ImmutableBytesWritable createKey() {
        return new ImmutableBytesWritable();
      }

      @Override public ResultWritable createValue() {
        return new ResultWritable(new Result());
      }

      @Override public long getPos() throws IOException {
        return 0;
      }

      @Override public float getProgress() throws IOException {
        float progress = 0.0F;

        try {
          progress = recordReader.getProgress();
        } catch (InterruptedException e) {
          throw new IOException(e);
        }

        return progress;
      }

      @Override public boolean next(ImmutableBytesWritable rowKey, ResultWritable value) throws IOException {

        boolean next = false;

        try {
          next = recordReader.nextKeyValue();

          if (next) {
            rowKey.set(recordReader.getCurrentValue().getRow());
            value.setResult(recordReader.getCurrentValue());
          }
        } catch (InterruptedException e) {
          throw new IOException(e);
        }

        return next;
      }
    };
  }

  /**
   * Converts a filter (which has been pushed down from Hive's optimizer)
   * into corresponding restrictions on the HBase scan.  The
   * filter should already be in a form which can be fully converted.
   *
   * @param jobConf configuration for the scan
   *
   * @param iKey 0-based offset of key column within Hive table
   *
   * @return converted table split if any
   */
  private Scan createFilterScan(JobConf jobConf, int iKey, int iTimestamp, boolean isKeyBinary) throws IOException {

    // TODO: assert iKey is HBaseSerDe#HBASE_KEY_COL

    Scan scan = new Scan();
    String filterObjectSerialized = jobConf.get(TableScanDesc.FILTER_OBJECT_CONF_STR);
    if (filterObjectSerialized != null) {
      HiveHBaseInputFormatUtil.setupScanRange(scan, filterObjectSerialized, jobConf, false);
      return scan;
    }

    String filterExprSerialized = jobConf.get(TableScanDesc.FILTER_EXPR_CONF_STR);
    if (filterExprSerialized == null) {
      return scan;
    }

    ExprNodeGenericFuncDesc filterExpr = SerializationUtilities.deserializeExpression(filterExprSerialized);

    String keyColName = jobConf.get(serdeConstants.LIST_COLUMNS).split(",")[iKey];
    ArrayList<TypeInfo> cols = TypeInfoUtils.getTypeInfosFromTypeString(jobConf.get(serdeConstants.LIST_COLUMN_TYPES));
    String colType = cols.get(iKey).getTypeName();
    boolean isKeyComparable = isKeyBinary || "string".equalsIgnoreCase(colType);

    String tsColName = null;
    if (iTimestamp >= 0) {
      tsColName = jobConf.get(serdeConstants.LIST_COLUMNS).split(",")[iTimestamp];
    }

    IndexPredicateAnalyzer analyzer = newIndexPredicateAnalyzer(keyColName, isKeyComparable, tsColName);

    List<IndexSearchCondition> conditions = new ArrayList<IndexSearchCondition>();
    ExprNodeDesc residualPredicate = analyzer.analyzePredicate(filterExpr, conditions);

    // There should be no residual since we already negotiated that earlier in
    // HBaseStorageHandler.decomposePredicate. However, with hive.optimize.index.filter
    // OpProcFactory#pushFilterToStorageHandler pushes the original filter back down again.
    // Since pushed-down filters are not omitted at the higher levels (and thus the
    // contract of negotiation is ignored anyway), just ignore the residuals.
    // Re-assess this when negotiation is honored and the duplicate evaluation is removed.
    // THIS IGNORES RESIDUAL PARSING FROM HBaseStorageHandler#decomposePredicate
    if (residualPredicate != null) {
      LOG.debug("Ignoring residual predicate " + residualPredicate.getExprString());
    }

    Map<String, List<IndexSearchCondition>> split = HiveHBaseInputFormatUtil.decompose(conditions);
    List<IndexSearchCondition> keyConditions = split.get(keyColName);
    if (keyConditions != null && !keyConditions.isEmpty()) {
      HiveHBaseInputFormatUtil.setupKeyRange(scan, keyConditions, isKeyBinary);
    }
    List<IndexSearchCondition> tsConditions = split.get(tsColName);
    if (tsConditions != null && !tsConditions.isEmpty()) {
      HiveHBaseInputFormatUtil.setupTimeRange(scan, tsConditions);
    }
    return scan;
  }

  /**
   * Instantiates a new predicate analyzer suitable for
   * determining how to push a filter down into the HBase scan,
   * based on the rules for what kinds of pushdown we currently support.
   *
   * @param keyColumnName name of the Hive column mapped to the HBase row key
   *
   * @return preconfigured predicate analyzer
   */
  static IndexPredicateAnalyzer newIndexPredicateAnalyzer(String keyColumnName, boolean isKeyComparable,
      String timestampColumn) {

    IndexPredicateAnalyzer analyzer = new IndexPredicateAnalyzer();

    // We can always do equality predicate. Just need to make sure we get appropriate
    // BA representation of constant of filter condition.
    // We can do other comparisons only if storage format in hbase is either binary
    // or we are dealing with string types since there lexicographic ordering will suffice.
    if (isKeyComparable) {
      analyzer.addComparisonOp(keyColumnName, "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqual",
          "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqualOrGreaterThan",
          "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqualOrLessThan",
          "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPLessThan",
          "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPGreaterThan");
    } else {
      analyzer.addComparisonOp(keyColumnName, "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqual");
    }

    if (timestampColumn != null) {
      analyzer.addComparisonOp(timestampColumn, "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqual",
          "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqualOrGreaterThan",
          "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPEqualOrLessThan",
          "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPLessThan",
          "org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPGreaterThan");
    }

    return analyzer;
  }

  @Override public InputSplit[] getSplits(final JobConf jobConf, final int numSplits) throws IOException {
    synchronized (HBASE_TABLE_MONITOR) {
      final UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
      if (ugi == null) {
        return getSplitsInternal(jobConf, numSplits);
      }

      try {
        return ugi.doAs(new PrivilegedExceptionAction<InputSplit[]>() {
          @Override public InputSplit[] run() throws IOException {
            return getSplitsInternal(jobConf, numSplits);
          }
        });
      } catch (InterruptedException e) {
        throw new IOException(e);
      }
    }
  }

  private InputSplit[] getSplitsInternal(JobConf jobConf, int numSplits) throws IOException {

    //obtain delegation tokens for the job
    if (UserGroupInformation.getCurrentUser().hasKerberosCredentials()) {
      TableMapReduceUtil.initCredentials(jobConf);
    }

    String hbaseTableName = jobConf.get(HBaseSerDe.HBASE_TABLE_NAME);

    Connection conn = ConnectionFactory.createConnection(HBaseConfiguration.create(jobConf));

    TableName tableName = TableName.valueOf(hbaseTableName);
    initializeTable(conn, tableName);

    String hbaseColumnsMapping = jobConf.get(HBaseSerDe.HBASE_COLUMNS_MAPPING);
    boolean doColumnRegexMatching = jobConf.getBoolean(HBaseSerDe.HBASE_COLUMNS_REGEX_MATCHING, true);

    try {
      if (hbaseColumnsMapping == null) {
        throw new IOException(HBaseSerDe.HBASE_COLUMNS_MAPPING + " required for HBase Table.");
      }

      ColumnMappings columnMappings = null;
      try {
        columnMappings = HBaseSerDe.parseColumnsMapping(hbaseColumnsMapping, doColumnRegexMatching);
      } catch (SerDeException e) {
        throw new IOException(e);
      }

      int iKey = columnMappings.getKeyIndex();
      int iTimestamp = columnMappings.getTimestampIndex();
      ColumnMapping keyMapping = columnMappings.getKeyMapping();

      // Take filter pushdown into account while calculating splits; this
      // allows us to prune off regions immediately.  Note that although
      // the Javadoc for the superclass getSplits says that it returns one
      // split per region, the implementation actually takes the scan
      // definition into account and excludes regions which don't satisfy
      // the start/stop row conditions (HBASE-1829).
      Scan scan = createFilterScan(jobConf, iKey, iTimestamp, HiveHBaseInputFormatUtil
          .getStorageFormatOfKey(keyMapping.mappingSpec,
              jobConf.get(HBaseSerDe.HBASE_TABLE_DEFAULT_STORAGE_TYPE, "string")));

      // The list of families that have been added to the scan
      List<String> addedFamilies = new ArrayList<String>();

      // REVIEW:  are we supposed to be applying the getReadColumnIDs
      // same as in getRecordReader?
      for (ColumnMapping colMap : columnMappings) {
        if (colMap.hbaseRowKey || colMap.hbaseTimestamp) {
          continue;
        }

        if (colMap.qualifierName == null) {
          scan.addFamily(colMap.familyNameBytes);
          addedFamilies.add(colMap.familyName);
        } else {
          if (!addedFamilies.contains(colMap.familyName)) {
            // add the column only if the family has not already been added
            scan.addColumn(colMap.familyNameBytes, colMap.qualifierNameBytes);
          }
        }
      }
      setScan(scan);

      Job job = new Job(jobConf);
      JobContext jobContext = ShimLoader.getHadoopShims().newJobContext(job);
      Path[] tablePaths = FileInputFormat.getInputPaths(jobContext);

      List<org.apache.hadoop.mapreduce.InputSplit> splits = super.getSplits(jobContext);
      InputSplit[] results = new InputSplit[splits.size()];

      for (int i = 0; i < splits.size(); i++) {
        results[i] = new HBaseSplit((TableSplit) splits.get(i), tablePaths[0]);
      }

      return results;
    } finally {
      closeTable();
      conn.close();
    }
  }

  @Override protected void finalize() throws Throwable {
    try {
      closeTable();
    } finally {
      super.finalize();
    }
  }
}


text:
from __future__ import absolute_import

import mock
import pytest
from tornado import gen

from tchannel.tornado import peer as tpeer
from tchannel.tornado.stream import InMemStream
from tchannel.tornado.stream import read_full

def closed_stream(body):
    """Builds an in-memory stream whose entire request body is the given string.

    :param body:
        Request body for the returned Stream
    """
    stream = InMemStream(body)
    stream.close()
    return stream

def mocked_stream():
    # An object that conforms to the stream interface but isn't an instance of
    # Stream.
    def reader():
        if stream.read.call_count == 3:
            return gen.maybe_future('')
        else:
            return gen.maybe_future('foo')

    stream = mock.Mock()
    stream.read.side_effect = reader

    return stream

def test_basic_peer_management_operations():
    peer_group = tpeer.PeerGroup(mock.MagicMock())

    assert not peer_group.hosts
    assert not peer_group.peers
    assert not peer_group.lookup('localhost:4040')

    p = peer_group.get('localhost:4040')

    assert p
    assert peer_group.lookup('localhost:4040') is p
    assert peer_group.get('localhost:4040') is p

    assert peer_group.remove('localhost:4040') is p
    assert not peer_group.lookup('localhost:4040')

    peer_group.add(p)
    assert peer_group.hosts == ['localhost:4040']
    assert peer_group.peers == [p]

@pytest.mark.parametrize('s, expected', [
    (None, b''),
    ('foo', b'foo'),
    (u'☃', b'\xe2\x98\x83'),
    (bytearray([0x12, 0x34]), b'\x12\x34'),
    (closed_stream('foo'), b'foo'),
    (mocked_stream(), b'foofoo')
])
@pytest.mark.gen_test
def test_maybe_stream(s, expected):
    got = yield read_full(tpeer.maybe_stream(s))
    assert expected == got

@pytest.mark.gen_test
def test_peer_group_clear_multiple():
    # Multiple concurrent reset attempts should not conflict with each other.

    peer_group = tpeer.PeerGroup(mock.MagicMock())
    for i in xrange(10):
        peer_group.get('localhost:404%d' % i)

    # A peer that will intentionally take a while to close.
    dirty_peer = mock.MagicMock()
    dirty_peer.close.side_effect = lambda: gen.sleep(0.1)
    peer_group.add(dirty_peer)

    yield [peer_group.clear() for i in xrange(10)]

    # Dirty peer must have been closed only once.
    dirty_peer.close.assert_called_once_with()

    for i in xrange(10):
        assert not peer_group.lookup('localhost:404%d' % i)

@pytest.mark.gen_test
def test_peer_connection_failure():
    # Test connecting a peer when the first connection attempt fails.

    MockConnection = mock.MagicMock()
    connection = mock.MagicMock()

    with mock.patch.object(tpeer.Peer, 'connection_class', MockConnection):

        @gen.coroutine
        def try_connect(*args, **kwargs):
            if MockConnection.outgoing.call_count == 1:
                # If this is the first call, fail.
                raise ZeroDivisionError('great sadness')
            else:
                raise gen.Return(connection)

        MockConnection.outgoing.side_effect = try_connect

        peer = tpeer.Peer(mock.MagicMock(), 'localhost:4040')

        future = peer.connect()
        with pytest.raises(ZeroDivisionError) as excinfo:
            yield future
        assert 'great sadness' in str(excinfo)

        got = yield peer.connect()
        assert got is connection

        assert MockConnection.outgoing.call_count == 2