<commit_before>(function(DOM, VK_SPACE, VK_TAB, VK_ENTER, VK_ESCAPE, VK_BACKSPACE, VK_DELETE, VK_CONTROL) {
    "use strict";

    var emmet = DOM.emmetLiteral,
        HTML = DOM.get("documentElement"),
        BASE_CLASS = "btr-dateinput-calendar",
        ampm = (pos, neg) => HTML.lang === "en-US" ? pos : neg,
        formatISODate = (value) => value.toISOString().split("T")[0],
        PICKER_TEMPLATE = DOM.create(emmet `div.${BASE_CLASS}>(p.${BASE_CLASS}-header>a[unselectable=on]*2+time[is=local-time data-format='MMMM yyyy' aria-hidden=true unselectable=on].${BASE_CLASS}-caption)`),
        DAYS_TEMPLATE = DOM.create(emmet `table[aria-hidden=true].${BASE_CLASS}-days>(thead>(tr>(th[unselectable=on]>time[is=local-time datetime='${ampm(2001,2002)}-01-$$@6T21:00:00.000Z' data-format=E])*7)+(tbody.${BASE_CLASS}-body>tr*6>td*7))`),
        MONTHS_TEMPLATE = DOM.create(emmet `table[aria-hidden=true].${BASE_CLASS}-months>tbody>tr*3>td*4>time[is=local-time data-format=MMM])`),
        LABEL_TEMPLATE = DOM.create(emmet `time[is=local-time aria-hidden=true].btr-dateinput-value`),
        readDateRange = (el) => ["min", "max"].map((x) => new Date(el.get(x) || ""));

    MONTHS_TEMPLATE.findAll("time").forEach((time, index) => {
        time.set("datetime", new Date(2001, index, 1, 12).toISOString());
    });

    PICKER_TEMPLATE.append(DAYS_TEMPLATE).append(MONTHS_TEMPLATE);

    DOM.extend("input[type=date]", {
        constructor() {
            if (this._isNative()) return false;

            var defaultValue = this.get("defaultValue"),
                picker = PICKER_TEMPLATE.clone(true),
                label = LABEL_TEMPLATE.clone(true),
                textColor = this.css("color"),
                calenderDays = picker.find(`.${BASE_CLASS}-body`),
                calendarMonths = picker.find(`.${BASE_CLASS}-months`),
                calendarCaption = picker.find(`.${BASE_CLASS}-caption`),
                invalidatePicker = this._invalidatePicker.bind(this, calendarCaption, calendarMonths, calenderDays, picker);

            this// hide original input text
                // IE8 doesn't suport color:transparent - use background-color instead
                .css("color", document.addEventListener ? "transparent" : this.css("background-color"))
                // sync picker visibility on focus/blur
                .on(["focus", "click"], this._focusPicker.bind(this, picker))
                .on("blur", this._blurPicker.bind(this, picker))
                .on("change", this._syncValue.bind(this, "value", label))
                .on("keydown", ["which"], this._keydownPicker.bind(this, picker))
                .value(defaultValue); // restore initial value

            label
                .set("data-format", this.get("data-format") || "E, dd MMM yyyy")
                .css(this.css(["width", "font", "padding", "text-align", "border-width", "box-sizing"]))
                .css({color: textColor, "line-height": ""}) // IE10 returns invalid line-height for hidden elements
                .on("click", this._clickLabel.bind(this))
                .watch("datetime", invalidatePicker)
                .set("datetime", defaultValue);

            this
                .before(picker.hide(), label)
                .closest("form").on("reset", this._syncValue.bind(this, "defaultValue", label));

            picker
                .watch("aria-expanded", invalidatePicker)
                .on("mousedown", ["target"], this._clickPicker.bind(this, picker, calendarMonths))
                .css("z-index", 1 + (this.css("z-index") | 0));

            calendarCaption
                .on("click", this._clickPickerCaption.bind(this, picker));

            // display calendar for autofocused elements
            if (this.matches(":focus")) picker.show();
        },
        _isNative() {
            var polyfillType = this.get("data-polyfill"),
                deviceType = "orientation" in window ? "mobile" : "desktop";

            if (polyfillType === "none") return true;

            if (!polyfillType || polyfillType === deviceType && polyfillType !== "all") {
                // use a stronger type support detection that handles old WebKit browsers:
                // http://www.quirksmode.org/blog/archives/2015/03/better_modern_i.html
                if (this[0].type === "date") return true;
                // persist current value to restore it later
                this.set("defaultValue", this.value());
                // if browser allows invalid value then it doesn't support the feature
                return this.value("_").value() !== "_";
            } else {
                // remove native control
                this.set("type", "text");
                // force applying the polyfill
                return false;
            }
        },
        _invalidatePicker(caption, calendarMonths, calenderDays, picker) {
            var expanded = picker.get("aria-expanded") === "true";
            var value = new Date(this.value());
            var year, month, date;

            if (!value.getTime()) {
                value = new Date();
            }

            month = value.getUTCMonth();
            date = value.getUTCDate();
            year = value.getUTCFullYear();

            var range = readDateRange(this);
            var iterDate = new Date(Date.UTC(year, month, 0));

            if (expanded) {
                calendarMonths.findAll("td").forEach((day, index) => {
                    iterDate.setUTCMonth(index);

                    var mDiff = month - iterDate.getUTCMonth(),
                        className = BASE_CLASS;

                    if (iterDate < range[0] || iterDate > range[1]) {
                        className += "-out";
                    } else if (!mDiff) {
                        className += "-today";
                    } else {
                        className = "";
                    }

                    day.set("class", className);
                });
            } else {
                // move to beginning of the first week in current month
                iterDate.setUTCDate(iterDate.getUTCDate() - iterDate.getUTCDay() - ampm(1, 0));
                // update days picker
                calenderDays.findAll("td").forEach((day) => {
                    iterDate.setUTCDate(iterDate.getUTCDate() + 1);

                    var mDiff = month - iterDate.getUTCMonth(),
                        className = BASE_CLASS;

                    if (year !== iterDate.getUTCFullYear()) mDiff *= -1;

                    if (iterDate < range[0] || iterDate > range[1]) {
                        className += "-out";
                    } else if (mDiff > 0) {
                        className += "-past";
                    } else if (mDiff < 0) {
                        className += "-future";
                    } else if (date === iterDate.getUTCDate()) {
                        className += "-today";
                    } else {
                        className = "";
                    }

                    day
                        .set("class", className)
                        .data("ts", iterDate.getTime())
                        .value(iterDate.getUTCDate());
                });
            }

            // update calendar caption
            caption
                .set("data-format", expanded ? "yyyy" : "MMMM yyyy")
                .set("datetime", new Date(year, month).toISOString());
        },
        _syncValue(propName, label) {
            var value = this.get(propName);

            this.value(value);
            label.set("datetime", value);
        },
        _clickPicker(picker, calendarMonths, target) {
            var targetDate;

            if (target.matches("a")) {
                targetDate = new Date(this.value());

                if (!targetDate.getTime()) targetDate = new Date();

                var sign = target.next("a")[0] ? -1 : 1;

                if (picker.get("aria-expanded") === "true") {
                    targetDate.setUTCFullYear(targetDate.getUTCFullYear() + sign);
                } else {
                    targetDate.setUTCMonth(targetDate.getUTCMonth() + sign);
                }
            } else if (calendarMonths.contains(target)) {
                target = target.closest("time");

                targetDate = new Date(this.value());
                targetDate.setUTCMonth(new Date(target.get("datetime")).getUTCMonth());

                picker.hide();
            } else if (target.matches("td")) {
                targetDate = target.data("ts");

                if (targetDate) {
                    targetDate = new Date(targetDate);
                    picker.hide();
                }
            }

            if (targetDate != null) {
                var range = readDateRange(this);

                if (targetDate < range[0]) {
                    targetDate = range[0];
                } else if (targetDate > range[1]) {
                    targetDate = range[1];
                }

                this.value(formatISODate(targetDate)).fire("change");
            }
            // prevent input from loosing focus
            return false;
        },
        _keydownPicker(picker, which) {
            var delta, currentDate;
            // ENTER key should submit form if calendar is hidden
            if (picker.matches(":hidden") && which === VK_ENTER) return true;

            if (which === VK_SPACE) {
                // SPACE key toggles calendar visibility
                picker.set("aria-expanded", "false").toggle();
            } else if (which === VK_ESCAPE || which === VK_TAB || which === VK_ENTER) {
                picker.hide(); // ESC, TAB or ENTER keys hide calendar
            } else if (which === VK_BACKSPACE || which === VK_DELETE) {
                this.value("").fire("change"); // BACKSPACE, DELETE clear value
            } else if (which === VK_CONTROL) {
                // CONTROL toggles calendar mode
                picker.set("aria-expanded",
                    String(picker.get("aria-expanded") !== "true"));
            } else {
                currentDate = new Date(this.value());

                if (!currentDate.getTime()) currentDate = new Date();

                if (which === 74 || which === 40) { delta = 7; }
                else if (which === 75 || which === 38) { delta = -7; }
                else if (which === 76 || which === 39) { delta = 1; }
                else if (which === 72 || which === 37) { delta = -1; }

                if (delta) {
                    var expanded = picker.get("aria-expanded") === "true";

                    if (expanded && (which === 40 || which === 38)) {
                        currentDate.setUTCMonth(currentDate.getUTCMonth() + (delta > 0 ? 4 : -4));
                    } else if (expanded && (which === 37 || which === 39)) {
                        currentDate.setUTCMonth(currentDate.getUTCMonth() + (delta > 0 ? 1 : -1));
                    } else {
                        currentDate.setUTCDate(currentDate.getUTCDate() + delta);
                    }

                    var range = readDateRange(this);

                    if (!(currentDate < range[0] || currentDate > range[1])) {
                        this.value(formatISODate(currentDate)).fire("change");
                    }
                }
            }
            // prevent default action except if it was TAB so
            // do not allow to change the value manually
            return which === VK_TAB;
        },
        _blurPicker(picker) {
            picker.hide();
        },
        _focusPicker(picker) {
            if (this.get("readonly")) return false;

            var offset = this.offset();
            var pickerOffset = picker.offset();
            var marginTop = offset.height;

            // #3: move calendar to the top when passing cross browser window bounds
            if (HTML.clientHeight < offset.bottom + pickerOffset.height) {
                marginTop = -pickerOffset.height;
            }

            picker
                // always recalculate picker top position
                .css("margin-top", marginTop)
                // always reset picker mode to default
                .set("aria-expanded", "false")
                // display the date picker
                .show();

            // use the trick below to reset text selection on focus
            /* istanbul ignore next */
            setTimeout(() => {
                var node = this[0];

                if ("selectionStart" in node) {
                    node.selectionStart = 0;
                    node.selectionEnd = 0;
                } else {
                    var inputRange = node.createTextRange();

                    inputRange.moveStart("character", 0);
                    inputRange.collapse();
                    inputRange.moveEnd("character", 0);
                    inputRange.select();
                }
            }, 0);
        },
        _clickPickerCaption(picker) {
            picker.set("aria-expanded",
                String(picker.get("aria-expanded") !== "true"));
        },
        _clickLabel() {
            this.fire("focus");
        }
    });
}(window.DOM, 32, 9, 13, 27, 8, 46, 17));
<commit_msg>space key respects readonly attribute<commit_after>(function(DOM, VK_SPACE, VK_TAB, VK_ENTER, VK_ESCAPE, VK_BACKSPACE, VK_DELETE, VK_CONTROL) {
    "use strict";

    var emmet = DOM.emmetLiteral,
        HTML = DOM.get("documentElement"),
        BASE_CLASS = "btr-dateinput-calendar",
        ampm = (pos, neg) => HTML.lang === "en-US" ? pos : neg,
        formatISODate = (value) => value.toISOString().split("T")[0],
        PICKER_TEMPLATE = DOM.create(emmet `div.${BASE_CLASS}>(p.${BASE_CLASS}-header>a[unselectable=on]*2+time[is=local-time data-format='MMMM yyyy' aria-hidden=true unselectable=on].${BASE_CLASS}-caption)`),
        DAYS_TEMPLATE = DOM.create(emmet `table[aria-hidden=true].${BASE_CLASS}-days>(thead>(tr>(th[unselectable=on]>time[is=local-time datetime='${ampm(2001,2002)}-01-$$@6T21:00:00.000Z' data-format=E])*7)+(tbody.${BASE_CLASS}-body>tr*6>td*7))`),
        MONTHS_TEMPLATE = DOM.create(emmet `table[aria-hidden=true].${BASE_CLASS}-months>tbody>tr*3>td*4>time[is=local-time data-format=MMM])`),
        LABEL_TEMPLATE = DOM.create(emmet `time[is=local-time aria-hidden=true].btr-dateinput-value`),
        readDateRange = (el) => ["min", "max"].map((x) => new Date(el.get(x) || ""));

    MONTHS_TEMPLATE.findAll("time").forEach((time, index) => {
        time.set("datetime", new Date(2001, index, 1, 12).toISOString());
    });

    PICKER_TEMPLATE.append(DAYS_TEMPLATE).append(MONTHS_TEMPLATE);

    DOM.extend("input[type=date]", {
        constructor() {
            if (this._isNative()) return false;

            var defaultValue = this.get("defaultValue"),
                picker = PICKER_TEMPLATE.clone(true),
                label = LABEL_TEMPLATE.clone(true),
                textColor = this.css("color"),
                calenderDays = picker.find(`.${BASE_CLASS}-body`),
                calendarMonths = picker.find(`.${BASE_CLASS}-months`),
                calendarCaption = picker.find(`.${BASE_CLASS}-caption`),
                invalidatePicker = this._invalidatePicker.bind(this, calendarCaption, calendarMonths, calenderDays, picker);

            this// hide original input text
                // IE8 doesn't suport color:transparent - use background-color instead
                .css("color", document.addEventListener ? "transparent" : this.css("background-color"))
                // sync picker visibility on focus/blur
                .on(["focus", "click"], this._focusPicker.bind(this, picker))
                .on("blur", this._blurPicker.bind(this, picker))
                .on("change", this._syncValue.bind(this, "value", label))
                .on("keydown", ["which"], this._keydownPicker.bind(this, picker))
                .value(defaultValue); // restore initial value

            label
                .set("data-format", this.get("data-format") || "E, dd MMM yyyy")
                .css(this.css(["width", "font", "padding", "text-align", "border-width", "box-sizing"]))
                .css({color: textColor, "line-height": ""}) // IE10 returns invalid line-height for hidden elements
                .on("click", this._clickLabel.bind(this))
                .watch("datetime", invalidatePicker)
                .set("datetime", defaultValue);

            this
                .before(picker.hide(), label)
                .closest("form").on("reset", this._syncValue.bind(this, "defaultValue", label));

            picker
                .watch("aria-expanded", invalidatePicker)
                .on("mousedown", ["target"], this._clickPicker.bind(this, picker, calendarMonths))
                .css("z-index", 1 + (this.css("z-index") | 0));

            calendarCaption
                .on("click", this._clickPickerCaption.bind(this, picker));

            // display calendar for autofocused elements
            if (this.matches(":focus")) picker.show();
        },
        _isNative() {
            var polyfillType = this.get("data-polyfill"),
                deviceType = "orientation" in window ? "mobile" : "desktop";

            if (polyfillType === "none") return true;

            if (!polyfillType || polyfillType === deviceType && polyfillType !== "all") {
                // use a stronger type support detection that handles old WebKit browsers:
                // http://www.quirksmode.org/blog/archives/2015/03/better_modern_i.html
                if (this[0].type === "date") return true;
                // persist current value to restore it later
                this.set("defaultValue", this.value());
                // if browser allows invalid value then it doesn't support the feature
                return this.value("_").value() !== "_";
            } else {
                // remove native control
                this.set("type", "text");
                // force applying the polyfill
                return false;
            }
        },
        _invalidatePicker(caption, calendarMonths, calenderDays, picker) {
            var expanded = picker.get("aria-expanded") === "true";
            var value = new Date(this.value());
            var year, month, date;

            if (!value.getTime()) {
                value = new Date();
            }

            month = value.getUTCMonth();
            date = value.getUTCDate();
            year = value.getUTCFullYear();

            var range = readDateRange(this);
            var iterDate = new Date(Date.UTC(year, month, 0));

            if (expanded) {
                calendarMonths.findAll("td").forEach((day, index) => {
                    iterDate.setUTCMonth(index);

                    var mDiff = month - iterDate.getUTCMonth(),
                        className = BASE_CLASS;

                    if (iterDate < range[0] || iterDate > range[1]) {
                        className += "-out";
                    } else if (!mDiff) {
                        className += "-today";
                    } else {
                        className = "";
                    }

                    day.set("class", className);
                });
            } else {
                // move to beginning of the first week in current month
                iterDate.setUTCDate(iterDate.getUTCDate() - iterDate.getUTCDay() - ampm(1, 0));
                // update days picker
                calenderDays.findAll("td").forEach((day) => {
                    iterDate.setUTCDate(iterDate.getUTCDate() + 1);

                    var mDiff = month - iterDate.getUTCMonth(),
                        className = BASE_CLASS;

                    if (year !== iterDate.getUTCFullYear()) mDiff *= -1;

                    if (iterDate < range[0] || iterDate > range[1]) {
                        className += "-out";
                    } else if (mDiff > 0) {
                        className += "-past";
                    } else if (mDiff < 0) {
                        className += "-future";
                    } else if (date === iterDate.getUTCDate()) {
                        className += "-today";
                    } else {
                        className = "";
                    }

                    day
                        .set("class", className)
                        .data("ts", iterDate.getTime())
                        .value(iterDate.getUTCDate());
                });
            }

            // update calendar caption
            caption
                .set("data-format", expanded ? "yyyy" : "MMMM yyyy")
                .set("datetime", new Date(year, month).toISOString());
        },
        _syncValue(propName, label) {
            var value = this.get(propName);

            this.value(value);
            label.set("datetime", value);
        },
        _clickPicker(picker, calendarMonths, target) {
            var targetDate;

            if (target.matches("a")) {
                targetDate = new Date(this.value());

                if (!targetDate.getTime()) targetDate = new Date();

                var sign = target.next("a")[0] ? -1 : 1;

                if (picker.get("aria-expanded") === "true") {
                    targetDate.setUTCFullYear(targetDate.getUTCFullYear() + sign);
                } else {
                    targetDate.setUTCMonth(targetDate.getUTCMonth() + sign);
                }
            } else if (calendarMonths.contains(target)) {
                target = target.closest("time");

                targetDate = new Date(this.value());
                targetDate.setUTCMonth(new Date(target.get("datetime")).getUTCMonth());

                picker.hide();
            } else if (target.matches("td")) {
                targetDate = target.data("ts");

                if (targetDate) {
                    targetDate = new Date(targetDate);
                    picker.hide();
                }
            }

            if (targetDate != null) {
                var range = readDateRange(this);

                if (targetDate < range[0]) {
                    targetDate = range[0];
                } else if (targetDate > range[1]) {
                    targetDate = range[1];
                }

                this.value(formatISODate(targetDate)).fire("change");
            }
            // prevent input from loosing focus
            return false;
        },
        _keydownPicker(picker, which) {
            var delta, currentDate;
            // ENTER key should submit form if calendar is hidden
            if (picker.matches(":hidden") && which === VK_ENTER) return true;

            if (which === VK_SPACE) {
                // SPACE key toggles calendar visibility
                if (!this.get("readonly")) {
                    picker.set("aria-expanded", "false").toggle();
                }
            } else if (which === VK_ESCAPE || which === VK_TAB || which === VK_ENTER) {
                picker.hide(); // ESC, TAB or ENTER keys hide calendar
            } else if (which === VK_BACKSPACE || which === VK_DELETE) {
                this.value("").fire("change"); // BACKSPACE, DELETE clear value
            } else if (which === VK_CONTROL) {
                // CONTROL toggles calendar mode
                picker.set("aria-expanded",
                    String(picker.get("aria-expanded") !== "true"));
            } else {
                currentDate = new Date(this.value());

                if (!currentDate.getTime()) currentDate = new Date();

                if (which === 74 || which === 40) { delta = 7; }
                else if (which === 75 || which === 38) { delta = -7; }
                else if (which === 76 || which === 39) { delta = 1; }
                else if (which === 72 || which === 37) { delta = -1; }

                if (delta) {
                    var expanded = picker.get("aria-expanded") === "true";

                    if (expanded && (which === 40 || which === 38)) {
                        currentDate.setUTCMonth(currentDate.getUTCMonth() + (delta > 0 ? 4 : -4));
                    } else if (expanded && (which === 37 || which === 39)) {
                        currentDate.setUTCMonth(currentDate.getUTCMonth() + (delta > 0 ? 1 : -1));
                    } else {
                        currentDate.setUTCDate(currentDate.getUTCDate() + delta);
                    }

                    var range = readDateRange(this);

                    if (!(currentDate < range[0] || currentDate > range[1])) {
                        this.value(formatISODate(currentDate)).fire("change");
                    }
                }
            }
            // prevent default action except if it was TAB so
            // do not allow to change the value manually
            return which === VK_TAB;
        },
        _blurPicker(picker) {
            picker.hide();
        },
        _focusPicker(picker) {
            if (this.get("readonly")) return false;

            var offset = this.offset();
            var pickerOffset = picker.offset();
            var marginTop = offset.height;

            // #3: move calendar to the top when passing cross browser window bounds
            if (HTML.clientHeight < offset.bottom + pickerOffset.height) {
                marginTop = -pickerOffset.height;
            }

            picker
                // always recalculate picker top position
                .css("margin-top", marginTop)
                // always reset picker mode to default
                .set("aria-expanded", "false")
                // display the date picker
                .show();

            // use the trick below to reset text selection on focus
            /* istanbul ignore next */
            setTimeout(() => {
                var node = this[0];

                if ("selectionStart" in node) {
                    node.selectionStart = 0;
                    node.selectionEnd = 0;
                } else {
                    var inputRange = node.createTextRange();

                    inputRange.moveStart("character", 0);
                    inputRange.collapse();
                    inputRange.moveEnd("character", 0);
                    inputRange.select();
                }
            }, 0);
        },
        _clickPickerCaption(picker) {
            picker.set("aria-expanded",
                String(picker.get("aria-expanded") !== "true"));
        },
        _clickLabel() {
            this.fire("focus");
        }
    });
}(window.DOM, 32, 9, 13, 27, 8, 46, 17));
<|endoftext|>


<commit_before>import './main.scss';
import R from 'ramda';
import lexer from 'pug-lexer';
import parser from 'pug-parser';
import tpl from './tpl.pug';
import immutable from 'object-path-immutable';

import idom from 'incremental-dom';
const fixIdom = fn => (tagname, key, staticProp, rest) =>
	fn.apply(undefined, [tagname, key, staticProp].concat(rest));
const elementOpen = fixIdom(idom.elementOpen);
const elementClose = idom.elementClose;
const elementVoid = fixIdom(idom.elementVoid);
const text = (str, formatters = []) => idom.text.apply(undefined, [str].concat(formatters));

/**
 * elementOpen(tagname, tracking key, static propValArr, propValArr)
 * elementVoid(tagname, tracking key, static propValArr, propValArr)
 * elementClose(tagname)
 * text(text)
 */

const PugNodeType = {
	Block: 'Block',
	Tag: 'Tag',
	Text: 'Text',
	Code: 'Code',
};

// @todo: eval the argval?!? gross.
const parseAttrs = (attrs, props) => {
	const staticAttrs = [];
	const dynamicAttrs = [];

	const {
		classes,
		events,
		rest,
	} = R.reduce(
		(acc, x) => {
			const token = x.name.toLowerCase();
			if (token.startsWith('on')) {
				acc.events.push(x);
			} else if (token === 'class') {
				acc.classes.push(x);
			} else {
				acc.rest.push(x);
			}

			return acc;
		},
		{ events: [], classes: [], rest: [] },
		attrs
	);

	if (classes.length) {
		staticAttrs.push('class', classes.map(x => x.val.slice(1, -1)).join(' '));
	}

	if (events.length) {
		events.forEach(
			x => dynamicAttrs.push(x.name, R.path(x.val.split('.'), props))
		);
	}

	if (rest.length) {
		rest.forEach(
			x => staticAttrs.push(x.name, x.val)
		);
	}

	return {
		dynamicAttrs,
		staticAttrs,
	};
};

const isVoidElt = (node) =>
	node.selfClosing ||
	(
		node.type === PugNodeType.Tag &&
		[
			'input',
		].includes(node.name.toLowerCase())
	);

// @todo: we can push these calls into a list
// @todo: and we can develop smart inc-dom...
const render = ({ ast, props }) =>
	// @todo: this can be so optimized.
	// @todo: static parts of the tree can stay fine
	// @todo: determine where my code goes to generate a sexy idom loop
	(function recurse(node, parent) {
		switch (node.type) {
			case PugNodeType.Block:
				node.nodes.forEach(x => recurse(x, node));
				break;

			case PugNodeType.Tag: {

				const { staticAttrs, dynamicAttrs } = parseAttrs(node.attrs, props);
				const args = [node.name, undefined, staticAttrs, dynamicAttrs];

				if (isVoidElt(node)) {
					elementVoid.apply(undefined, args);
					break;
				}

				elementOpen.apply(undefined, args);
				if (node.block) {
					node.block.nodes.forEach(x => recurse(x, node));
				}
				elementClose(node.name);
			}
				break;

			case PugNodeType.Text:
				text(node.val);
				break;

			case PugNodeType.Code:
				// @todo: this is one of the only times we depend on props...
				// @todo: only paths for now?
				if (parent.type === PugNodeType.Tag) {
					// Interpret as interpolated text
					const path = node.val.split('.');
					text(R.path(path, props));
				}
				break;

			default:
				console.debug('Walking: ', node, 'from', parent);
				console.error('unhandled.');
		}
	}(ast, undefined));

const root = document.createElement('root');

document.body.appendChild(root);

let name = 'Frank';
const state = {
	name,
	time: Date.now(),
	input: (evt) => {
		name = evt.target.value;
	},
};

const tokens = lexer(tpl);
const component = parser(tokens);
setInterval(() => {
	const newState = immutable(state)
		.set('name', name)
		.set('time', Date.now())
		.value();

	idom.patch(root, render, {
		ast: component,
		props: newState,
	});
});
<commit_msg>Switched to a compiled fn list to run recursive build.<commit_after>import './main.scss';
import R from 'ramda';
import lexer from 'pug-lexer';
import parser from 'pug-parser';
import tpl from './tpl.pug';
import immutable from 'object-path-immutable';

import idom from 'incremental-dom';
const fixIdom = fn => (tagname, key, staticProp, rest) =>
	fn.apply(undefined, [tagname, key, staticProp].concat(rest));
const elementOpen = fixIdom(idom.elementOpen);
const elementClose = idom.elementClose;
const elementVoid = fixIdom(idom.elementVoid);
const text = (str, formatters = []) => idom.text.apply(undefined, [str].concat(formatters));

/**
 * elementOpen(tagname, tracking key, static propValArr, propValArr)
 * elementVoid(tagname, tracking key, static propValArr, propValArr)
 * elementClose(tagname)
 * text(text)
 */

const PugNodeType = {
	Block: 'Block',
	Tag: 'Tag',
	Text: 'Text',
	Code: 'Code',
};

// @todo: eval the argval?!? gross.
const parseAttrs = (attrs, props) => {
	const staticAttrs = [];
	const dynamicAttrs = [];

	const {
		classes,
		events,
		rest
	} = R.reduce(
		(acc, x) => {
			const token = x.name.toLowerCase();
			if (token.startsWith('on')) {
				acc.events.push(x);
			} else if (token === 'class') {
				acc.classes.push(x);
			} else {
				acc.rest.push(x);
			}

			return acc;
		},
		{ events: [], classes: [], rest: [] },
		attrs
	);

	if (classes.length) {
		staticAttrs.push('class', classes.map(x => x.val.slice(1, -1)).join(' '));
	}

	if (events.length) {
		events.forEach(
			x => dynamicAttrs.push(x.name, R.path(x.val.split('.'), props))
		);
	}

	if (rest.length) {
		rest.forEach(
			x => staticAttrs.push(x.name, x.val)
		);
	}

	return {
		dynamicAttrs,
		staticAttrs
	};
}

const isVoidElt = (node) =>
	node.selfClosing ||
	(
		node.type === PugNodeType.Tag &&
		[
			'input'
		].includes(node.name.toLowerCase())
	);

// @todo: we can push these calls into a list
// @todo: and we can develop smart inc-dom...
const compile = (ast) => {
	const commands = [];
	// @todo: pivitol parts of state model changing / extraction

	// @todo: this can be so optimized.
	// @todo: static parts of the tree can stay fine
	// @todo: determine where my code goes to generate a sexy idom loop
	(function recurse(node, parent){
		switch (node.type) {
			case PugNodeType.Block:
				node.nodes.forEach(x => recurse(x, node));
				break;

			case PugNodeType.Tag: {
				commands.push((props) => {
					const { staticAttrs, dynamicAttrs } = parseAttrs(node.attrs, props);
					const args = [node.name, undefined, staticAttrs, dynamicAttrs];
					if (isVoidElt(node)) {
						elementVoid.apply(undefined, args);
					} else {
						elementOpen.apply(undefined, args);
					}
				});

				if (node.block) {
					node.block.nodes.forEach(x => recurse(x, node));
				}

				if (!isVoidElt(node)) {
					commands.push(() => elementClose(node.name));
				}
			}
			break;

			case PugNodeType.Text:
				commands.push(() => text(node.val));
				break;

			case PugNodeType.Code:
				// @todo: this is one of the only times we depend on props...
				// @todo: only paths for now?
				if (parent.type === PugNodeType.Tag) {
					// Interpret as interpolated text
					const path = node.val.split('.');
					commands.push((props) => text(R.path(path, props)));
				}
				break;

			default:
				console.debug('Walking: ', node, 'from', parent);
				console.error('unhandled.');
		}
	}(ast, undefined));

	// The compiled fn list, injecting props
	return (props) => commands.forEach(cmd => cmd(props));
}

const root = document.createElement('root');

document.body.appendChild(root);

let name = 'Frank';
const state = {
	name,
	time: Date.now(),
	input: (evt) => {
		name = evt.target.value;
	}
}

const tokens = lexer(tpl);
const component = parser(tokens);
const renderer = compile(component);

setInterval(() => {
	const newState = immutable(state)
		.set('name', name)
		.set('time', Date.now())
		.value();

	idom.patch(root, renderer, newState);
});
<|endoftext|>


<commit_before>/**
 * mini-event
 * Copyright 2013 Baidu Inc. All rights reserved.
 *
 * @file 入口
 * @author otakustay
 */

define(
    function (require) {
        return {
            Event: require('./Event')
        };
    }
);
<commit_msg>主模块提供更多方法<commit_after>/**
 * mini-event
 * Copyright 2013 Baidu Inc. All rights reserved.
 *
 * @file 入口
 * @author otakustay
 */

define(
    function (require) {
        var Event = require('./Event');

        return {
            Event: Event,
            fromDOMEvent: Event.fromDOMEvent,
            fromEvent: Event.fromEvent,
            delegate: Event.delegate
        };
    }
);
<|endoftext|>


<commit_before>$('table.statistics-confusion').each(function(){
	var tableNode=$(this);
	var tbodyNode=tableNode.children('tbody');
	var rcDir=0; // outcome headers on top?
	var rcOrd=[0,0]; // outcomes swapped?, conditions swapped?
	var isExpanded=false;
	//function wikipedia(block,url) {
	//	if (url===undefined) url="https://en.wikipedia.org/wiki/"+block.replace(/ /g,'_');
	function wikipedia(block) {
		url="https://en.wikipedia.org/wiki/"+block.replace(/ /g,'_');
		return ""+block+"";
	}
	var expandData=[
		[ // new row
			parseFormula("(FN+TN)/(TP+FP+FN+TN)"),
			"
"+wikipedia("False negative rate")+"
"+parseFormula("FNR=FN/(TP+FN)"),
			"
"+wikipedia("False positive rate")+"
"+parseFormula("FPR=FP/(FP+TN)"),
			"
Overall error rate
"+parseFormula("(FP+FN)/(TP+FP+FN+TN)"),
			"" // not used
		],[ // new col
			parseFormula("(FP+TN)/(TP+FP+FN+TN)"),
			"
"+wikipedia("False discovery rate")+"
"+parseFormula("FDR=FP/(TP+FP)"),
			"
"+wikipedia("False omission rate")+"
"+parseFormula("FOR=FN/(FN+TN)"),
			"
"+wikipedia("Positive likelihood ratio")+"
"+parseFormula("PLR=TPR/FPR"),
			"
"+wikipedia("Negative likelihood ratio")+"
"+parseFormula("NLR=FNR/TNR")
		]
	];
	function haveToSwap(dir,i) {
		if (i==1 || i==2) {
			return ((i-1)^rcOrd[0]^rcOrd[1])&1;
		} else {
			rcOrd[rcDir^dir]&1;
		}
	}
	function expandTable() {
		function addCell(callOrd,dir,i,insertNormal,insertSwapped) {
			function makeCell() {
				var j=i;
				if ((j==1 || j==2) && rcOrd[rcDir^dir^1]) {
					j^=1^2;
				} else if (callOrd && (j==3 || j==4) && rcOrd[rcDir^dir^1]) {
					j^=3^4;
				}
				var cellHtml=expandData[rcDir^dir][j];
				return $("").html(cellHtml);
			}
			var cell=makeCell();
			if (haveToSwap(dir,i)) {
				insertSwapped(cell);
			} else {
				insertNormal(cell);
			}
		}
		function addCol(callOrd) {
			tbodyNode.children().each(function(i){
				var oldRow=$(this);
				addCell(callOrd,1,i,function(newCell){
					oldRow.append(newCell);
				},function(newCell){
					oldRow.children().eq(-1).before(newCell);
				});
			});
		}
		function addRow(callOrd) {
			var newRow=$("
");
			tbodyNode.append(newRow);
			tbodyNode.children().eq(-2).children().each(function(i){
				var oldCell=$(this);
				addCell(callOrd,0,i,function(newCell){
					newRow.append(newCell);
				},function(newCell){
					oldCell.before(newCell);
					newRow.append(oldCell);
				});
			});
		}
		if (rcDir) {
			addCol(0);
			addRow(1);
		} else {
			addRow(0);
			addCol(1);
		}
		isExpanded=true;
		tableNode.find('button.add-r, button.add-c').text('−').attr('title','contract table').off().click(contractTable);
	}
	function contractTable() {
		function removeCol() {
			tbodyNode.children().each(function(i){
				var oldRow=$(this);
				oldRow.children().eq(haveToSwap(1,i)?-2:-1).remove();
			});
		}
		function removeRow() {
			var oldRow=tbodyNode.children().eq(-2);
			var newRow=tbodyNode.children().eq(-1);
			newRow.children().each(function(i){
				if (haveToSwap(0,i)) {
					var oldCell=$(this);
					var newCell=oldRow.children().eq(i);
					newCell.after(oldCell).remove();
				}
			});
			newRow.remove();
		}
		if (rcDir) {
			removeRow();
			removeCol();
		} else {
			removeCol();
			removeRow();
		}
		isExpanded=false;
		tableNode.find('button.add-r, button.add-c').text('+').attr('title','expand table').off().click(expandTable);
	}
	function swapChildren(node,i) {
		var c1=node.children().eq(i);
		var c2=node.children().eq(i+1);
		c1.before(c2);
	}
	tableNode.children('caption').append(
		$("<button type='button' class='swap-rc' title='swap rows and columns'>↻</button>").click(function(){
			rcDir^=1;
			var n=tbodyNode.children().length;
			for (var i=0;i<n;i++) {
				for (var j=0;j<i;j++) {
					var c1=tbodyNode.children().eq(i).children().eq(j);
					var c2=tbodyNode.children().eq(j).children().eq(i);
					var c2p=c2.prev();
					c1.after(c2);
					c2p.after(c1);
				}
			}
		})
	).append(
		$("<button type='button' class='swap-c' title='swap columns'>↔</button>").click(function(){
			rcOrd[rcDir^1]^=1;
			tbodyNode.children().each(function(){
				swapChildren($(this),1);
				if (!isExpanded) return;
				swapChildren($(this),3);
			});
		})
	).append(
		$("<button type='button' class='swap-r' title='swap rows'>↕</button>").click(function(){
			rcOrd[rcDir]^=1;
			swapChildren(tbodyNode,1);
			if (!isExpanded) return;
			swapChildren(tbodyNode,3);
		})
	).append(
		$("<button type='button' class='add-c' title='expand table'>+</button>").click(expandTable)
	).append(
		$("<button type='button' class='add-r' title='expand table'>+</button>").click(expandTable)
	);
	tableNode.on('mouseenter','.term',function(){
		tableNode.find("[class='"+this.className+"']").addClass('highlight');
	}).on('mouseleave','.term',function(){
		tableNode.find("[class='"+this.className+"']").removeClass('highlight');
	});

	// svg test
	tableNode.find('button.swap-c').html(
		"<svg width='100%' height='100%' viewBox='-2 -2 4 4'>"+
			"<path d='M -1 1 V 0 A 1 1 0 0 1 1 0 V 1' style='fill:none; stroke:#000; stroke-width: 0.3' />"+
		"</svg>"
	);
});
<commit_msg>tweaking arrow shape<commit_after>$('table.statistics-confusion').each(function(){
	var tableNode=$(this);
	var tbodyNode=tableNode.children('tbody');
	var rcDir=0; // outcome headers on top?
	var rcOrd=[0,0]; // outcomes swapped?, conditions swapped?
	var isExpanded=false;
	//function wikipedia(block,url) {
	//	if (url===undefined) url="https://en.wikipedia.org/wiki/"+block.replace(/ /g,'_');
	function wikipedia(block) {
		url="https://en.wikipedia.org/wiki/"+block.replace(/ /g,'_');
		return ""+block+"";
	}
	var expandData=[
		[ // new row
			parseFormula("(FN+TN)/(TP+FP+FN+TN)"),
			"
"+wikipedia("False negative rate")+"
"+parseFormula("FNR=FN/(TP+FN)"),
			"
"+wikipedia("False positive rate")+"
"+parseFormula("FPR=FP/(FP+TN)"),
			"
Overall error rate
"+parseFormula("(FP+FN)/(TP+FP+FN+TN)"),
			"" // not used
		],[ // new col
			parseFormula("(FP+TN)/(TP+FP+FN+TN)"),
			"
"+wikipedia("False discovery rate")+"
"+parseFormula("FDR=FP/(TP+FP)"),
			"
"+wikipedia("False omission rate")+"
"+parseFormula("FOR=FN/(FN+TN)"),
			"
"+wikipedia("Positive likelihood ratio")+"
"+parseFormula("PLR=TPR/FPR"),
			"
"+wikipedia("Negative likelihood ratio")+"
"+parseFormula("NLR=FNR/TNR")
		]
	];
	function haveToSwap(dir,i) {
		if (i==1 || i==2) {
			return ((i-1)^rcOrd[0]^rcOrd[1])&1;
		} else {
			rcOrd[rcDir^dir]&1;
		}
	}
	function expandTable() {
		function addCell(callOrd,dir,i,insertNormal,insertSwapped) {
			function makeCell() {
				var j=i;
				if ((j==1 || j==2) && rcOrd[rcDir^dir^1]) {
					j^=1^2;
				} else if (callOrd && (j==3 || j==4) && rcOrd[rcDir^dir^1]) {
					j^=3^4;
				}
				var cellHtml=expandData[rcDir^dir][j];
				return $("").html(cellHtml);
			}
			var cell=makeCell();
			if (haveToSwap(dir,i)) {
				insertSwapped(cell);
			} else {
				insertNormal(cell);
			}
		}
		function addCol(callOrd) {
			tbodyNode.children().each(function(i){
				var oldRow=$(this);
				addCell(callOrd,1,i,function(newCell){
					oldRow.append(newCell);
				},function(newCell){
					oldRow.children().eq(-1).before(newCell);
				});
			});
		}
		function addRow(callOrd) {
			var newRow=$("
");
			tbodyNode.append(newRow);
			tbodyNode.children().eq(-2).children().each(function(i){
				var oldCell=$(this);
				addCell(callOrd,0,i,function(newCell){
					newRow.append(newCell);
				},function(newCell){
					oldCell.before(newCell);
					newRow.append(oldCell);
				});
			});
		}
		if (rcDir) {
			addCol(0);
			addRow(1);
		} else {
			addRow(0);
			addCol(1);
		}
		isExpanded=true;
		tableNode.find('button.add-r, button.add-c').text('−').attr('title','contract table').off().click(contractTable);
	}
	function contractTable() {
		function removeCol() {
			tbodyNode.children().each(function(i){
				var oldRow=$(this);
				oldRow.children().eq(haveToSwap(1,i)?-2:-1).remove();
			});
		}
		function removeRow() {
			var oldRow=tbodyNode.children().eq(-2);
			var newRow=tbodyNode.children().eq(-1);
			newRow.children().each(function(i){
				if (haveToSwap(0,i)) {
					var oldCell=$(this);
					var newCell=oldRow.children().eq(i);
					newCell.after(oldCell).remove();
				}
			});
			newRow.remove();
		}
		if (rcDir) {
			removeRow();
			removeCol();
		} else {
			removeCol();
			removeRow();
		}
		isExpanded=false;
		tableNode.find('button.add-r, button.add-c').text('+').attr('title','expand table').off().click(expandTable);
	}
	function swapChildren(node,i) {
		var c1=node.children().eq(i);
		var c2=node.children().eq(i+1);
		c1.before(c2);
	}
	tableNode.children('caption').append(
		$("<button type='button' class='swap-rc' title='swap rows and columns'>↻</button>").click(function(){
			rcDir^=1;
			var n=tbodyNode.children().length;
			for (var i=0;i<n;i++) {
				for (var j=0;j<i;j++) {
					var c1=tbodyNode.children().eq(i).children().eq(j);
					var c2=tbodyNode.children().eq(j).children().eq(i);
					var c2p=c2.prev();
					c1.after(c2);
					c2p.after(c1);
				}
			}
		})
	).append(
		$("<button type='button' class='swap-c' title='swap columns'>↔</button>").click(function(){
			rcOrd[rcDir^1]^=1;
			tbodyNode.children().each(function(){
				swapChildren($(this),1);
				if (!isExpanded) return;
				swapChildren($(this),3);
			});
		})
	).append(
		$("<button type='button' class='swap-r' title='swap rows'>↕</button>").click(function(){
			rcOrd[rcDir]^=1;
			swapChildren(tbodyNode,1);
			if (!isExpanded) return;
			swapChildren(tbodyNode,3);
		})
	).append(
		$("<button type='button' class='add-c' title='expand table'>+</button>").click(expandTable)
	).append(
		$("<button type='button' class='add-r' title='expand table'>+</button>").click(expandTable)
	);
	tableNode.on('mouseenter','.term',function(){
		tableNode.find("[class='"+this.className+"']").addClass('highlight');
	}).on('mouseleave','.term',function(){
		tableNode.find("[class='"+this.className+"']").removeClass('highlight');
	});

	// svg test
	tableNode.find('button.swap-c').html(
		"<svg width='100%' height='100%' viewBox='-2 -2 4 4'>"+
			"<path d='M -1.4 0.25 L -1 1 V 0 A 1 1 0 0 1 1 0 V 1 L 1.4 0.25' style='fill:none; stroke:#000; stroke-width:0.25; stroke-miterlimit:10' />"+
		"</svg>"
	);
});
<|endoftext|>


<commit_before>
(function (root) {
  'use strict';

  var iframeHtml = '::iframeHtml::',
      iframeStyle = {
        position: 'fixed',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%'
      },
      api = {
        host: 'https://api.aplazame.com/',
        accept: 'application/vnd.aplazame{sandbox}-v{version}+json'
      };

  function Env () {}
    Env.prototype = {
      version: 1,
      sandbox: false
    };
  var env = new Env();

  // utility functions

  function replaceKeys (tmpl, keys) {
    return keys ? tmpl.replace(/\{([^\}]+)\}/g, function (match, key) {
      return keys[key];
    }) : function (ks) {
      return replaceKeys(tmpl, ks);
    };
  }

  var arrayShift = [].shift;
  function extend () {
      var dest = arrayShift.call(arguments),
        src = arrayShift.call(arguments),
        key;

    while( src ) {
      for( key in src) {
        dest[key] = src[key];
      }
      src = arrayShift.call(arguments);
    }

    return dest;
  }

  function headerToTitleSlug(text) {
    var key = text[0].toUpperCase() + text.substr(1);
    return key.replace(/([a-z])([A-Z])/, function (match, lower, upper) {
        return lower + '-' + upper;
    });
  }

  function headerToCamelCase(text) {
    var key = text[0].toLowerCase() + text.substr(1);
    return key.replace(/([a-z])-([A-Z])/, function (match, lower, upper) {
      return lower + upper;
    });
  }

  var RE_contentType = /([^\/]+)\/([^+]+\+)?(.*)/;
  function parseContentType(contentType, text, xml) {
    var matches = contentType.match(RE_contentType);
    return ( matches[3] === 'json' ) ? JSON.parse(data) : ( matches[3] === 'xml' ? xml : text );
  }

  function http (url, options) {
    options = options || {};
    options.headers = options.headers || {};
    options.url = url;

    var request = null,
        on = { resolve: [], reject: [] };

    try { // Firefox, Opera 8.0+, Safari
        request = new XMLHttpRequest();
    } catch (e) { // Internet Explorer
        try { request = new ActiveXObject("Msxml2.XMLHTTP"); }
        catch (er) { request = new ActiveXObject("Microsoft.XMLHTTP"); }
    }
    if( request === null ) { throw "Browser does not support HTTP Request"; }

    request.open( ( options.method || 'get').toUpperCase(), url );

    for( var key in options.headers ) {
        request.setRequestHeader( headerToTitleSlug(key), options.headers[key] );
    }

    request.resolve = function ( response ) {
      on.resolve.forEach(function (handler) {
        handler(response);
      });
    };
    request.reject = function ( response ) {
      on.reject.forEach(function (handler) {
        handler(response);
      });
    };

    var headersCache;
    request.getHeaders = function () {
      if( !headersCache ) {
        headersCache = request.getAllResponseHeaders().replace(/\s*([^\:]+)\s*\:\s*([^\;\n]+)/g, function (match, key, value) {
            request.headers[headerToCamelCase(key)] = value.trim();
        });
      }
      return headersCache;
    };

    request.onreadystatechange = function(){
      if( request.readyState === 'complete' || request.readyState === 4 ) {
        var response = {
          data: parseContentType(contentType, text, xml),
          status: request.status,
          headers: request.getHeaders,
          xhr: request
        };
        if( request.status >= 200 && request.status < 300 ) {
          request.resolve( response );
        } else if( request.status >= 400 ) {
          request.reject( response );
        } else {
          throw new Error('Unexpected status code ' + request.status);
        }
      }
    };

    request.options = options;

    request.send( options.data );

    return {
      then: function (onResolve, onReject) {
        on.resolve.push(onResolve);
        if( onReject instanceof Function ) {
          on.reject.push(onreject);
        }
      },
      error: function (onReject) {
        on.reject.push(onReject);
      }
    };
  }

  function apiOptions (options) {
    options = options || {};
    options.version = options.version || env.version;
    options.sandbox = ( options.sandbox === undefined ? env.sandbox : options.sandbox ) ? '.sandbox' : '';
    options.paramsStr = '';
    if( options.params ) {
      for( var key in options.params ) {
        options.paramsStr += ( options.paramsStr ? '&' : '?' ) + key + '=' + encodeURIComponent(options.params[key]);
      }
    }
    return options;
  }

  // aplazame methods

  function init (options) {
    if( !options ) {
      throw new Error('aplazame.init({options}) requires options');
    }
    if( !options.publicKey ) {
      throw new Error('aplazame.init({options}) requires at least the publicKey');
    }
    extend(env, options);
  }

  function getEnv () {
    return env;
  }

  function apiGet (options) {
    options = apiOptions(options);
    return http(api.host + options.paramsStr, {
      headers: {
        accept: replaceKeys(api.accept, options)
      }
    });
  }

  function apiPost (options) {
    options = apiOptions(options);
    return http(api.host + options.paramsStr, {
      method: 'post',
      headers: {
        accept: replaceKeys(api.accept, options)
      }
    });
  }

  function button (options) {
    // options:
    // ------------------
    // id: "CONTAINER_ID",
    // token: "<ACCESS_TOKEN>",
    // amount: 12050,
    // currency: "EUR",
    // sandbox: true
  }

  function checkout () {
    var iframe = document.createElement('iframe');
    iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(iframeHtml);
    extend(iframe.style, iframeStyle);
    iframe.frameBorder = '0';
    document.body.appendChild(iframe);
  }

  // globalizing aplazame object

  if( document.querySelector('script[data-aplazame]') ) {
    var initText = document.querySelector('script[data-aplazame]').getAttribute('data-aplazame');
    if( /\s/.test(initText) ) {
      var envOptions = {};
      initText.split(',').forEach(function (part) {
        var keys = part.match(/^([^\:]+)\:(.*)/);
        envOptions[keys[1].trim()] = keys[2].trim();
      });
      init(envOptions);
    } else {
      init({ publicKey: initText });
    }
  }

  root.aplazame = {
    init: init,
    getEnv: getEnv,
    checkout: checkout,
    button: button,
    apiGet: apiGet,
    apiPost: apiPost
  };

})(this);
<commit_msg>accepting data-version and data-sandbox<commit_after>
(function (root) {
  'use strict';

  var iframeHtml = '::iframeHtml::',
      iframeStyle = {
        position: 'fixed',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%'
      },
      api = {
        host: 'https://api.aplazame.com/',
        accept: 'application/vnd.aplazame{sandbox}-v{version}+json'
      };

  function Env () {}
    Env.prototype = {
      version: 1,
      sandbox: false
    };
  var env = new Env();

  // utility functions

  function replaceKeys (tmpl, keys) {
    return keys ? tmpl.replace(/\{([^\}]+)\}/g, function (match, key) {
      return keys[key];
    }) : function (ks) {
      return replaceKeys(tmpl, ks);
    };
  }

  var arrayShift = [].shift;
  function extend () {
      var dest = arrayShift.call(arguments),
        src = arrayShift.call(arguments),
        key;

    while( src ) {
      for( key in src) {
        dest[key] = src[key];
      }
      src = arrayShift.call(arguments);
    }

    return dest;
  }

  function headerToTitleSlug(text) {
    var key = text[0].toUpperCase() + text.substr(1);
    return key.replace(/([a-z])([A-Z])/, function (match, lower, upper) {
        return lower + '-' + upper;
    });
  }

  function headerToCamelCase(text) {
    var key = text[0].toLowerCase() + text.substr(1);
    return key.replace(/([a-z])-([A-Z])/, function (match, lower, upper) {
      return lower + upper;
    });
  }

  var RE_contentType = /([^\/]+)\/([^+]+\+)?(.*)/;
  function parseContentType(contentType, text, xml) {
    var matches = contentType.match(RE_contentType);
    return ( matches[3] === 'json' ) ? JSON.parse(data) : ( matches[3] === 'xml' ? xml : text );
  }

  function http (url, options) {
    options = options || {};
    options.headers = options.headers || {};
    options.url = url;

    var request = null,
        on = { resolve: [], reject: [] };

    try { // Firefox, Opera 8.0+, Safari
        request = new XMLHttpRequest();
    } catch (e) { // Internet Explorer
        try { request = new ActiveXObject("Msxml2.XMLHTTP"); }
        catch (er) { request = new ActiveXObject("Microsoft.XMLHTTP"); }
    }
    if( request === null ) { throw "Browser does not support HTTP Request"; }

    request.open( ( options.method || 'get').toUpperCase(), url );

    for( var key in options.headers ) {
        request.setRequestHeader( headerToTitleSlug(key), options.headers[key] );
    }

    request.resolve = function ( response ) {
      on.resolve.forEach(function (handler) {
        handler(response);
      });
    };
    request.reject = function ( response ) {
      on.reject.forEach(function (handler) {
        handler(response);
      });
    };

    var headersCache;
    request.getHeaders = function () {
      if( !headersCache ) {
        headersCache = request.getAllResponseHeaders().replace(/\s*([^\:]+)\s*\:\s*([^\;\n]+)/g, function (match, key, value) {
            request.headers[headerToCamelCase(key)] = value.trim();
        });
      }
      return headersCache;
    };

    request.onreadystatechange = function(){
      if( request.readyState === 'complete' || request.readyState === 4 ) {
        var response = {
          data: parseContentType(contentType, text, xml),
          status: request.status,
          headers: request.getHeaders,
          xhr: request
        };
        if( request.status >= 200 && request.status < 300 ) {
          request.resolve( response );
        } else if( request.status >= 400 ) {
          request.reject( response );
        } else {
          throw new Error('Unexpected status code ' + request.status);
        }
      }
    };

    request.options = options;

    request.send( options.data );

    return {
      then: function (onResolve, onReject) {
        on.resolve.push(onResolve);
        if( onReject instanceof Function ) {
          on.reject.push(onreject);
        }
      },
      error: function (onReject) {
        on.reject.push(onReject);
      }
    };
  }

  function apiOptions (options) {
    options = options || {};
    options.version = options.version || env.version;
    options.sandbox = ( options.sandbox === undefined ? env.sandbox : options.sandbox ) ? '.sandbox' : '';
    options.paramsStr = '';
    if( options.params ) {
      for( var key in options.params ) {
        options.paramsStr += ( options.paramsStr ? '&' : '?' ) + key + '=' + encodeURIComponent(options.params[key]);
      }
    }
    return options;
  }

  // aplazame methods

  function init (options) {
    if( !options ) {
      throw new Error('aplazame.init({options}) requires options');
    }
    if( !options.publicKey ) {
      throw new Error('aplazame.init({options}) requires at least the publicKey');
    }
    extend(env, options);
  }

  function getEnv () {
    return env;
  }

  function apiGet (options) {
    options = apiOptions(options);
    return http(api.host + options.paramsStr, {
      headers: {
        accept: replaceKeys(api.accept, options)
      }
    });
  }

  function apiPost (options) {
    options = apiOptions(options);
    return http(api.host + options.paramsStr, {
      method: 'post',
      headers: {
        accept: replaceKeys(api.accept, options)
      }
    });
  }

  function button (options) {
    // options:
    // ------------------
    // id: "CONTAINER_ID",
    // token: "<ACCESS_TOKEN>",
    // amount: 12050,
    // currency: "EUR",
    // sandbox: true
  }

  function checkout () {
    var iframe = document.createElement('iframe');
    iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(iframeHtml);
    extend(iframe.style, iframeStyle);
    iframe.frameBorder = '0';
    document.body.appendChild(iframe);
  }

  // globalizing aplazame object

  if( document.querySelector('script[data-aplazame]') ) {
    var script = document.querySelector('script[data-aplazame]'),
        initText = script.getAttribute('data-aplazame'),
        envOptions = {};
    if( /\s/.test(initText) ) {
      initText.split(',').forEach(function (part) {
        var keys = part.match(/^([^\:]+)\:(.*)/);
        envOptions[keys[1].trim()] = keys[2].trim();
      });
    } else {
      if( script.getAttribute('data-version') ) {
        envOptions.version = Number(script.getAttribute('data-version'));
      }
      if( script.getAttribute('data-sandbox') ) {
        envOptions.sandbox = script.getAttribute('data-sandbox') === 'true';
      }
    }
    init(envOptions);
  }

  root.aplazame = {
    init: init,
    getEnv: getEnv,
    checkout: checkout,
    button: button,
    apiGet: apiGet,
    apiPost: apiPost
  };

})(this);
<|endoftext|>


<commit_before>const Ytdl = index.Ytdl;

exports.isPlaying = {};
exports.guildMusicInfo = {};
exports.guildQueue = {};
exports.noPlay = {};

exports.stopMusic = function(guild, reason) {
	var connection = guild.voiceConnection;
	if (!connection) return false;
	var voiceChannel = connection.channel;
	var player = connection.player;
	if (!player) return false;
	var dispatcher = player.dispatcher;
	if (!dispatcher) return false;
	exports.isPlaying[guild.id] = false;
	dispatcher.end(reason);
	var guildMusicInfo = exports.guildMusicInfo[guild.id];
	guildMusicInfo.activeSong = null;
	guildMusicInfo.activeAuthor = null;
	guildMusicInfo.voteSkips = [];
	guildMusicInfo.isAuto = false;
	return true;
};

exports.clearQueue = function(guild) {
	exports.guildQueue[guild.id] = [];
	return exports.stopMusic(guild);
};

exports.chooseRandomSong = function(guild, autoPlaylist, lastId) {
	var autoSongs = autoPlaylist.songs;
	var newSong = autoSongs[Util.getRandomInt(0, autoSongs.length-1)];
	var songData = exports.formatSong(newSong[0], false);
	var songInfo = [songData, newSong[1]];
	var songId = songData.id;
	if (autoSongs.length > 1 && songId == lastId) {
		return exports.chooseRandomSong(guild, autoPlaylist, lastId);
	} else {
		return songInfo;
	}
};

exports.playRealSong = function(newSong, guild, channel, doPrint) {
	console.log("Playing Real Song");
	if (doPrint == null) doPrint = true;
	var songData = newSong[0];
	var author = newSong[1];
	var guildMusicInfo = exports.guildMusicInfo[guild.id];
	guildMusicInfo.activeSong = songData;
	guildMusicInfo.activeAuthor = author;
	guildMusicInfo.voteSkips = [];
	guildMusicInfo.isAuto = false;
	exports.streamAudio(songData, guild, channel);
	if (doPrint) Util.sendDescEmbed(channel, "Playing " + songData.title, "Added by " + Util.safeEveryone(author.toString()), Util.makeEmbedFooter(author), null, 0x00E676);
};

exports.playNextQueue = function(guild, channel, doPrint) {
	console.log("\nCalled Playing Next Queue");
	if (doPrint == null) doPrint = true;
	var guildQueue = exports.guildQueue[guild.id];
	var autoPlaylist = Data.guildGet(guild, Data.playlist);
	console.log("guildQueue");
	console.log(guildQueue.length);
	console.log("-------Playing Next Queue---------\n");
	if (guildQueue.length > 0) {
		var newSong = guildQueue[0];
		exports.playRealSong(newSong, guild, channel, doPrint);
	} else if (autoPlaylist.hasOwnProperty("songs") && autoPlaylist.songs.length > 0) {
		console.log("Playing Next Queue, Playing Next Auto");
		exports.playNextAuto(guild, channel, true);
	} else {
		exports.stopMusic(guild);
	}
};

exports.playNextAuto = function(guild, channel, doPrint) {
	var autoPlaylist = Data.guildGet(guild, Data.playlist);
	if (!autoPlaylist.hasOwnProperty("songs") || autoPlaylist.songs.length === 0) {
		exports.stopMusic(guild);
		return;
	}
	var guildMusicInfo = exports.guildMusicInfo[guild.id];
	var lastId = "";
	if (guildMusicInfo.isAuto === true) lastId = guildMusicInfo.activeSong.id;
	var newSong = exports.chooseRandomSong(guild, autoPlaylist, lastId);
	var songData = newSong[0];
	var author = newSong[1];
	/*var newSongNum = songNum+1;
	if (newSongNum >= autoSongs.length) newSongNum = 0;
	autoPlaylist.songNum = newSongNum;
	Data.guildSaveData(Data.playlist);*/
	console.log("Playing Next Auto");
	guildMusicInfo.activeSong = songData;
	guildMusicInfo.activeAuthor = author;
	guildMusicInfo.voteSkips = [];
	guildMusicInfo.isAuto = true;
	exports.streamAudio(songData, guild, channel);
	if (doPrint) Util.sendDescEmbed(channel, "[Auto-Playlist-Started]", "Playing " + songData.title, Util.makeEmbedFooter(null), null, 0x00E676);
};

exports.streamAudio = function(songData, guild, channel) {
	var connection = guild.voiceConnection;
	if (connection == null) return Util.commandFailed(channel, "System", "Bot is not connected to a Voice Channel");

	var oldPlayer = connection.player;

	if (oldPlayer) {
		var oldDispatcher = oldPlayer.dispatcher;
		if (oldDispatcher) {
			console.log("Ended previous!");
			oldDispatcher.end("NewStreamAudio");
		}
	}

	var songId = songData.id;
	var isFile = songData.isFile;

	setTimeout(function() {
		connection = guild.voiceConnection;
		if (connection == null) return Util.commandFailed(channel, "System", "Bot is not connected to a Voice Channel");

		var voiceChannel = connection.channel;

		console.log("Streaming Audio: " + songId);

		const streamOptions = {seek: 0, volume: 0.2};
		var dispatcher;

		if (!isFile) {
			const stream = Ytdl(songId, {filter: 'audioonly'});
			dispatcher = connection.playStream(stream, streamOptions);
		} else {
			dispatcher = connection.playFile("/var/files/VaeBot/resources/music/" + songId + ".mp3");
		}

		exports.isPlaying[guild.id] = true;

		dispatcher.on("error", error => {
			console.log("StreamError: " + error);
		});

		dispatcher.on("end", reason => {
			console.log("Track Ended: " + reason);
			if (reason == "Stream is not generating quickly enough.") {
				if (exports.isPlaying[guild.id]) {
					console.log("Track Ended, Starting Next: " + reason);
					var guildMusicInfo = exports.guildMusicInfo[guild.id];
					var guildQueue = exports.guildQueue[guild.id];

					if (guildQueue.length > 0) {
						var songData = guildQueue[0][0];
						var songId = songData.id;
						if (songId == songId) guildQueue.splice(0, 1);
					}

					if (voiceChannel.members.size > 1) {
						var autoPlaylist = Data.guildGet(guild, Data.playlist);
						if (guildQueue.length === 0 && guildMusicInfo.isAuto === true) {
							console.log("Track Ended, Playing Next Auto");
							exports.playNextAuto(guild, channel);
						} else {
							exports.playNextQueue(guild, channel, true);
						}
					} else {
						exports.stopMusic(guild);
						Util.print(channel, "Auto stopping audio | No users in voice");
					}
				}
			}
		});
	}, 1000);
};

exports.playFile = function(name, guild, channel) {
	var connection = guild.voiceConnection;
	if (connection == null) return Util.commandFailed(channel, "System", "Bot is not connected to a Voice Channel");
	var voiceChannel = connection.channel;

	var oldPlayer = connection.player;
	if (oldPlayer) {
		var oldDispatcher = oldPlayer.dispatcher;
		if (oldDispatcher) {
			console.log("Ended previous!");
			oldDispatcher.end("NewStreamAudio");
		}
	}

	console.log("Playing File: " + name);
	const streamOptions = {seek: 0, volume: 0.2};

	const dispatcher = connection.playFile("/var/files/VaeBot/resources/music/" + name + ".mp3");

	exports.isPlaying[guild.id] = true;

	dispatcher.on("error", error => {
		console.log(error);
	});

	dispatcher.on("end", reason => {
		console.log(reason);
	});
};

exports.joinMusic = function(guild, channel, func) {
	var connection = guild.voiceConnection;
	if (connection == null) {
		var musicChannel = Util.findVoiceChannel("music", guild);
		if (musicChannel) {
			musicChannel.join()
			.then(connection => {
				func(connection);
			})
			.catch(error => console.log("\n[E_JoinMusic] " + error));
		} else {
			Util.print(channel, "Not connected to a voice channel");
			return;
		}
	} else {
		func(connection);
	}
};

exports.formatSong = function(data, isFile) {
	if (isFile) {
		return {
			id: data,
			title: data,
			isFile: true
		};
	} else {
		return {
			id: typeof(data.id) == "object" ? data.id.videoId : data.id,
			title: data.snippet.title,
			isFile: false
		};
	}
};

exports.addSong = function(speaker, guild, channel, songData) {
	var guildQueue = exports.guildQueue[guild.id];
	guildQueue.push([songData, speaker]);
	if (guildQueue.length <= 1 || exports.guildMusicInfo[guild.id].isAuto === true) {
		exports.playNextQueue(guild, channel, true);
	} else {
		Util.sendDescEmbed(channel, "[" + guildQueue.length + "] Audio Queue Appended", songData.title, Util.makeEmbedFooter(speaker), null, 0x00E676);
	}
};
<commit_msg>TP-LINK Archer T9E AC1900 Dual Band Wireless PCI Express Adapter with Three Antennas<commit_after>const Ytdl = index.Ytdl;

exports.isPlaying = {};
exports.guildMusicInfo = {};
exports.guildQueue = {};
exports.noPlay = {};

exports.stopMusic = function(guild, reason) {
	var connection = guild.voiceConnection;
	if (!connection) return false;
	var voiceChannel = connection.channel;
	var player = connection.player;
	if (!player) return false;
	var dispatcher = player.dispatcher;
	if (!dispatcher) return false;
	exports.isPlaying[guild.id] = false;
	dispatcher.end(reason);
	var guildMusicInfo = exports.guildMusicInfo[guild.id];
	guildMusicInfo.activeSong = null;
	guildMusicInfo.activeAuthor = null;
	guildMusicInfo.voteSkips = [];
	guildMusicInfo.isAuto = false;
	return true;
};

exports.clearQueue = function(guild) {
	exports.guildQueue[guild.id] = [];
	return exports.stopMusic(guild);
};

exports.chooseRandomSong = function(guild, autoPlaylist, lastId) {
	var autoSongs = autoPlaylist.songs;
	var newSong = autoSongs[Util.getRandomInt(0, autoSongs.length-1)];
	var songData = exports.formatSong(newSong[0], false);
	var songInfo = [songData, newSong[1]];
	var songId = songData.id;
	if (autoSongs.length > 1 && songId == lastId) {
		return exports.chooseRandomSong(guild, autoPlaylist, lastId);
	} else {
		return songInfo;
	}
};

exports.playRealSong = function(newSong, guild, channel, doPrint) {
	console.log("Playing Real Song");
	if (doPrint == null) doPrint = true;
	var songData = newSong[0];
	var author = newSong[1];
	var guildMusicInfo = exports.guildMusicInfo[guild.id];
	guildMusicInfo.activeSong = songData;
	guildMusicInfo.activeAuthor = author;
	guildMusicInfo.voteSkips = [];
	guildMusicInfo.isAuto = false;
	exports.streamAudio(songData, guild, channel);
	if (doPrint) Util.sendDescEmbed(channel, "Playing " + songData.title, "Added by " + Util.safeEveryone(author.toString()), Util.makeEmbedFooter(author), null, 0x00E676);
};

exports.playNextQueue = function(guild, channel, doPrint) {
	console.log("\nCalled Playing Next Queue");
	if (doPrint == null) doPrint = true;
	var guildQueue = exports.guildQueue[guild.id];
	var autoPlaylist = Data.guildGet(guild, Data.playlist);
	console.log("guildQueue");
	console.log(guildQueue.length);
	console.log("-------Playing Next Queue---------\n");
	if (guildQueue.length > 0) {
		var newSong = guildQueue[0];
		exports.playRealSong(newSong, guild, channel, doPrint);
	} else if (autoPlaylist.hasOwnProperty("songs") && autoPlaylist.songs.length > 0) {
		console.log("Playing Next Queue, Playing Next Auto");
		exports.playNextAuto(guild, channel, true);
	} else {
		exports.stopMusic(guild);
	}
};

exports.playNextAuto = function(guild, channel, doPrint) {
	var autoPlaylist = Data.guildGet(guild, Data.playlist);
	if (!autoPlaylist.hasOwnProperty("songs") || autoPlaylist.songs.length === 0) {
		exports.stopMusic(guild);
		return;
	}
	var guildMusicInfo = exports.guildMusicInfo[guild.id];
	var lastId = "";
	if (guildMusicInfo.isAuto === true) lastId = guildMusicInfo.activeSong.id;
	var newSong = exports.chooseRandomSong(guild, autoPlaylist, lastId);
	var songData = newSong[0];
	var author = newSong[1];
	/*var newSongNum = songNum+1;
	if (newSongNum >= autoSongs.length) newSongNum = 0;
	autoPlaylist.songNum = newSongNum;
	Data.guildSaveData(Data.playlist);*/
	console.log("Playing Next Auto");
	guildMusicInfo.activeSong = songData;
	guildMusicInfo.activeAuthor = author;
	guildMusicInfo.voteSkips = [];
	guildMusicInfo.isAuto = true;
	exports.streamAudio(songData, guild, channel);
	if (doPrint) Util.sendDescEmbed(channel, "[Auto-Playlist-Started]", "Playing " + songData.title, Util.makeEmbedFooter(null), null, 0x00E676);
};

exports.streamAudio = function(songData, guild, channel) {
	var connection = guild.voiceConnection;
	if (connection == null) return Util.commandFailed(channel, "System", "Bot is not connected to a Voice Channel");

	var oldPlayer = connection.player;

	if (oldPlayer) {
		var oldDispatcher = oldPlayer.dispatcher;
		if (oldDispatcher) {
			console.log("Ended previous!");
			oldDispatcher.end("NewStreamAudio");
		}
	}

	var songId = songData.id;
	var isFile = songData.isFile;

	setTimeout(function() {
		connection = guild.voiceConnection;
		if (connection == null) return Util.commandFailed(channel, "System", "Bot is not connected to a Voice Channel");

		var voiceChannel = connection.channel;

		console.log("Streaming Audio: " + songId);

		const streamOptions = {seek: 0, volume: 0.2};
		var dispatcher;

		if (!isFile) {
			const stream = Ytdl(songId, {filter: 'audioonly'});
			dispatcher = connection.playStream(stream, streamOptions);
		} else {
			dispatcher = connection.playFile("/var/files/VaeBot/resources/music/" + songId + ".mp3");
		}

		exports.isPlaying[guild.id] = true;

		dispatcher.on("error", error => {
			console.log("StreamError: " + error);
		});

		dispatcher.on("end", reason => {
			console.log("Track Ended: " + reason);
			if (reason == "Stream is not generating quickly enough." || reason == "stream") {
				if (exports.isPlaying[guild.id]) {
					console.log("Track Ended, Starting Next: " + reason);
					var guildMusicInfo = exports.guildMusicInfo[guild.id];
					var guildQueue = exports.guildQueue[guild.id];

					if (guildQueue.length > 0) {
						var songData = guildQueue[0][0];
						var songId = songData.id;
						if (songId == songId) guildQueue.splice(0, 1);
					}

					if (voiceChannel.members.size > 1) {
						var autoPlaylist = Data.guildGet(guild, Data.playlist);
						if (guildQueue.length === 0 && guildMusicInfo.isAuto === true) {
							console.log("Track Ended, Playing Next Auto");
							exports.playNextAuto(guild, channel);
						} else {
							exports.playNextQueue(guild, channel, true);
						}
					} else {
						exports.stopMusic(guild);
						Util.print(channel, "Auto stopping audio | No users in voice");
					}
				}
			}
		});
	}, 1000);
};

exports.playFile = function(name, guild, channel) {
	var connection = guild.voiceConnection;
	if (connection == null) return Util.commandFailed(channel, "System", "Bot is not connected to a Voice Channel");
	var voiceChannel = connection.channel;

	var oldPlayer = connection.player;
	if (oldPlayer) {
		var oldDispatcher = oldPlayer.dispatcher;
		if (oldDispatcher) {
			console.log("Ended previous!");
			oldDispatcher.end("NewStreamAudio");
		}
	}

	console.log("Playing File: " + name);
	const streamOptions = {seek: 0, volume: 0.2};

	const dispatcher = connection.playFile("/var/files/VaeBot/resources/music/" + name + ".mp3");

	exports.isPlaying[guild.id] = true;

	dispatcher.on("error", error => {
		console.log(error);
	});

	dispatcher.on("end", reason => {
		console.log(reason);
	});
};

exports.joinMusic = function(guild, channel, func) {
	var connection = guild.voiceConnection;
	if (connection == null) {
		var musicChannel = Util.findVoiceChannel("music", guild);
		if (musicChannel) {
			musicChannel.join()
			.then(connection => {
				func(connection);
			})
			.catch(error => console.log("\n[E_JoinMusic] " + error));
		} else {
			Util.print(channel, "Not connected to a voice channel");
			return;
		}
	} else {
		func(connection);
	}
};

exports.formatSong = function(data, isFile) {
	if (isFile) {
		return {
			id: data,
			title: data,
			isFile: true
		};
	} else {
		return {
			id: typeof(data.id) == "object" ? data.id.videoId : data.id,
			title: data.snippet.title,
			isFile: false
		};
	}
};

exports.addSong = function(speaker, guild, channel, songData) {
	var guildQueue = exports.guildQueue[guild.id];
	guildQueue.push([songData, speaker]);
	if (guildQueue.length <= 1 || exports.guildMusicInfo[guild.id].isAuto === true) {
		exports.playNextQueue(guild, channel, true);
	} else {
		Util.sendDescEmbed(channel, "[" + guildQueue.length + "] Audio Queue Appended", songData.title, Util.makeEmbedFooter(speaker), null, 0x00E676);
	}
};
<|endoftext|>


<commit_before>import { LogManager } from 'aurelia-framework';
import { ConsoleAppender } from 'aurelia-logging-console';

//Configure Bluebird Promises.
if (Promise.config) {
  Promise.config({
    warnings: {
      wForgottenReturn: false
    }
  });
}

export function configure (aurelia) {
  aurelia.use
    .standardConfiguration()
    .feature('resources');

  if (!window.hipilerConfig) {
    window.hipilerConfig = {};
  }

  if (window.hipilerConfig.debug) {
    LogManager.addAppender(new ConsoleAppender());
    LogManager.setLevel(LogManager.logLevel.debug);
  }

  if (window.hipilerConfig.testing) {
    aurelia.use.plugin('aurelia-testing');
  }

  aurelia.start().then(() => aurelia.setRoot());
}

export default {
  configure
};
<commit_msg>Init validator plugin<commit_after>import { LogManager } from 'aurelia-framework';
import { ConsoleAppender } from 'aurelia-logging-console';

//Configure Bluebird Promises.
if (Promise.config) {
  Promise.config({
    warnings: {
      wForgottenReturn: false
    }
  });
}

export function configure (aurelia) {
  aurelia.use
    .standardConfiguration()
    .plugin('aurelia-validation')
    .feature('resources');

  if (!window.hipilerConfig) {
    window.hipilerConfig = {};
  }

  if (window.hipilerConfig.debug) {
    LogManager.addAppender(new ConsoleAppender());
    LogManager.setLevel(LogManager.logLevel.debug);
  }

  if (window.hipilerConfig.testing) {
    aurelia.use.plugin('aurelia-testing');
  }

  aurelia.start().then(() => aurelia.setRoot());
}

export default {
  configure
};
<|endoftext|>