/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0

THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.

See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */

function __decorate(decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
}

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
const directives = new WeakMap();
const isDirective = (o) => {
    return typeof o === 'function' && directives.has(o);
};

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
/**
 * True if the custom elements polyfill is in use.
 */
const isCEPolyfill = window.customElements !== undefined &&
    window.customElements.polyfillWrapFlushCallback !==
        undefined;
/**
 * Removes nodes, starting from `start` (inclusive) to `end` (exclusive), from
 * `container`.
 */
const removeNodes = (container, start, end = null) => {
    while (start !== end) {
        const n = start.nextSibling;
        container.removeChild(start);
        start = n;
    }
};

/**
 * @license
 * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
/**
 * A sentinel value that signals that a value was handled by a directive and
 * should not be written to the DOM.
 */
const noChange = {};
/**
 * A sentinel value that signals a NodePart to fully clear its content.
 */
const nothing = {};

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
/**
 * An expression marker with embedded unique key to avoid collision with
 * possible text in templates.
 */
const marker = `{{lit-${String(Math.random()).slice(2)}}}`;
/**
 * An expression marker used text-positions, multi-binding attributes, and
 * attributes with markup-like text values.
 */
const nodeMarker = `<!--${marker}-->`;
const markerRegex = new RegExp(`${marker}|${nodeMarker}`);
/**
 * Suffix appended to all bound attribute names.
 */
const boundAttributeSuffix = '$lit$';
/**
 * An updateable Template that tracks the location of dynamic parts.
 */
class Template {
    constructor(result, element) {
        this.parts = [];
        this.element = element;
        const nodesToRemove = [];
        const stack = [];
        // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null
        const walker = document.createTreeWalker(element.content, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false);
        // Keeps track of the last index associated with a part. We try to delete
        // unnecessary nodes, but we never want to associate two different parts
        // to the same index. They must have a constant node between.
        let lastPartIndex = 0;
        let index = -1;
        let partIndex = 0;
        const { strings, values: { length } } = result;
        while (partIndex < length) {
            const node = walker.nextNode();
            if (node === null) {
                // We've exhausted the content inside a nested template element.
                // Because we still have parts (the outer for-loop), we know:
                // - There is a template in the stack
                // - The walker will find a nextNode outside the template
                walker.currentNode = stack.pop();
                continue;
            }
            index++;
            if (node.nodeType === 1 /* Node.ELEMENT_NODE */) {
                if (node.hasAttributes()) {
                    const attributes = node.attributes;
                    const { length } = attributes;
                    // Per
                    // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap,
                    // attributes are not guaranteed to be returned in document order.
                    // In particular, Edge/IE can return them out of order, so we cannot
                    // assume a correspondence between part index and attribute index.
                    let count = 0;
                    for (let i = 0; i < length; i++) {
                        if (endsWith(attributes[i].name, boundAttributeSuffix)) {
                            count++;
                        }
                    }
                    while (count-- > 0) {
                        // Get the template literal section leading up to the first
                        // expression in this attribute
                        const stringForPart = strings[partIndex];
                        // Find the attribute name
                        const name = lastAttributeNameRegex.exec(stringForPart)[2];
                        // Find the corresponding attribute
                        // All bound attributes have had a suffix added in
                        // TemplateResult#getHTML to opt out of special attribute
                        // handling. To look up the attribute value we also need to add
                        // the suffix.
                        const attributeLookupName = name.toLowerCase() + boundAttributeSuffix;
                        const attributeValue = node.getAttribute(attributeLookupName);
                        node.removeAttribute(attributeLookupName);
                        const statics = attributeValue.split(markerRegex);
                        this.parts.push({ type: 'attribute', index, name, strings: statics });
                        partIndex += statics.length - 1;
                    }
                }
                if (node.tagName === 'TEMPLATE') {
                    stack.push(node);
                    walker.currentNode = node.content;
                }
            }
            else if (node.nodeType === 3 /* Node.TEXT_NODE */) {
                const data = node.data;
                if (data.indexOf(marker) >= 0) {
                    const parent = node.parentNode;
                    const strings = data.split(markerRegex);
                    const lastIndex = strings.length - 1;
                    // Generate a new text node for each literal section
                    // These nodes are also used as the markers for node parts
                    for (let i = 0; i < lastIndex; i++) {
                        let insert;
                        let s = strings[i];
                        if (s === '') {
                            insert = createMarker();
                        }
                        else {
                            const match = lastAttributeNameRegex.exec(s);
                            if (match !== null && endsWith(match[2], boundAttributeSuffix)) {
                                s = s.slice(0, match.index) + match[1] +
                                    match[2].slice(0, -boundAttributeSuffix.length) + match[3];
                            }
                            insert = document.createTextNode(s);
                        }
                        parent.insertBefore(insert, node);
                        this.parts.push({ type: 'node', index: ++index });
                    }
                    // If there's no text, we must insert a comment to mark our place.
                    // Else, we can trust it will stick around after cloning.
                    if (strings[lastIndex] === '') {
                        parent.insertBefore(createMarker(), node);
                        nodesToRemove.push(node);
                    }
                    else {
                        node.data = strings[lastIndex];
                    }
                    // We have a part for each match found
                    partIndex += lastIndex;
                }
            }
            else if (node.nodeType === 8 /* Node.COMMENT_NODE */) {
                if (node.data === marker) {
                    const parent = node.parentNode;
                    // Add a new marker node to be the startNode of the Part if any of
                    // the following are true:
                    //  * We don't have a previousSibling
                    //  * The previousSibling is already the start of a previous part
                    if (node.previousSibling === null || index === lastPartIndex) {
                        index++;
                        parent.insertBefore(createMarker(), node);
                    }
                    lastPartIndex = index;
                    this.parts.push({ type: 'node', index });
                    // If we don't have a nextSibling, keep this node so we have an end.
                    // Else, we can remove it to save future costs.
                    if (node.nextSibling === null) {
                        node.data = '';
                    }
                    else {
                        nodesToRemove.push(node);
                        index--;
                    }
                    partIndex++;
                }
                else {
                    let i = -1;
                    while ((i = node.data.indexOf(marker, i + 1)) !== -1) {
                        // Comment node has a binding marker inside, make an inactive part
                        // The binding won't work, but subsequent bindings will
                        // TODO (justinfagnani): consider whether it's even worth it to
                        // make bindings in comments work
                        this.parts.push({ type: 'node', index: -1 });
                        partIndex++;
                    }
                }
            }
        }
        // Remove text binding nodes after the walk to not disturb the TreeWalker
        for (const n of nodesToRemove) {
            n.parentNode.removeChild(n);
        }
    }
}
const endsWith = (str, suffix) => {
    const index = str.length - suffix.length;
    return index >= 0 && str.slice(index) === suffix;
};
const isTemplatePartActive = (part) => part.index !== -1;
// Allows `document.createComment('')` to be renamed for a
// small manual size-savings.
const createMarker = () => document.createComment('');
/**
 * This regex extracts the attribute name preceding an attribute-position
 * expression. It does this by matching the syntax allowed for attributes
 * against the string literal directly preceding the expression, assuming that
 * the expression is in an attribute-value position.
 *
 * See attributes in the HTML spec:
 * https://www.w3.org/TR/html5/syntax.html#elements-attributes
 *
 * " \x09\x0a\x0c\x0d" are HTML space characters:
 * https://www.w3.org/TR/html5/infrastructure.html#space-characters
 *
 * "\0-\x1F\x7F-\x9F" are Unicode control characters, which includes every
 * space character except " ".
 *
 * So an attribute is:
 *  * The name: any character except a control character, space character, ('),
 *    ("), ">", "=", or "/"
 *  * Followed by zero or more space characters
 *  * Followed by "="
 *  * Followed by zero or more space characters
 *  * Followed by:
 *    * Any character except space, ('), ("), "<", ">", "=", (`), or
 *    * (") then any non-("), or
 *    * (') then any non-(')
 */
const lastAttributeNameRegex = /([ \x09\x0a\x0c\x0d])([^\0-\x1F\x7F-\x9F "'>=/]+)([ \x09\x0a\x0c\x0d]*=[ \x09\x0a\x0c\x0d]*(?:[^ \x09\x0a\x0c\x0d"'`<>=]*|"[^"]*|'[^']*))$/;

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
/**
 * An instance of a `Template` that can be attached to the DOM and updated
 * with new values.
 */
class TemplateInstance {
    constructor(template, processor, options) {
        this.__parts = [];
        this.template = template;
        this.processor = processor;
        this.options = options;
    }
    update(values) {
        let i = 0;
        for (const part of this.__parts) {
            if (part !== undefined) {
                part.setValue(values[i]);
            }
            i++;
        }
        for (const part of this.__parts) {
            if (part !== undefined) {
                part.commit();
            }
        }
    }
    _clone() {
        // There are a number of steps in the lifecycle of a template instance's
        // DOM fragment:
        //  1. Clone - create the instance fragment
        //  2. Adopt - adopt into the main document
        //  3. Process - find part markers and create parts
        //  4. Upgrade - upgrade custom elements
        //  5. Update - set node, attribute, property, etc., values
        //  6. Connect - connect to the document. Optional and outside of this
        //     method.
        //
        // We have a few constraints on the ordering of these steps:
        //  * We need to upgrade before updating, so that property values will pass
        //    through any property setters.
        //  * We would like to process before upgrading so that we're sure that the
        //    cloned fragment is inert and not disturbed by self-modifying DOM.
        //  * We want custom elements to upgrade even in disconnected fragments.
        //
        // Given these constraints, with full custom elements support we would
        // prefer the order: Clone, Process, Adopt, Upgrade, Update, Connect
        //
        // But Safari dooes not implement CustomElementRegistry#upgrade, so we
        // can not implement that order and still have upgrade-before-update and
        // upgrade disconnected fragments. So we instead sacrifice the
        // process-before-upgrade constraint, since in Custom Elements v1 elements
        // must not modify their light DOM in the constructor. We still have issues
        // when co-existing with CEv0 elements like Polymer 1, and with polyfills
        // that don't strictly adhere to the no-modification rule because shadow
        // DOM, which may be created in the constructor, is emulated by being placed
        // in the light DOM.
        //
        // The resulting order is on native is: Clone, Adopt, Upgrade, Process,
        // Update, Connect. document.importNode() performs Clone, Adopt, and Upgrade
        // in one step.
        //
        // The Custom Elements v1 polyfill supports upgrade(), so the order when
        // polyfilled is the more ideal: Clone, Process, Adopt, Upgrade, Update,
        // Connect.
        const fragment = isCEPolyfill ?
            this.template.element.content.cloneNode(true) :
            document.importNode(this.template.element.content, true);
        const stack = [];
        const parts = this.template.parts;
        // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null
        const walker = document.createTreeWalker(fragment, 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */, null, false);
        let partIndex = 0;
        let nodeIndex = 0;
        let part;
        let node = walker.nextNode();
        // Loop through all the nodes and parts of a template
        while (partIndex < parts.length) {
            part = parts[partIndex];
            if (!isTemplatePartActive(part)) {
                this.__parts.push(undefined);
                partIndex++;
                continue;
            }
            // Progress the tree walker until we find our next part's node.
            // Note that multiple parts may share the same node (attribute parts
            // on a single element), so this loop may not run at all.
            while (nodeIndex < part.index) {
                nodeIndex++;
                if (node.nodeName === 'TEMPLATE') {
                    stack.push(node);
                    walker.currentNode = node.content;
                }
                if ((node = walker.nextNode()) === null) {
                    // We've exhausted the content inside a nested template element.
                    // Because we still have parts (the outer for-loop), we know:
                    // - There is a template in the stack
                    // - The walker will find a nextNode outside the template
                    walker.currentNode = stack.pop();
                    node = walker.nextNode();
                }
            }
            // We've arrived at our part's node.
            if (part.type === 'node') {
                const part = this.processor.handleTextExpression(this.options);
                part.insertAfterNode(node.previousSibling);
                this.__parts.push(part);
            }
            else {
                this.__parts.push(...this.processor.handleAttributeExpressions(node, part.name, part.strings, this.options));
            }
            partIndex++;
        }
        if (isCEPolyfill) {
            document.adoptNode(fragment);
            customElements.upgrade(fragment);
        }
        return fragment;
    }
}

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
const commentMarker = ` ${marker} `;
/**
 * The return type of `html`, which holds a Template and the values from
 * interpolated expressions.
 */
class TemplateResult {
    constructor(strings, values, type, processor) {
        this.strings = strings;
        this.values = values;
        this.type = type;
        this.processor = processor;
    }
    /**
     * Returns a string of HTML used to create a `<template>` element.
     */
    getHTML() {
        const l = this.strings.length - 1;
        let html = '';
        let isCommentBinding = false;
        for (let i = 0; i < l; i++) {
            const s = this.strings[i];
            // For each binding we want to determine the kind of marker to insert
            // into the template source before it's parsed by the browser's HTML
            // parser. The marker type is based on whether the expression is in an
            // attribute, text, or comment poisition.
            //   * For node-position bindings we insert a comment with the marker
            //     sentinel as its text content, like <!--{{lit-guid}}-->.
            //   * For attribute bindings we insert just the marker sentinel for the
            //     first binding, so that we support unquoted attribute bindings.
            //     Subsequent bindings can use a comment marker because multi-binding
            //     attributes must be quoted.
            //   * For comment bindings we insert just the marker sentinel so we don't
            //     close the comment.
            //
            // The following code scans the template source, but is *not* an HTML
            // parser. We don't need to track the tree structure of the HTML, only
            // whether a binding is inside a comment, and if not, if it appears to be
            // the first binding in an attribute.
            const commentOpen = s.lastIndexOf('<!--');
            // We're in comment position if we have a comment open with no following
            // comment close. Because <-- can appear in an attribute value there can
            // be false positives.
            isCommentBinding = (commentOpen > -1 || isCommentBinding) &&
                s.indexOf('-->', commentOpen + 1) === -1;
            // Check to see if we have an attribute-like sequence preceeding the
            // expression. This can match "name=value" like structures in text,
            // comments, and attribute values, so there can be false-positives.
            const attributeMatch = lastAttributeNameRegex.exec(s);
            if (attributeMatch === null) {
                // We're only in this branch if we don't have a attribute-like
                // preceeding sequence. For comments, this guards against unusual
                // attribute values like <div foo="<!--${'bar'}">. Cases like
                // <!-- foo=${'bar'}--> are handled correctly in the attribute branch
                // below.
                html += s + (isCommentBinding ? commentMarker : nodeMarker);
            }
            else {
                // For attributes we use just a marker sentinel, and also append a
                // $lit$ suffix to the name to opt-out of attribute-specific parsing
                // that IE and Edge do for style and certain SVG attributes.
                html += s.substr(0, attributeMatch.index) + attributeMatch[1] +
                    attributeMatch[2] + boundAttributeSuffix + attributeMatch[3] +
                    marker;
            }
        }
        html += this.strings[l];
        return html;
    }
    getTemplateElement() {
        const template = document.createElement('template');
        template.innerHTML = this.getHTML();
        return template;
    }
}

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
const isPrimitive = (value) => {
    return (value === null ||
        !(typeof value === 'object' || typeof value === 'function'));
};
const isIterable = (value) => {
    return Array.isArray(value) ||
        // tslint:disable-next-line:no-any
        !!(value && value[Symbol.iterator]);
};
/**
 * Writes attribute values to the DOM for a group of AttributeParts bound to a
 * single attibute. The value is only set once even if there are multiple parts
 * for an attribute.
 */
class AttributeCommitter {
    constructor(element, name, strings) {
        this.dirty = true;
        this.element = element;
        this.name = name;
        this.strings = strings;
        this.parts = [];
        for (let i = 0; i < strings.length - 1; i++) {
            this.parts[i] = this._createPart();
        }
    }
    /**
     * Creates a single part. Override this to create a differnt type of part.
     */
    _createPart() {
        return new AttributePart(this);
    }
    _getValue() {
        const strings = this.strings;
        const l = strings.length - 1;
        let text = '';
        for (let i = 0; i < l; i++) {
            text += strings[i];
            const part = this.parts[i];
            if (part !== undefined) {
                const v = part.value;
                if (isPrimitive(v) || !isIterable(v)) {
                    text += typeof v === 'string' ? v : String(v);
                }
                else {
                    for (const t of v) {
                        text += typeof t === 'string' ? t : String(t);
                    }
                }
            }
        }
        text += strings[l];
        return text;
    }
    commit() {
        if (this.dirty) {
            this.dirty = false;
            this.element.setAttribute(this.name, this._getValue());
        }
    }
}
/**
 * A Part that controls all or part of an attribute value.
 */
class AttributePart {
    constructor(committer) {
        this.value = undefined;
        this.committer = committer;
    }
    setValue(value) {
        if (value !== noChange && (!isPrimitive(value) || value !== this.value)) {
            this.value = value;
            // If the value is a not a directive, dirty the committer so that it'll
            // call setAttribute. If the value is a directive, it'll dirty the
            // committer if it calls setValue().
            if (!isDirective(value)) {
                this.committer.dirty = true;
            }
        }
    }
    commit() {
        while (isDirective(this.value)) {
            const directive = this.value;
            this.value = noChange;
            directive(this);
        }
        if (this.value === noChange) {
            return;
        }
        this.committer.commit();
    }
}
/**
 * A Part that controls a location within a Node tree. Like a Range, NodePart
 * has start and end locations and can set and update the Nodes between those
 * locations.
 *
 * NodeParts support several value types: primitives, Nodes, TemplateResults,
 * as well as arrays and iterables of those types.
 */
class NodePart {
    constructor(options) {
        this.value = undefined;
        this.__pendingValue = undefined;
        this.options = options;
    }
    /**
     * Appends this part into a container.
     *
     * This part must be empty, as its contents are not automatically moved.
     */
    appendInto(container) {
        this.startNode = container.appendChild(createMarker());
        this.endNode = container.appendChild(createMarker());
    }
    /**
     * Inserts this part after the `ref` node (between `ref` and `ref`'s next
     * sibling). Both `ref` and its next sibling must be static, unchanging nodes
     * such as those that appear in a literal section of a template.
     *
     * This part must be empty, as its contents are not automatically moved.
     */
    insertAfterNode(ref) {
        this.startNode = ref;
        this.endNode = ref.nextSibling;
    }
    /**
     * Appends this part into a parent part.
     *
     * This part must be empty, as its contents are not automatically moved.
     */
    appendIntoPart(part) {
        part.__insert(this.startNode = createMarker());
        part.__insert(this.endNode = createMarker());
    }
    /**
     * Inserts this part after the `ref` part.
     *
     * This part must be empty, as its contents are not automatically moved.
     */
    insertAfterPart(ref) {
        ref.__insert(this.startNode = createMarker());
        this.endNode = ref.endNode;
        ref.endNode = this.startNode;
    }
    setValue(value) {
        this.__pendingValue = value;
    }
    commit() {
        while (isDirective(this.__pendingValue)) {
            const directive = this.__pendingValue;
            this.__pendingValue = noChange;
            directive(this);
        }
        const value = this.__pendingValue;
        if (value === noChange) {
            return;
        }
        if (isPrimitive(value)) {
            if (value !== this.value) {
                this.__commitText(value);
            }
        }
        else if (value instanceof TemplateResult) {
            this.__commitTemplateResult(value);
        }
        else if (value instanceof Node) {
            this.__commitNode(value);
        }
        else if (isIterable(value)) {
            this.__commitIterable(value);
        }
        else if (value === nothing) {
            this.value = nothing;
            this.clear();
        }
        else {
            // Fallback, will render the string representation
            this.__commitText(value);
        }
    }
    __insert(node) {
        this.endNode.parentNode.insertBefore(node, this.endNode);
    }
    __commitNode(value) {
        if (this.value === value) {
            return;
        }
        this.clear();
        this.__insert(value);
        this.value = value;
    }
    __commitText(value) {
        const node = this.startNode.nextSibling;
        value = value == null ? '' : value;
        // If `value` isn't already a string, we explicitly convert it here in case
        // it can't be implicitly converted - i.e. it's a symbol.
        const valueAsString = typeof value === 'string' ? value : String(value);
        if (node === this.endNode.previousSibling &&
            node.nodeType === 3 /* Node.TEXT_NODE */) {
            // If we only have a single text node between the markers, we can just
            // set its value, rather than replacing it.
            // TODO(justinfagnani): Can we just check if this.value is primitive?
            node.data = valueAsString;
        }
        else {
            this.__commitNode(document.createTextNode(valueAsString));
        }
        this.value = value;
    }
    __commitTemplateResult(value) {
        const template = this.options.templateFactory(value);
        if (this.value instanceof TemplateInstance &&
            this.value.template === template) {
            this.value.update(value.values);
        }
        else {
            // Make sure we propagate the template processor from the TemplateResult
            // so that we use its syntax extension, etc. The template factory comes
            // from the render function options so that it can control template
            // caching and preprocessing.
            const instance = new TemplateInstance(template, value.processor, this.options);
            const fragment = instance._clone();
            instance.update(value.values);
            this.__commitNode(fragment);
            this.value = instance;
        }
    }
    __commitIterable(value) {
        // For an Iterable, we create a new InstancePart per item, then set its
        // value to the item. This is a little bit of overhead for every item in
        // an Iterable, but it lets us recurse easily and efficiently update Arrays
        // of TemplateResults that will be commonly returned from expressions like:
        // array.map((i) => html`${i}`), by reusing existing TemplateInstances.
        // If _value is an array, then the previous render was of an
        // iterable and _value will contain the NodeParts from the previous
        // render. If _value is not an array, clear this part and make a new
        // array for NodeParts.
        if (!Array.isArray(this.value)) {
            this.value = [];
            this.clear();
        }
        // Lets us keep track of how many items we stamped so we can clear leftover
        // items from a previous render
        const itemParts = this.value;
        let partIndex = 0;
        let itemPart;
        for (const item of value) {
            // Try to reuse an existing part
            itemPart = itemParts[partIndex];
            // If no existing part, create a new one
            if (itemPart === undefined) {
                itemPart = new NodePart(this.options);
                itemParts.push(itemPart);
                if (partIndex === 0) {
                    itemPart.appendIntoPart(this);
                }
                else {
                    itemPart.insertAfterPart(itemParts[partIndex - 1]);
                }
            }
            itemPart.setValue(item);
            itemPart.commit();
            partIndex++;
        }
        if (partIndex < itemParts.length) {
            // Truncate the parts array so _value reflects the current state
            itemParts.length = partIndex;
            this.clear(itemPart && itemPart.endNode);
        }
    }
    clear(startNode = this.startNode) {
        removeNodes(this.startNode.parentNode, startNode.nextSibling, this.endNode);
    }
}
/**
 * Implements a boolean attribute, roughly as defined in the HTML
 * specification.
 *
 * If the value is truthy, then the attribute is present with a value of
 * ''. If the value is falsey, the attribute is removed.
 */
class BooleanAttributePart {
    constructor(element, name, strings) {
        this.value = undefined;
        this.__pendingValue = undefined;
        if (strings.length !== 2 || strings[0] !== '' || strings[1] !== '') {
            throw new Error('Boolean attributes can only contain a single expression');
        }
        this.element = element;
        this.name = name;
        this.strings = strings;
    }
    setValue(value) {
        this.__pendingValue = value;
    }
    commit() {
        while (isDirective(this.__pendingValue)) {
            const directive = this.__pendingValue;
            this.__pendingValue = noChange;
            directive(this);
        }
        if (this.__pendingValue === noChange) {
            return;
        }
        const value = !!this.__pendingValue;
        if (this.value !== value) {
            if (value) {
                this.element.setAttribute(this.name, '');
            }
            else {
                this.element.removeAttribute(this.name);
            }
            this.value = value;
        }
        this.__pendingValue = noChange;
    }
}
/**
 * Sets attribute values for PropertyParts, so that the value is only set once
 * even if there are multiple parts for a property.
 *
 * If an expression controls the whole property value, then the value is simply
 * assigned to the property under control. If there are string literals or
 * multiple expressions, then the strings are expressions are interpolated into
 * a string first.
 */
class PropertyCommitter extends AttributeCommitter {
    constructor(element, name, strings) {
        super(element, name, strings);
        this.single =
            (strings.length === 2 && strings[0] === '' && strings[1] === '');
    }
    _createPart() {
        return new PropertyPart(this);
    }
    _getValue() {
        if (this.single) {
            return this.parts[0].value;
        }
        return super._getValue();
    }
    commit() {
        if (this.dirty) {
            this.dirty = false;
            // tslint:disable-next-line:no-any
            this.element[this.name] = this._getValue();
        }
    }
}
class PropertyPart extends AttributePart {
}
// Detect event listener options support. If the `capture` property is read
// from the options object, then options are supported. If not, then the thrid
// argument to add/removeEventListener is interpreted as the boolean capture
// value so we should only pass the `capture` property.
let eventOptionsSupported = false;
try {
    const options = {
        get capture() {
            eventOptionsSupported = true;
            return false;
        }
    };
    // tslint:disable-next-line:no-any
    window.addEventListener('test', options, options);
    // tslint:disable-next-line:no-any
    window.removeEventListener('test', options, options);
}
catch (_e) {
}
class EventPart {
    constructor(element, eventName, eventContext) {
        this.value = undefined;
        this.__pendingValue = undefined;
        this.element = element;
        this.eventName = eventName;
        this.eventContext = eventContext;
        this.__boundHandleEvent = (e) => this.handleEvent(e);
    }
    setValue(value) {
        this.__pendingValue = value;
    }
    commit() {
        while (isDirective(this.__pendingValue)) {
            const directive = this.__pendingValue;
            this.__pendingValue = noChange;
            directive(this);
        }
        if (this.__pendingValue === noChange) {
            return;
        }
        const newListener = this.__pendingValue;
        const oldListener = this.value;
        const shouldRemoveListener = newListener == null ||
            oldListener != null &&
                (newListener.capture !== oldListener.capture ||
                    newListener.once !== oldListener.once ||
                    newListener.passive !== oldListener.passive);
        const shouldAddListener = newListener != null && (oldListener == null || shouldRemoveListener);
        if (shouldRemoveListener) {
            this.element.removeEventListener(this.eventName, this.__boundHandleEvent, this.__options);
        }
        if (shouldAddListener) {
            this.__options = getOptions(newListener);
            this.element.addEventListener(this.eventName, this.__boundHandleEvent, this.__options);
        }
        this.value = newListener;
        this.__pendingValue = noChange;
    }
    handleEvent(event) {
        if (typeof this.value === 'function') {
            this.value.call(this.eventContext || this.element, event);
        }
        else {
            this.value.handleEvent(event);
        }
    }
}
// We copy options because of the inconsistent behavior of browsers when reading
// the third argument of add/removeEventListener. IE11 doesn't support options
// at all. Chrome 41 only reads `capture` if the argument is an object.
const getOptions = (o) => o &&
    (eventOptionsSupported ?
        { capture: o.capture, passive: o.passive, once: o.once } :
        o.capture);

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
/**
 * Creates Parts when a template is instantiated.
 */
class DefaultTemplateProcessor {
    /**
     * Create parts for an attribute-position binding, given the event, attribute
     * name, and string literals.
     *
     * @param element The element containing the binding
     * @param name  The attribute name
     * @param strings The string literals. There are always at least two strings,
     *   event for fully-controlled bindings with a single expression.
     */
    handleAttributeExpressions(element, name, strings, options) {
        const prefix = name[0];
        if (prefix === '.') {
            const committer = new PropertyCommitter(element, name.slice(1), strings);
            return committer.parts;
        }
        if (prefix === '@') {
            return [new EventPart(element, name.slice(1), options.eventContext)];
        }
        if (prefix === '?') {
            return [new BooleanAttributePart(element, name.slice(1), strings)];
        }
        const committer = new AttributeCommitter(element, name, strings);
        return committer.parts;
    }
    /**
     * Create parts for a text-position binding.
     * @param templateFactory
     */
    handleTextExpression(options) {
        return new NodePart(options);
    }
}
const defaultTemplateProcessor = new DefaultTemplateProcessor();

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
/**
 * The default TemplateFactory which caches Templates keyed on
 * result.type and result.strings.
 */
function templateFactory(result) {
    let templateCache = templateCaches.get(result.type);
    if (templateCache === undefined) {
        templateCache = {
            stringsArray: new WeakMap(),
            keyString: new Map()
        };
        templateCaches.set(result.type, templateCache);
    }
    let template = templateCache.stringsArray.get(result.strings);
    if (template !== undefined) {
        return template;
    }
    // If the TemplateStringsArray is new, generate a key from the strings
    // This key is shared between all templates with identical content
    const key = result.strings.join(marker);
    // Check if we already have a Template for this key
    template = templateCache.keyString.get(key);
    if (template === undefined) {
        // If we have not seen this key before, create a new Template
        template = new Template(result, result.getTemplateElement());
        // Cache the Template for this key
        templateCache.keyString.set(key, template);
    }
    // Cache all future queries for this TemplateStringsArray
    templateCache.stringsArray.set(result.strings, template);
    return template;
}
const templateCaches = new Map();

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
const parts = new WeakMap();
/**
 * Renders a template result or other value to a container.
 *
 * To update a container with new values, reevaluate the template literal and
 * call `render` with the new result.
 *
 * @param result Any value renderable by NodePart - typically a TemplateResult
 *     created by evaluating a template tag like `html` or `svg`.
 * @param container A DOM parent to render to. The entire contents are either
 *     replaced, or efficiently updated if the same result type was previous
 *     rendered there.
 * @param options RenderOptions for the entire render tree rendered to this
 *     container. Render options must *not* change between renders to the same
 *     container, as those changes will not effect previously rendered DOM.
 */
const render = (result, container, options) => {
    let part = parts.get(container);
    if (part === undefined) {
        removeNodes(container, container.firstChild);
        parts.set(container, part = new NodePart(Object.assign({ templateFactory }, options)));
        part.appendInto(container);
    }
    part.setValue(result);
    part.commit();
};

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
// IMPORTANT: do not change the property name or the assignment expression.
// This line will be used in regexes to search for lit-html usage.
// TODO(justinfagnani): inject version number at build time
(window['litHtmlVersions'] || (window['litHtmlVersions'] = [])).push('1.1.2');
/**
 * Interprets a template literal as an HTML template that can efficiently
 * render to and update a container.
 */
const html = (strings, ...values) => new TemplateResult(strings, values, 'html', defaultTemplateProcessor);

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
const walkerNodeFilter = 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */;
/**
 * Removes the list of nodes from a Template safely. In addition to removing
 * nodes from the Template, the Template part indices are updated to match
 * the mutated Template DOM.
 *
 * As the template is walked the removal state is tracked and
 * part indices are adjusted as needed.
 *
 * div
 *   div#1 (remove) <-- start removing (removing node is div#1)
 *     div
 *       div#2 (remove)  <-- continue removing (removing node is still div#1)
 *         div
 * div <-- stop removing since previous sibling is the removing node (div#1,
 * removed 4 nodes)
 */
function removeNodesFromTemplate(template, nodesToRemove) {
    const { element: { content }, parts } = template;
    const walker = document.createTreeWalker(content, walkerNodeFilter, null, false);
    let partIndex = nextActiveIndexInTemplateParts(parts);
    let part = parts[partIndex];
    let nodeIndex = -1;
    let removeCount = 0;
    const nodesToRemoveInTemplate = [];
    let currentRemovingNode = null;
    while (walker.nextNode()) {
        nodeIndex++;
        const node = walker.currentNode;
        // End removal if stepped past the removing node
        if (node.previousSibling === currentRemovingNode) {
            currentRemovingNode = null;
        }
        // A node to remove was found in the template
        if (nodesToRemove.has(node)) {
            nodesToRemoveInTemplate.push(node);
            // Track node we're removing
            if (currentRemovingNode === null) {
                currentRemovingNode = node;
            }
        }
        // When removing, increment count by which to adjust subsequent part indices
        if (currentRemovingNode !== null) {
            removeCount++;
        }
        while (part !== undefined && part.index === nodeIndex) {
            // If part is in a removed node deactivate it by setting index to -1 or
            // adjust the index as needed.
            part.index = currentRemovingNode !== null ? -1 : part.index - removeCount;
            // go to the next active part.
            partIndex = nextActiveIndexInTemplateParts(parts, partIndex);
            part = parts[partIndex];
        }
    }
    nodesToRemoveInTemplate.forEach((n) => n.parentNode.removeChild(n));
}
const countNodes = (node) => {
    let count = (node.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */) ? 0 : 1;
    const walker = document.createTreeWalker(node, walkerNodeFilter, null, false);
    while (walker.nextNode()) {
        count++;
    }
    return count;
};
const nextActiveIndexInTemplateParts = (parts, startIndex = -1) => {
    for (let i = startIndex + 1; i < parts.length; i++) {
        const part = parts[i];
        if (isTemplatePartActive(part)) {
            return i;
        }
    }
    return -1;
};
/**
 * Inserts the given node into the Template, optionally before the given
 * refNode. In addition to inserting the node into the Template, the Template
 * part indices are updated to match the mutated Template DOM.
 */
function insertNodeIntoTemplate(template, node, refNode = null) {
    const { element: { content }, parts } = template;
    // If there's no refNode, then put node at end of template.
    // No part indices need to be shifted in this case.
    if (refNode === null || refNode === undefined) {
        content.appendChild(node);
        return;
    }
    const walker = document.createTreeWalker(content, walkerNodeFilter, null, false);
    let partIndex = nextActiveIndexInTemplateParts(parts);
    let insertCount = 0;
    let walkerIndex = -1;
    while (walker.nextNode()) {
        walkerIndex++;
        const walkerNode = walker.currentNode;
        if (walkerNode === refNode) {
            insertCount = countNodes(node);
            refNode.parentNode.insertBefore(node, refNode);
        }
        while (partIndex !== -1 && parts[partIndex].index === walkerIndex) {
            // If we've inserted the node, simply adjust all subsequent parts
            if (insertCount > 0) {
                while (partIndex !== -1) {
                    parts[partIndex].index += insertCount;
                    partIndex = nextActiveIndexInTemplateParts(parts, partIndex);
                }
                return;
            }
            partIndex = nextActiveIndexInTemplateParts(parts, partIndex);
        }
    }
}

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
// Get a key to lookup in `templateCaches`.
const getTemplateCacheKey = (type, scopeName) => `${type}--${scopeName}`;
let compatibleShadyCSSVersion = true;
if (typeof window.ShadyCSS === 'undefined') {
    compatibleShadyCSSVersion = false;
}
else if (typeof window.ShadyCSS.prepareTemplateDom === 'undefined') {
    console.warn(`Incompatible ShadyCSS version detected. ` +
        `Please update to at least @webcomponents/webcomponentsjs@2.0.2 and ` +
        `@webcomponents/shadycss@1.3.1.`);
    compatibleShadyCSSVersion = false;
}
/**
 * Template factory which scopes template DOM using ShadyCSS.
 * @param scopeName {string}
 */
const shadyTemplateFactory = (scopeName) => (result) => {
    const cacheKey = getTemplateCacheKey(result.type, scopeName);
    let templateCache = templateCaches.get(cacheKey);
    if (templateCache === undefined) {
        templateCache = {
            stringsArray: new WeakMap(),
            keyString: new Map()
        };
        templateCaches.set(cacheKey, templateCache);
    }
    let template = templateCache.stringsArray.get(result.strings);
    if (template !== undefined) {
        return template;
    }
    const key = result.strings.join(marker);
    template = templateCache.keyString.get(key);
    if (template === undefined) {
        const element = result.getTemplateElement();
        if (compatibleShadyCSSVersion) {
            window.ShadyCSS.prepareTemplateDom(element, scopeName);
        }
        template = new Template(result, element);
        templateCache.keyString.set(key, template);
    }
    templateCache.stringsArray.set(result.strings, template);
    return template;
};
const TEMPLATE_TYPES = ['html', 'svg'];
/**
 * Removes all style elements from Templates for the given scopeName.
 */
const removeStylesFromLitTemplates = (scopeName) => {
    TEMPLATE_TYPES.forEach((type) => {
        const templates = templateCaches.get(getTemplateCacheKey(type, scopeName));
        if (templates !== undefined) {
            templates.keyString.forEach((template) => {
                const { element: { content } } = template;
                // IE 11 doesn't support the iterable param Set constructor
                const styles = new Set();
                Array.from(content.querySelectorAll('style')).forEach((s) => {
                    styles.add(s);
                });
                removeNodesFromTemplate(template, styles);
            });
        }
    });
};
const shadyRenderSet = new Set();
/**
 * For the given scope name, ensures that ShadyCSS style scoping is performed.
 * This is done just once per scope name so the fragment and template cannot
 * be modified.
 * (1) extracts styles from the rendered fragment and hands them to ShadyCSS
 * to be scoped and appended to the document
 * (2) removes style elements from all lit-html Templates for this scope name.
 *
 * Note, <style> elements can only be placed into templates for the
 * initial rendering of the scope. If <style> elements are included in templates
 * dynamically rendered to the scope (after the first scope render), they will
 * not be scoped and the <style> will be left in the template and rendered
 * output.
 */
const prepareTemplateStyles = (scopeName, renderedDOM, template) => {
    shadyRenderSet.add(scopeName);
    // If `renderedDOM` is stamped from a Template, then we need to edit that
    // Template's underlying template element. Otherwise, we create one here
    // to give to ShadyCSS, which still requires one while scoping.
    const templateElement = !!template ? template.element : document.createElement('template');
    // Move styles out of rendered DOM and store.
    const styles = renderedDOM.querySelectorAll('style');
    const { length } = styles;
    // If there are no styles, skip unnecessary work
    if (length === 0) {
        // Ensure prepareTemplateStyles is called to support adding
        // styles via `prepareAdoptedCssText` since that requires that
        // `prepareTemplateStyles` is called.
        //
        // ShadyCSS will only update styles containing @apply in the template
        // given to `prepareTemplateStyles`. If no lit Template was given,
        // ShadyCSS will not be able to update uses of @apply in any relevant
        // template. However, this is not a problem because we only create the
        // template for the purpose of supporting `prepareAdoptedCssText`,
        // which doesn't support @apply at all.
        window.ShadyCSS.prepareTemplateStyles(templateElement, scopeName);
        return;
    }
    const condensedStyle = document.createElement('style');
    // Collect styles into a single style. This helps us make sure ShadyCSS
    // manipulations will not prevent us from being able to fix up template
    // part indices.
    // NOTE: collecting styles is inefficient for browsers but ShadyCSS
    // currently does this anyway. When it does not, this should be changed.
    for (let i = 0; i < length; i++) {
        const style = styles[i];
        style.parentNode.removeChild(style);
        condensedStyle.textContent += style.textContent;
    }
    // Remove styles from nested templates in this scope.
    removeStylesFromLitTemplates(scopeName);
    // And then put the condensed style into the "root" template passed in as
    // `template`.
    const content = templateElement.content;
    if (!!template) {
        insertNodeIntoTemplate(template, condensedStyle, content.firstChild);
    }
    else {
        content.insertBefore(condensedStyle, content.firstChild);
    }
    // Note, it's important that ShadyCSS gets the template that `lit-html`
    // will actually render so that it can update the style inside when
    // needed (e.g. @apply native Shadow DOM case).
    window.ShadyCSS.prepareTemplateStyles(templateElement, scopeName);
    const style = content.querySelector('style');
    if (window.ShadyCSS.nativeShadow && style !== null) {
        // When in native Shadow DOM, ensure the style created by ShadyCSS is
        // included in initially rendered output (`renderedDOM`).
        renderedDOM.insertBefore(style.cloneNode(true), renderedDOM.firstChild);
    }
    else if (!!template) {
        // When no style is left in the template, parts will be broken as a
        // result. To fix this, we put back the style node ShadyCSS removed
        // and then tell lit to remove that node from the template.
        // There can be no style in the template in 2 cases (1) when Shady DOM
        // is in use, ShadyCSS removes all styles, (2) when native Shadow DOM
        // is in use ShadyCSS removes the style if it contains no content.
        // NOTE, ShadyCSS creates its own style so we can safely add/remove
        // `condensedStyle` here.
        content.insertBefore(condensedStyle, content.firstChild);
        const removes = new Set();
        removes.add(condensedStyle);
        removeNodesFromTemplate(template, removes);
    }
};
/**
 * Extension to the standard `render` method which supports rendering
 * to ShadowRoots when the ShadyDOM (https://github.com/webcomponents/shadydom)
 * and ShadyCSS (https://github.com/webcomponents/shadycss) polyfills are used
 * or when the webcomponentsjs
 * (https://github.com/webcomponents/webcomponentsjs) polyfill is used.
 *
 * Adds a `scopeName` option which is used to scope element DOM and stylesheets
 * when native ShadowDOM is unavailable. The `scopeName` will be added to
 * the class attribute of all rendered DOM. In addition, any style elements will
 * be automatically re-written with this `scopeName` selector and moved out
 * of the rendered DOM and into the document `<head>`.
 *
 * It is common to use this render method in conjunction with a custom element
 * which renders a shadowRoot. When this is done, typically the element's
 * `localName` should be used as the `scopeName`.
 *
 * In addition to DOM scoping, ShadyCSS also supports a basic shim for css
 * custom properties (needed only on older browsers like IE11) and a shim for
 * a deprecated feature called `@apply` that supports applying a set of css
 * custom properties to a given location.
 *
 * Usage considerations:
 *
 * * Part values in `<style>` elements are only applied the first time a given
 * `scopeName` renders. Subsequent changes to parts in style elements will have
 * no effect. Because of this, parts in style elements should only be used for
 * values that will never change, for example parts that set scope-wide theme
 * values or parts which render shared style elements.
 *
 * * Note, due to a limitation of the ShadyDOM polyfill, rendering in a
 * custom element's `constructor` is not supported. Instead rendering should
 * either done asynchronously, for example at microtask timing (for example
 * `Promise.resolve()`), or be deferred until the first time the element's
 * `connectedCallback` runs.
 *
 * Usage considerations when using shimmed custom properties or `@apply`:
 *
 * * Whenever any dynamic changes are made which affect
 * css custom properties, `ShadyCSS.styleElement(element)` must be called
 * to update the element. There are two cases when this is needed:
 * (1) the element is connected to a new parent, (2) a class is added to the
 * element that causes it to match different custom properties.
 * To address the first case when rendering a custom element, `styleElement`
 * should be called in the element's `connectedCallback`.
 *
 * * Shimmed custom properties may only be defined either for an entire
 * shadowRoot (for example, in a `:host` rule) or via a rule that directly
 * matches an element with a shadowRoot. In other words, instead of flowing from
 * parent to child as do native css custom properties, shimmed custom properties
 * flow only from shadowRoots to nested shadowRoots.
 *
 * * When using `@apply` mixing css shorthand property names with
 * non-shorthand names (for example `border` and `border-width`) is not
 * supported.
 */
const render$1 = (result, container, options) => {
    if (!options || typeof options !== 'object' || !options.scopeName) {
        throw new Error('The `scopeName` option is required.');
    }
    const scopeName = options.scopeName;
    const hasRendered = parts.has(container);
    const needsScoping = compatibleShadyCSSVersion &&
        container.nodeType === 11 /* Node.DOCUMENT_FRAGMENT_NODE */ &&
        !!container.host;
    // Handle first render to a scope specially...
    const firstScopeRender = needsScoping && !shadyRenderSet.has(scopeName);
    // On first scope render, render into a fragment; this cannot be a single
    // fragment that is reused since nested renders can occur synchronously.
    const renderContainer = firstScopeRender ? document.createDocumentFragment() : container;
    render(result, renderContainer, Object.assign({ templateFactory: shadyTemplateFactory(scopeName) }, options));
    // When performing first scope render,
    // (1) We've rendered into a fragment so that there's a chance to
    // `prepareTemplateStyles` before sub-elements hit the DOM
    // (which might cause them to render based on a common pattern of
    // rendering in a custom element's `connectedCallback`);
    // (2) Scope the template with ShadyCSS one time only for this scope.
    // (3) Render the fragment into the container and make sure the
    // container knows its `part` is the one we just rendered. This ensures
    // DOM will be re-used on subsequent renders.
    if (firstScopeRender) {
        const part = parts.get(renderContainer);
        parts.delete(renderContainer);
        // ShadyCSS might have style sheets (e.g. from `prepareAdoptedCssText`)
        // that should apply to `renderContainer` even if the rendered value is
        // not a TemplateInstance. However, it will only insert scoped styles
        // into the document if `prepareTemplateStyles` has already been called
        // for the given scope name.
        const template = part.value instanceof TemplateInstance ?
            part.value.template :
            undefined;
        prepareTemplateStyles(scopeName, renderContainer, template);
        removeNodes(container, container.firstChild);
        container.appendChild(renderContainer);
        parts.set(container, part);
    }
    // After elements have hit the DOM, update styling if this is the
    // initial render to this container.
    // This is needed whenever dynamic changes are made so it would be
    // safest to do every render; however, this would regress performance
    // so we leave it up to the user to call `ShadyCSS.styleElement`
    // for dynamic changes.
    if (!hasRendered && needsScoping) {
        window.ShadyCSS.styleElement(container.host);
    }
};

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
var _a;
/**
 * When using Closure Compiler, JSCompiler_renameProperty(property, object) is
 * replaced at compile time by the munged name for object[property]. We cannot
 * alias this function, so we have to use a small shim that has the same
 * behavior when not compiling.
 */
window.JSCompiler_renameProperty =
    (prop, _obj) => prop;
const defaultConverter = {
    toAttribute(value, type) {
        switch (type) {
            case Boolean:
                return value ? '' : null;
            case Object:
            case Array:
                // if the value is `null` or `undefined` pass this through
                // to allow removing/no change behavior.
                return value == null ? value : JSON.stringify(value);
        }
        return value;
    },
    fromAttribute(value, type) {
        switch (type) {
            case Boolean:
                return value !== null;
            case Number:
                return value === null ? null : Number(value);
            case Object:
            case Array:
                return JSON.parse(value);
        }
        return value;
    }
};
/**
 * Change function that returns true if `value` is different from `oldValue`.
 * This method is used as the default for a property's `hasChanged` function.
 */
const notEqual = (value, old) => {
    // This ensures (old==NaN, value==NaN) always returns false
    return old !== value && (old === old || value === value);
};
const defaultPropertyDeclaration = {
    attribute: true,
    type: String,
    converter: defaultConverter,
    reflect: false,
    hasChanged: notEqual
};
const microtaskPromise = Promise.resolve(true);
const STATE_HAS_UPDATED = 1;
const STATE_UPDATE_REQUESTED = 1 << 2;
const STATE_IS_REFLECTING_TO_ATTRIBUTE = 1 << 3;
const STATE_IS_REFLECTING_TO_PROPERTY = 1 << 4;
const STATE_HAS_CONNECTED = 1 << 5;
/**
 * The Closure JS Compiler doesn't currently have good support for static
 * property semantics where "this" is dynamic (e.g.
 * https://github.com/google/closure-compiler/issues/3177 and others) so we use
 * this hack to bypass any rewriting by the compiler.
 */
const finalized = 'finalized';
/**
 * Base element class which manages element properties and attributes. When
 * properties change, the `update` method is asynchronously called. This method
 * should be supplied by subclassers to render updates as desired.
 */
class UpdatingElement extends HTMLElement {
    constructor() {
        super();
        this._updateState = 0;
        this._instanceProperties = undefined;
        this._updatePromise = microtaskPromise;
        this._hasConnectedResolver = undefined;
        /**
         * Map with keys for any properties that have changed since the last
         * update cycle with previous values.
         */
        this._changedProperties = new Map();
        /**
         * Map with keys of properties that should be reflected when updated.
         */
        this._reflectingProperties = undefined;
        this.initialize();
    }
    /**
     * Returns a list of attributes corresponding to the registered properties.
     * @nocollapse
     */
    static get observedAttributes() {
        // note: piggy backing on this to ensure we're finalized.
        this.finalize();
        const attributes = [];
        // Use forEach so this works even if for/of loops are compiled to for loops
        // expecting arrays
        this._classProperties.forEach((v, p) => {
            const attr = this._attributeNameForProperty(p, v);
            if (attr !== undefined) {
                this._attributeToPropertyMap.set(attr, p);
                attributes.push(attr);
            }
        });
        return attributes;
    }
    /**
     * Ensures the private `_classProperties` property metadata is created.
     * In addition to `finalize` this is also called in `createProperty` to
     * ensure the `@property` decorator can add property metadata.
     */
    /** @nocollapse */
    static _ensureClassProperties() {
        // ensure private storage for property declarations.
        if (!this.hasOwnProperty(JSCompiler_renameProperty('_classProperties', this))) {
            this._classProperties = new Map();
            // NOTE: Workaround IE11 not supporting Map constructor argument.
            const superProperties = Object.getPrototypeOf(this)._classProperties;
            if (superProperties !== undefined) {
                superProperties.forEach((v, k) => this._classProperties.set(k, v));
            }
        }
    }
    /**
     * Creates a property accessor on the element prototype if one does not exist.
     * The property setter calls the property's `hasChanged` property option
     * or uses a strict identity check to determine whether or not to request
     * an update.
     * @nocollapse
     */
    static createProperty(name, options = defaultPropertyDeclaration) {
        // Note, since this can be called by the `@property` decorator which
        // is called before `finalize`, we ensure storage exists for property
        // metadata.
        this._ensureClassProperties();
        this._classProperties.set(name, options);
        // Do not generate an accessor if the prototype already has one, since
        // it would be lost otherwise and that would never be the user's intention;
        // Instead, we expect users to call `requestUpdate` themselves from
        // user-defined accessors. Note that if the super has an accessor we will
        // still overwrite it
        if (options.noAccessor || this.prototype.hasOwnProperty(name)) {
            return;
        }
        const key = typeof name === 'symbol' ? Symbol() : `__${name}`;
        Object.defineProperty(this.prototype, name, {
            // tslint:disable-next-line:no-any no symbol in index
            get() {
                return this[key];
            },
            set(value) {
                const oldValue = this[name];
                this[key] = value;
                this._requestUpdate(name, oldValue);
            },
            configurable: true,
            enumerable: true
        });
    }
    /**
     * Creates property accessors for registered properties and ensures
     * any superclasses are also finalized.
     * @nocollapse
     */
    static finalize() {
        // finalize any superclasses
        const superCtor = Object.getPrototypeOf(this);
        if (!superCtor.hasOwnProperty(finalized)) {
            superCtor.finalize();
        }
        this[finalized] = true;
        this._ensureClassProperties();
        // initialize Map populated in observedAttributes
        this._attributeToPropertyMap = new Map();
        // make any properties
        // Note, only process "own" properties since this element will inherit
        // any properties defined on the superClass, and finalization ensures
        // the entire prototype chain is finalized.
        if (this.hasOwnProperty(JSCompiler_renameProperty('properties', this))) {
            const props = this.properties;
            // support symbols in properties (IE11 does not support this)
            const propKeys = [
                ...Object.getOwnPropertyNames(props),
                ...(typeof Object.getOwnPropertySymbols === 'function') ?
                    Object.getOwnPropertySymbols(props) :
                    []
            ];
            // This for/of is ok because propKeys is an array
            for (const p of propKeys) {
                // note, use of `any` is due to TypeSript lack of support for symbol in
                // index types
                // tslint:disable-next-line:no-any no symbol in index
                this.createProperty(p, props[p]);
            }
        }
    }
    /**
     * Returns the property name for the given attribute `name`.
     * @nocollapse
     */
    static _attributeNameForProperty(name, options) {
        const attribute = options.attribute;
        return attribute === false ?
            undefined :
            (typeof attribute === 'string' ?
                attribute :
                (typeof name === 'string' ? name.toLowerCase() : undefined));
    }
    /**
     * Returns true if a property should request an update.
     * Called when a property value is set and uses the `hasChanged`
     * option for the property if present or a strict identity check.
     * @nocollapse
     */
    static _valueHasChanged(value, old, hasChanged = notEqual) {
        return hasChanged(value, old);
    }
    /**
     * Returns the property value for the given attribute value.
     * Called via the `attributeChangedCallback` and uses the property's
     * `converter` or `converter.fromAttribute` property option.
     * @nocollapse
     */
    static _propertyValueFromAttribute(value, options) {
        const type = options.type;
        const converter = options.converter || defaultConverter;
        const fromAttribute = (typeof converter === 'function' ? converter : converter.fromAttribute);
        return fromAttribute ? fromAttribute(value, type) : value;
    }
    /**
     * Returns the attribute value for the given property value. If this
     * returns undefined, the property will *not* be reflected to an attribute.
     * If this returns null, the attribute will be removed, otherwise the
     * attribute will be set to the value.
     * This uses the property's `reflect` and `type.toAttribute` property options.
     * @nocollapse
     */
    static _propertyValueToAttribute(value, options) {
        if (options.reflect === undefined) {
            return;
        }
        const type = options.type;
        const converter = options.converter;
        const toAttribute = converter && converter.toAttribute ||
            defaultConverter.toAttribute;
        return toAttribute(value, type);
    }
    /**
     * Performs element initialization. By default captures any pre-set values for
     * registered properties.
     */
    initialize() {
        this._saveInstanceProperties();
        // ensures first update will be caught by an early access of
        // `updateComplete`
        this._requestUpdate();
    }
    /**
     * Fixes any properties set on the instance before upgrade time.
     * Otherwise these would shadow the accessor and break these properties.
     * The properties are stored in a Map which is played back after the
     * constructor runs. Note, on very old versions of Safari (<=9) or Chrome
     * (<=41), properties created for native platform properties like (`id` or
     * `name`) may not have default values set in the element constructor. On
     * these browsers native properties appear on instances and therefore their
     * default value will overwrite any element default (e.g. if the element sets
     * this.id = 'id' in the constructor, the 'id' will become '' since this is
     * the native platform default).
     */
    _saveInstanceProperties() {
        // Use forEach so this works even if for/of loops are compiled to for loops
        // expecting arrays
        this.constructor
            ._classProperties.forEach((_v, p) => {
            if (this.hasOwnProperty(p)) {
                const value = this[p];
                delete this[p];
                if (!this._instanceProperties) {
                    this._instanceProperties = new Map();
                }
                this._instanceProperties.set(p, value);
            }
        });
    }
    /**
     * Applies previously saved instance properties.
     */
    _applyInstanceProperties() {
        // Use forEach so this works even if for/of loops are compiled to for loops
        // expecting arrays
        // tslint:disable-next-line:no-any
        this._instanceProperties.forEach((v, p) => this[p] = v);
        this._instanceProperties = undefined;
    }
    connectedCallback() {
        this._updateState = this._updateState | STATE_HAS_CONNECTED;
        // Ensure first connection completes an update. Updates cannot complete
        // before connection and if one is pending connection the
        // `_hasConnectionResolver` will exist. If so, resolve it to complete the
        // update, otherwise requestUpdate.
        if (this._hasConnectedResolver) {
            this._hasConnectedResolver();
            this._hasConnectedResolver = undefined;
        }
    }
    /**
     * Allows for `super.disconnectedCallback()` in extensions while
     * reserving the possibility of making non-breaking feature additions
     * when disconnecting at some point in the future.
     */
    disconnectedCallback() {
    }
    /**
     * Synchronizes property values when attributes change.
     */
    attributeChangedCallback(name, old, value) {
        if (old !== value) {
            this._attributeToProperty(name, value);
        }
    }
    _propertyToAttribute(name, value, options = defaultPropertyDeclaration) {
        const ctor = this.constructor;
        const attr = ctor._attributeNameForProperty(name, options);
        if (attr !== undefined) {
            const attrValue = ctor._propertyValueToAttribute(value, options);
            // an undefined value does not change the attribute.
            if (attrValue === undefined) {
                return;
            }
            // Track if the property is being reflected to avoid
            // setting the property again via `attributeChangedCallback`. Note:
            // 1. this takes advantage of the fact that the callback is synchronous.
            // 2. will behave incorrectly if multiple attributes are in the reaction
            // stack at time of calling. However, since we process attributes
            // in `update` this should not be possible (or an extreme corner case
            // that we'd like to discover).
            // mark state reflecting
            this._updateState = this._updateState | STATE_IS_REFLECTING_TO_ATTRIBUTE;
            if (attrValue == null) {
                this.removeAttribute(attr);
            }
            else {
                this.setAttribute(attr, attrValue);
            }
            // mark state not reflecting
            this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_ATTRIBUTE;
        }
    }
    _attributeToProperty(name, value) {
        // Use tracking info to avoid deserializing attribute value if it was
        // just set from a property setter.
        if (this._updateState & STATE_IS_REFLECTING_TO_ATTRIBUTE) {
            return;
        }
        const ctor = this.constructor;
        const propName = ctor._attributeToPropertyMap.get(name);
        if (propName !== undefined) {
            const options = ctor._classProperties.get(propName) || defaultPropertyDeclaration;
            // mark state reflecting
            this._updateState = this._updateState | STATE_IS_REFLECTING_TO_PROPERTY;
            this[propName] =
                // tslint:disable-next-line:no-any
                ctor._propertyValueFromAttribute(value, options);
            // mark state not reflecting
            this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_PROPERTY;
        }
    }
    /**
     * This private version of `requestUpdate` does not access or return the
     * `updateComplete` promise. This promise can be overridden and is therefore
     * not free to access.
     */
    _requestUpdate(name, oldValue) {
        let shouldRequestUpdate = true;
        // If we have a property key, perform property update steps.
        if (name !== undefined) {
            const ctor = this.constructor;
            const options = ctor._classProperties.get(name) || defaultPropertyDeclaration;
            if (ctor._valueHasChanged(this[name], oldValue, options.hasChanged)) {
                if (!this._changedProperties.has(name)) {
                    this._changedProperties.set(name, oldValue);
                }
                // Add to reflecting properties set.
                // Note, it's important that every change has a chance to add the
                // property to `_reflectingProperties`. This ensures setting
                // attribute + property reflects correctly.
                if (options.reflect === true &&
                    !(this._updateState & STATE_IS_REFLECTING_TO_PROPERTY)) {
                    if (this._reflectingProperties === undefined) {
                        this._reflectingProperties = new Map();
                    }
                    this._reflectingProperties.set(name, options);
                }
            }
            else {
                // Abort the request if the property should not be considered changed.
                shouldRequestUpdate = false;
            }
        }
        if (!this._hasRequestedUpdate && shouldRequestUpdate) {
            this._enqueueUpdate();
        }
    }
    /**
     * Requests an update which is processed asynchronously. This should
     * be called when an element should update based on some state not triggered
     * by setting a property. In this case, pass no arguments. It should also be
     * called when manually implementing a property setter. In this case, pass the
     * property `name` and `oldValue` to ensure that any configured property
     * options are honored. Returns the `updateComplete` Promise which is resolved
     * when the update completes.
     *
     * @param name {PropertyKey} (optional) name of requesting property
     * @param oldValue {any} (optional) old value of requesting property
     * @returns {Promise} A Promise that is resolved when the update completes.
     */
    requestUpdate(name, oldValue) {
        this._requestUpdate(name, oldValue);
        return this.updateComplete;
    }
    /**
     * Sets up the element to asynchronously update.
     */
    async _enqueueUpdate() {
        // Mark state updating...
        this._updateState = this._updateState | STATE_UPDATE_REQUESTED;
        let resolve;
        let reject;
        const previousUpdatePromise = this._updatePromise;
        this._updatePromise = new Promise((res, rej) => {
            resolve = res;
            reject = rej;
        });
        try {
            // Ensure any previous update has resolved before updating.
            // This `await` also ensures that property changes are batched.
            await previousUpdatePromise;
        }
        catch (e) {
            // Ignore any previous errors. We only care that the previous cycle is
            // done. Any error should have been handled in the previous update.
        }
        // Make sure the element has connected before updating.
        if (!this._hasConnected) {
            await new Promise((res) => this._hasConnectedResolver = res);
        }
        try {
            const result = this.performUpdate();
            // If `performUpdate` returns a Promise, we await it. This is done to
            // enable coordinating updates with a scheduler. Note, the result is
            // checked to avoid delaying an additional microtask unless we need to.
            if (result != null) {
                await result;
            }
        }
        catch (e) {
            reject(e);
        }
        resolve(!this._hasRequestedUpdate);
    }
    get _hasConnected() {
        return (this._updateState & STATE_HAS_CONNECTED);
    }
    get _hasRequestedUpdate() {
        return (this._updateState & STATE_UPDATE_REQUESTED);
    }
    get hasUpdated() {
        return (this._updateState & STATE_HAS_UPDATED);
    }
    /**
     * Performs an element update. Note, if an exception is thrown during the
     * update, `firstUpdated` and `updated` will not be called.
     *
     * You can override this method to change the timing of updates. If this
     * method is overridden, `super.performUpdate()` must be called.
     *
     * For instance, to schedule updates to occur just before the next frame:
     *
     * ```
     * protected async performUpdate(): Promise<unknown> {
     *   await new Promise((resolve) => requestAnimationFrame(() => resolve()));
     *   super.performUpdate();
     * }
     * ```
     */
    performUpdate() {
        // Mixin instance properties once, if they exist.
        if (this._instanceProperties) {
            this._applyInstanceProperties();
        }
        let shouldUpdate = false;
        const changedProperties = this._changedProperties;
        try {
            shouldUpdate = this.shouldUpdate(changedProperties);
            if (shouldUpdate) {
                this.update(changedProperties);
            }
        }
        catch (e) {
            // Prevent `firstUpdated` and `updated` from running when there's an
            // update exception.
            shouldUpdate = false;
            throw e;
        }
        finally {
            // Ensure element can accept additional updates after an exception.
            this._markUpdated();
        }
        if (shouldUpdate) {
            if (!(this._updateState & STATE_HAS_UPDATED)) {
                this._updateState = this._updateState | STATE_HAS_UPDATED;
                this.firstUpdated(changedProperties);
            }
            this.updated(changedProperties);
        }
    }
    _markUpdated() {
        this._changedProperties = new Map();
        this._updateState = this._updateState & ~STATE_UPDATE_REQUESTED;
    }
    /**
     * Returns a Promise that resolves when the element has completed updating.
     * The Promise value is a boolean that is `true` if the element completed the
     * update without triggering another update. The Promise result is `false` if
     * a property was set inside `updated()`. If the Promise is rejected, an
     * exception was thrown during the update.
     *
     * To await additional asynchronous work, override the `_getUpdateComplete`
     * method. For example, it is sometimes useful to await a rendered element
     * before fulfilling this Promise. To do this, first await
     * `super._getUpdateComplete()`, then any subsequent state.
     *
     * @returns {Promise} The Promise returns a boolean that indicates if the
     * update resolved without triggering another update.
     */
    get updateComplete() {
        return this._getUpdateComplete();
    }
    /**
     * Override point for the `updateComplete` promise.
     *
     * It is not safe to override the `updateComplete` getter directly due to a
     * limitation in TypeScript which means it is not possible to call a
     * superclass getter (e.g. `super.updateComplete.then(...)`) when the target
     * language is ES5 (https://github.com/microsoft/TypeScript/issues/338).
     * This method should be overridden instead. For example:
     *
     *   class MyElement extends LitElement {
     *     async _getUpdateComplete() {
     *       await super._getUpdateComplete();
     *       await this._myChild.updateComplete;
     *     }
     *   }
     */
    _getUpdateComplete() {
        return this._updatePromise;
    }
    /**
     * Controls whether or not `update` should be called when the element requests
     * an update. By default, this method always returns `true`, but this can be
     * customized to control when to update.
     *
     * * @param _changedProperties Map of changed properties with old values
     */
    shouldUpdate(_changedProperties) {
        return true;
    }
    /**
     * Updates the element. This method reflects property values to attributes.
     * It can be overridden to render and keep updated element DOM.
     * Setting properties inside this method will *not* trigger
     * another update.
     *
     * * @param _changedProperties Map of changed properties with old values
     */
    update(_changedProperties) {
        if (this._reflectingProperties !== undefined &&
            this._reflectingProperties.size > 0) {
            // Use forEach so this works even if for/of loops are compiled to for
            // loops expecting arrays
            this._reflectingProperties.forEach((v, k) => this._propertyToAttribute(k, this[k], v));
            this._reflectingProperties = undefined;
        }
    }
    /**
     * Invoked whenever the element is updated. Implement to perform
     * post-updating tasks via DOM APIs, for example, focusing an element.
     *
     * Setting properties inside this method will trigger the element to update
     * again after this update cycle completes.
     *
     * * @param _changedProperties Map of changed properties with old values
     */
    updated(_changedProperties) {
    }
    /**
     * Invoked when the element is first updated. Implement to perform one time
     * work on the element after update.
     *
     * Setting properties inside this method will trigger the element to update
     * again after this update cycle completes.
     *
     * * @param _changedProperties Map of changed properties with old values
     */
    firstUpdated(_changedProperties) {
    }
}
_a = finalized;
/**
 * Marks class as having finished creating properties.
 */
UpdatingElement[_a] = true;

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
const legacyCustomElement = (tagName, clazz) => {
    window.customElements.define(tagName, clazz);
    // Cast as any because TS doesn't recognize the return type as being a
    // subtype of the decorated class when clazz is typed as
    // `Constructor<HTMLElement>` for some reason.
    // `Constructor<HTMLElement>` is helpful to make sure the decorator is
    // applied to elements however.
    // tslint:disable-next-line:no-any
    return clazz;
};
const standardCustomElement = (tagName, descriptor) => {
    const { kind, elements } = descriptor;
    return {
        kind,
        elements,
        // This callback is called once the class is otherwise fully defined
        finisher(clazz) {
            window.customElements.define(tagName, clazz);
        }
    };
};
/**
 * Class decorator factory that defines the decorated class as a custom element.
 *
 * @param tagName the name of the custom element to define
 */
const customElement = (tagName) => (classOrDescriptor) => (typeof classOrDescriptor === 'function') ?
    legacyCustomElement(tagName, classOrDescriptor) :
    standardCustomElement(tagName, classOrDescriptor);
const standardProperty = (options, element) => {
    // When decorating an accessor, pass it through and add property metadata.
    // Note, the `hasOwnProperty` check in `createProperty` ensures we don't
    // stomp over the user's accessor.
    if (element.kind === 'method' && element.descriptor &&
        !('value' in element.descriptor)) {
        return Object.assign({}, element, { finisher(clazz) {
                clazz.createProperty(element.key, options);
            } });
    }
    else {
        // createProperty() takes care of defining the property, but we still
        // must return some kind of descriptor, so return a descriptor for an
        // unused prototype field. The finisher calls createProperty().
        return {
            kind: 'field',
            key: Symbol(),
            placement: 'own',
            descriptor: {},
            // When @babel/plugin-proposal-decorators implements initializers,
            // do this instead of the initializer below. See:
            // https://github.com/babel/babel/issues/9260 extras: [
            //   {
            //     kind: 'initializer',
            //     placement: 'own',
            //     initializer: descriptor.initializer,
            //   }
            // ],
            initializer() {
                if (typeof element.initializer === 'function') {
                    this[element.key] = element.initializer.call(this);
                }
            },
            finisher(clazz) {
                clazz.createProperty(element.key, options);
            }
        };
    }
};
const legacyProperty = (options, proto, name) => {
    proto.constructor
        .createProperty(name, options);
};
/**
 * A property decorator which creates a LitElement property which reflects a
 * corresponding attribute value. A `PropertyDeclaration` may optionally be
 * supplied to configure property features.
 *
 * @ExportDecoratedItems
 */
function property(options) {
    // tslint:disable-next-line:no-any decorator
    return (protoOrDescriptor, name) => (name !== undefined) ?
        legacyProperty(options, protoOrDescriptor, name) :
        standardProperty(options, protoOrDescriptor);
}

/**
@license
Copyright (c) 2019 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
part of the polymer project is also subject to an additional IP rights grant
found at http://polymer.github.io/PATENTS.txt
*/
const supportsAdoptingStyleSheets = ('adoptedStyleSheets' in Document.prototype) &&
    ('replace' in CSSStyleSheet.prototype);
const constructionToken = Symbol();
class CSSResult {
    constructor(cssText, safeToken) {
        if (safeToken !== constructionToken) {
            throw new Error('CSSResult is not constructable. Use `unsafeCSS` or `css` instead.');
        }
        this.cssText = cssText;
    }
    // Note, this is a getter so that it's lazy. In practice, this means
    // stylesheets are not created until the first element instance is made.
    get styleSheet() {
        if (this._styleSheet === undefined) {
            // Note, if `adoptedStyleSheets` is supported then we assume CSSStyleSheet
            // is constructable.
            if (supportsAdoptingStyleSheets) {
                this._styleSheet = new CSSStyleSheet();
                this._styleSheet.replaceSync(this.cssText);
            }
            else {
                this._styleSheet = null;
            }
        }
        return this._styleSheet;
    }
    toString() {
        return this.cssText;
    }
}
const textFromCSSResult = (value) => {
    if (value instanceof CSSResult) {
        return value.cssText;
    }
    else if (typeof value === 'number') {
        return value;
    }
    else {
        throw new Error(`Value passed to 'css' function must be a 'css' function result: ${value}. Use 'unsafeCSS' to pass non-literal values, but
            take care to ensure page security.`);
    }
};
/**
 * Template tag which which can be used with LitElement's `style` property to
 * set element styles. For security reasons, only literal string values may be
 * used. To incorporate non-literal values `unsafeCSS` may be used inside a
 * template string part.
 */
const css = (strings, ...values) => {
    const cssText = values.reduce((acc, v, idx) => acc + textFromCSSResult(v) + strings[idx + 1], strings[0]);
    return new CSSResult(cssText, constructionToken);
};

/**
 * @license
 * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at
 * http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at
 * http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
// IMPORTANT: do not change the property name or the assignment expression.
// This line will be used in regexes to search for LitElement usage.
// TODO(justinfagnani): inject version number at build time
(window['litElementVersions'] || (window['litElementVersions'] = []))
    .push('2.2.1');
/**
 * Minimal implementation of Array.prototype.flat
 * @param arr the array to flatten
 * @param result the accumlated result
 */
function arrayFlat(styles, result = []) {
    for (let i = 0, length = styles.length; i < length; i++) {
        const value = styles[i];
        if (Array.isArray(value)) {
            arrayFlat(value, result);
        }
        else {
            result.push(value);
        }
    }
    return result;
}
/** Deeply flattens styles array. Uses native flat if available. */
const flattenStyles = (styles) => styles.flat ? styles.flat(Infinity) : arrayFlat(styles);
class LitElement extends UpdatingElement {
    /** @nocollapse */
    static finalize() {
        // The Closure JS Compiler does not always preserve the correct "this"
        // when calling static super methods (b/137460243), so explicitly bind.
        super.finalize.call(this);
        // Prepare styling that is stamped at first render time. Styling
        // is built from user provided `styles` or is inherited from the superclass.
        this._styles =
            this.hasOwnProperty(JSCompiler_renameProperty('styles', this)) ?
                this._getUniqueStyles() :
                this._styles || [];
    }
    /** @nocollapse */
    static _getUniqueStyles() {
        // Take care not to call `this.styles` multiple times since this generates
        // new CSSResults each time.
        // TODO(sorvell): Since we do not cache CSSResults by input, any
        // shared styles will generate new stylesheet objects, which is wasteful.
        // This should be addressed when a browser ships constructable
        // stylesheets.
        const userStyles = this.styles;
        const styles = [];
        if (Array.isArray(userStyles)) {
            const flatStyles = flattenStyles(userStyles);
            // As a performance optimization to avoid duplicated styling that can
            // occur especially when composing via subclassing, de-duplicate styles
            // preserving the last item in the list. The last item is kept to
            // try to preserve cascade order with the assumption that it's most
            // important that last added styles override previous styles.
            const styleSet = flatStyles.reduceRight((set, s) => {
                set.add(s);
                // on IE set.add does not return the set.
                return set;
            }, new Set());
            // Array.from does not work on Set in IE
            styleSet.forEach((v) => styles.unshift(v));
        }
        else if (userStyles) {
            styles.push(userStyles);
        }
        return styles;
    }
    /**
     * Performs element initialization. By default this calls `createRenderRoot`
     * to create the element `renderRoot` node and captures any pre-set values for
     * registered properties.
     */
    initialize() {
        super.initialize();
        this.renderRoot =
            this.createRenderRoot();
        // Note, if renderRoot is not a shadowRoot, styles would/could apply to the
        // element's getRootNode(). While this could be done, we're choosing not to
        // support this now since it would require different logic around de-duping.
        if (window.ShadowRoot && this.renderRoot instanceof window.ShadowRoot) {
            this.adoptStyles();
        }
    }
    /**
     * Returns the node into which the element should render and by default
     * creates and returns an open shadowRoot. Implement to customize where the
     * element's DOM is rendered. For example, to render into the element's
     * childNodes, return `this`.
     * @returns {Element|DocumentFragment} Returns a node into which to render.
     */
    createRenderRoot() {
        return this.attachShadow({ mode: 'open' });
    }
    /**
     * Applies styling to the element shadowRoot using the `static get styles`
     * property. Styling will apply using `shadowRoot.adoptedStyleSheets` where
     * available and will fallback otherwise. When Shadow DOM is polyfilled,
     * ShadyCSS scopes styles and adds them to the document. When Shadow DOM
     * is available but `adoptedStyleSheets` is not, styles are appended to the
     * end of the `shadowRoot` to [mimic spec
     * behavior](https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets).
     */
    adoptStyles() {
        const styles = this.constructor._styles;
        if (styles.length === 0) {
            return;
        }
        // There are three separate cases here based on Shadow DOM support.
        // (1) shadowRoot polyfilled: use ShadyCSS
        // (2) shadowRoot.adoptedStyleSheets available: use it.
        // (3) shadowRoot.adoptedStyleSheets polyfilled: append styles after
        // rendering
        if (window.ShadyCSS !== undefined && !window.ShadyCSS.nativeShadow) {
            window.ShadyCSS.ScopingShim.prepareAdoptedCssText(styles.map((s) => s.cssText), this.localName);
        }
        else if (supportsAdoptingStyleSheets) {
            this.renderRoot.adoptedStyleSheets =
                styles.map((s) => s.styleSheet);
        }
        else {
            // This must be done after rendering so the actual style insertion is done
            // in `update`.
            this._needsShimAdoptedStyleSheets = true;
        }
    }
    connectedCallback() {
        super.connectedCallback();
        // Note, first update/render handles styleElement so we only call this if
        // connected after first update.
        if (this.hasUpdated && window.ShadyCSS !== undefined) {
            window.ShadyCSS.styleElement(this);
        }
    }
    /**
     * Updates the element. This method reflects property values to attributes
     * and calls `render` to render DOM via lit-html. Setting properties inside
     * this method will *not* trigger another update.
     * * @param _changedProperties Map of changed properties with old values
     */
    update(changedProperties) {
        super.update(changedProperties);
        const templateResult = this.render();
        if (templateResult instanceof TemplateResult) {
            this.constructor
                .render(templateResult, this.renderRoot, { scopeName: this.localName, eventContext: this });
        }
        // When native Shadow DOM is used but adoptedStyles are not supported,
        // insert styling after rendering to ensure adoptedStyles have highest
        // priority.
        if (this._needsShimAdoptedStyleSheets) {
            this._needsShimAdoptedStyleSheets = false;
            this.constructor._styles.forEach((s) => {
                const style = document.createElement('style');
                style.textContent = s.cssText;
                this.renderRoot.appendChild(style);
            });
        }
    }
    /**
     * Invoked on each update to perform rendering tasks. This method must return
     * a lit-html TemplateResult. Setting properties inside this method will *not*
     * trigger the element to update.
     */
    render() {
    }
}
/**
 * Ensure this class is marked as `finalized` as an optimization ensuring
 * it will not needlessly try to `finalize`.
 *
 * Note this property name is a string to prevent breaking Closure JS Compiler
 * optimizations. See updating-element.ts for more information.
 */
LitElement['finalized'] = true;
/**
 * Render method used to render the lit-html TemplateResult to the element's
 * DOM.
 * @param {TemplateResult} Template to render.
 * @param {Element|DocumentFragment} Node into which to render.
 * @param {String} Element name.
 * @nocollapse
 */
LitElement.render = render$1;

function hass() {
  return document.querySelector('home-assistant').hass
}
function load_lovelace() {
  if(customElements.get("hui-view")) return true;

  const res = document.createElement("partial-panel-resolver");
  res.hass = hass();
  res.route = {path: "/lovelace/"};
  // res._updateRoutes();
  try {
    document.querySelector("home-assistant").appendChild(res).catch((error) => {});
  } catch (error) {
    document.querySelector("home-assistant").removeChild(res);
  }
  if(customElements.get("hui-view")) return true;
  return false;

}

const navigate = (_node, path) => {
    history.pushState(null, "", path);
};

/**
 * Scroll to a specific y coordinate.
 *
 * Copied from paper-scroll-header-panel.
 *
 * @method scroll
 * @param {number} top The coordinate to scroll to, along the y-axis.
 * @param {boolean} smooth true if the scroll position should be smoothly adjusted.
 */
function scrollToTarget(element, target) {
    // the scroll event will trigger _updateScrollState directly,
    // However, _updateScrollState relies on the previous `scrollTop` to update the states.
    // Calling _updateScrollState will ensure that the states are synced correctly.
    const top = 0;
    const scroller = target;
    const easingFn = function easeOutQuad(t, b, c, d) {
        /* eslint-disable no-param-reassign, space-infix-ops, no-mixed-operators */
        t /= d;
        return -c * t * (t - 2) + b;
        /* eslint-enable no-param-reassign, space-infix-ops, no-mixed-operators */
    };
    const animationId = Math.random();
    const duration = 200;
    const startTime = Date.now();
    const currentScrollTop = scroller.scrollTop;
    const deltaScrollTop = top - currentScrollTop;
    element._currentAnimationId = animationId;
    (function updateFrame() {
        const now = Date.now();
        const elapsedTime = now - startTime;
        if (elapsedTime > duration) {
            scroller.scrollTop = top;
        }
        else if (element._currentAnimationId === animationId) {
            scroller.scrollTop = easingFn(elapsedTime, currentScrollTop, deltaScrollTop, duration);
            requestAnimationFrame(updateFrame.bind(element));
        }
    }.call(element));
}

const haStyle = css `
    :host {
      @apply --paper-font-body1;
    }

    app-header-layout,
    ha-app-layout {
      background-color: var(--primary-background-color);
    }

    app-header, app-toolbar {
      background-color: var(--primary-color);
      font-weight: 400;
      color: var(--text-primary-color, white);
    }

    app-toolbar ha-menu-button + [main-title],
    app-toolbar ha-paper-icon-button-arrow-prev + [main-title],
    app-toolbar paper-icon-button + [main-title] {
      margin-left: 24px;
    }

    button.link {
      background: none;
      color: inherit;
      border: none;
      padding: 0;
      font: inherit;
      text-align: left;
      text-decoration: underline;
      cursor: pointer;
    }

    .card-actions a {
      text-decoration: none;
    }

    .card-actions .warning {
      --mdc-theme-primary: var(--google-red-500);
    }
`;

const navStyle = css `
    :host {
      font-family: var(--paper-font-body1_-_font-family);
      -webkit-font-smoothing: var(--paper-font-body1_-_-webkit-font-smoothing);
      font-size: var(--paper-font-body1_-_font-size);
      font-weight: var(--paper-font-body1_-_font-weight);
      line-height: var(--paper-font-body1_-_line-height);
    }

    app-header-layout, ha-app-layout {
      background-color: var(--primary-background-color);
    }

    app-header, app-toolbar, paper-tabs {
      background-color: var(--primary-color);
      font-weight: 400;
      text-transform: uppercase;
      color: var(--text-primary-color, white);
    }

    paper-tabs {
      --paper-tabs-selection-bar-color: #fff;
      margin-left: 12px;
    }

    app-toolbar ha-menu-button + [main-title], app-toolbar ha-paper-icon-button-arrow-prev + [main-title], app-toolbar paper-icon-button + [main-title] {
      margin-left: 24px;
    }
`;

const baseHacsStyles = css `
    :root {
        font-family: var(--paper-font-body1_-_font-family);
        -webkit-font-smoothing: var(--paper-font-body1_-_-webkit-font-smoothing);
        font-size: var(--paper-font-body1_-_font-size);
        font-weight: var(--paper-font-body1_-_font-weight);
        line-height: var(--paper-font-body1_-_line-height);
    }
    :host {
        --hacs-status-installed: #126e15;
        --hacs-status-pending-update: #ffab40;
        --hacs-status-pending-restart: var(--google-red-500);
        --hacs-status-not-loaded: var(--google-red-500);
        --hacs-badge-color: var(--primary-color);
        --link-color: var(--primary-color);
    }
    a {
        text-decoration: none;
        color: var(--dark-primary-color);
    }
    h1 {
        font-family: var(--paper-font-title_-_font-family);
        -webkit-font-smoothing: var(--paper-font-title_-_-webkit-font-smoothing);
        white-space: var(--paper-font-title_-_white-space);
        overflow: var(--paper-font-title_-_overflow);
        text-overflow: var(--paper-font-title_-_text-overflow);
        font-size: var(--paper-font-title_-_font-size);
        font-weight: var(--paper-font-title_-_font-weight);
        line-height: var(--paper-font-title_-_line-height);
        @apply --paper-font-title;
    }
    .title {
        margin-bottom: 16px;
        padding-top: 4px;
        color: var(--primary-text-color);
        white-space: nowrap;
        text-overflow: ellipsis;
        overflow: hidden;
    }
    .addition {
        color: var(--secondary-text-color);
        position: relative;
        height: auto;
        line-height: 1.2em;
        text-overflow: ellipsis;
        overflow: hidden;
    }
    paper-card {
        cursor: pointer;
    }
    ha-card {
      margin: 8px;
    }
    ha-icon {
        height: 24px;
        width: 24px;
        margin-right: 16px;
        float: left;
        color: var(--primary-text-color);
    }
    ha-icon.installed {
        color: var(--hacs-status-installed);
    }
    ha-icon.pending-upgrade {
        color: var(--hacs-status-pending-update);
    }
    ha-icon.pending-restart {
        color: var(--hacs-status-pending-restart);
    }
    ha-icon.not-loaded {
        color: var(--hacs-status-not-loaded);
    }
    ha-icon.new {
        color: var(--hacs-badge-color);
      }
`;
const mobileHacsStyles = css `
    @media screen and (max-width: 600px) and (min-width: 0) {
      .MobileHide {
          display: none !important;
      }
      .MobileGrid {
          display: grid !important;
          text-align: center !important;
          position: initial !important;
          width: 100% !important;
          padding-left: 0px !important;
          padding-right: 0px !important;
      }
      hacs-help-button {
          display: none;
      }
    }
`;
const HacsStyle = [haStyle, navStyle, baseHacsStyles, mobileHacsStyles];

let HacsHelpButton = class HacsHelpButton extends LitElement {
    render() {
        return html `
        <a href="#">
            <ha-icon
                title="Documentation"
                class="float"
                icon="mdi:help"
                @click=${this.openHelp}>
            </ha-icon>
        </a>
        `;
    }
    openHelp() {
        const base = "https://hacs.xyz/docs/navigation/";
        var location = window.location.pathname.split("/")[2];
        if (location === "integration")
            location = "stores";
        if (location === "plugin")
            location = "stores";
        if (location === "appdaemon")
            location = "stores";
        if (location === "python_script")
            location = "stores";
        if (location === "theme")
            location = "stores";
        window.open(`${base}${location}`, "Help", "noreferrer");
    }
    static get styles() {
        return [HacsStyle, css `
            .float{
                position: fixed;
                width: 36px;
                height:36px;
                bottom: 24px;
                right: 24px;
                border-radius: 50px;
                border: 4px solid var(--accent-color);
                text-align: center;
                color: var(--paper-card-background-color, var(--primary-background-color));
                background-color: var(--accent-color);
            }
        `];
    }
};
HacsHelpButton = __decorate([
    customElement("hacs-help-button")
], HacsHelpButton);

function AddedToLovelace(repository, lovelaceconfig, status) {
    if (status.lovelace_mode === "yaml")
        return true;
    if (lovelaceconfig !== undefined) {
        var loaded = false;
        var URL = `/community_plugin/${repository.full_name.split("/")[1]}/${repository.file_name}`;
        if (lovelaceconfig.resources !== undefined) {
            lovelaceconfig.resources.forEach((item) => {
                if (!loaded) {
                    if (item.url === URL)
                        loaded = true;
                }
            });
        }
        return loaded;
    }
    else
        return true;
}

class HacsRepositoryButton extends LitElement {
    static get styles() {
        return HacsStyle;
    }
}
__decorate([
    property()
], HacsRepositoryButton.prototype, "hass", void 0);
__decorate([
    property()
], HacsRepositoryButton.prototype, "repository", void 0);
__decorate([
    property()
], HacsRepositoryButton.prototype, "status", void 0);

let HacsButtonClearNew = class HacsButtonClearNew extends HacsRepositoryButton {
    render() {
        return html `
            <mwc-button @click=${this.ExecuteAction}>
                ${this.hass.localize(`component.hacs.store.clear_new`)}
            </mwc-button>
        `;
    }
    ExecuteAction() {
        var message = {
            type: "hacs/settings",
            action: "clear_new",
            category: this.category
        };
        this.hass.connection.sendMessage(message);
    }
};
__decorate([
    property()
], HacsButtonClearNew.prototype, "category", void 0);
HacsButtonClearNew = __decorate([
    customElement("hacs-button-clear-new")
], HacsButtonClearNew);

let HacsPanelStore = class HacsPanelStore extends LitElement {
    constructor() {
        super(...arguments);
        this.repository_view = false;
        this.SortKey = "name";
        this.SearchTerm = "";
    }
    render() {
        if (this.panel === "repository") {
            // How fun, this is a repository!
            return html `
      <hacs-panel-repository
        .hass=${this.hass}
        .route=${this.route}
        .status=${this.status}
        .configuration=${this.configuration}
        .repositories=${this.repositories}
        .repository=${this.repository}
        .lovelaceconfig=${this.lovelaceconfig}
      >
      </hacs-panel-repository>`;
        }
        else {
            const category = this.panel;
            var newRepositories = [];
            const config = this.configuration;
            this.SearchTerm = localStorage.getItem("hacs-search");
            var SearchTerm = this.SearchTerm;
            var _repositories = this.repositories.filter(function (repo) {
                if (category !== "installed") {
                    // Hide HACS from the store
                    if (repo.id === "172733314")
                        return false;
                    // Hide hidden repos from the store
                    if (repo.hide)
                        return false;
                    // Check contry restrictions
                    if (config.country !== "ALL" && repo.country !== undefined) {
                        if (config.country !== repo.country)
                            return false;
                    }
                }
                else {
                    if (repo.installed)
                        return true;
                }
                if (repo.category === category) {
                    if (SearchTerm !== "" || null) {
                        if (repo.name.toLowerCase().includes(SearchTerm))
                            return true;
                        if (repo.description.toLowerCase().includes(SearchTerm))
                            return true;
                        if (repo.full_name.toLowerCase().includes(SearchTerm))
                            return true;
                        if (String(repo.authors).toLowerCase().includes(SearchTerm))
                            return true;
                        if (String(repo.topics).toLowerCase().includes(SearchTerm))
                            return true;
                        return false;
                    }
                    if (repo.new)
                        newRepositories.push(repo);
                    // Fallback to not showing it if no search.
                    return true;
                }
                // Fallback to not showing it.
                return false;
            });
            return html `
      <div class="store-top store-top-${this.panel}">
        <paper-input
          class="search-bar"
          type="text"
          id="Search"
          @input=${this.DoSearch}
          placeholder="  ${this.hass.localize("component.hacs.store.placeholder_search")}."
          autofocus
          .value=${this.SearchTerm}
        >
          ${(this.SearchTerm.length > 0 ? html `
            <ha-icon slot="suffix" icon="mdi:close" @click="${this.clearSearch}"></ha-icon>
          ` : "")}
        </paper-input>
        <paper-dropdown-menu @value-changed="${this.SetSortKey}" class="sort" label="Sort">
          <paper-listbox slot="dropdown-content" selected="0">
            <paper-item>Name</paper-item>
            <paper-item>Status</paper-item>
          </paper-listbox>
        </paper-dropdown-menu>
        </div>

    ${(newRepositories.length !== 0 ? html `
    <div class="card-group">
      <h1>${this.hass.localize(`component.hacs.store.new_repositories`)}</h1>
      ${newRepositories.sort((a, b) => (this.SortRepo(a, b)) ? 1 : -1).map(repo => html `
          ${(this.configuration.frontend_mode !== "Table" ? html `
          <paper-card @click="${this.ShowRepository}" .RepoID="${repo.id}"
            class="${(this.configuration.frontend_compact ? "compact" : "")}">
          <div class="card-content">
            <div>
              <ha-icon
                icon="mdi:new-box"
                class="${this.StatusAndDescription(repo).status}"
                title="${this.StatusAndDescription(repo).description}"
                >
              </ha-icon>
              <div>
                <div class="title">${repo.name}</div>
                <div class="addition">${repo.description}</div>
              </div>
            </div>
          </div>
          </paper-card>

        ` : html `

        <paper-item .RepoID=${repo.id} @click="${this.ShowRepository}"
          class="${(this.configuration.frontend_compact ? "compact" : "")}">
          <div class="icon">
            <ha-icon
              icon="mdi:new-box"
              class="${this.StatusAndDescription(repo).status}"
              title="${this.StatusAndDescription(repo).description}"
          </ha-icon>
          </div>
          <paper-item-body two-line>
            <div>${repo.name}</div>
            <div class="addition">${repo.description}</div>
          </paper-item-body>
        </paper-item>
        `)}
      `)}
    </div>
    <div class="card-group">
      <hacs-button-clear-new .hass=${this.hass} .category=${category}></hacs-button-clear-new>
    </div>
    <hr>
    ` : "")}

    <div class="card-group">
    ${_repositories.sort((a, b) => (this.SortRepo(a, b)) ? 1 : -1).map(repo => html `

      ${(this.configuration.frontend_mode !== "Table" ? html `
        <paper-card @click="${this.ShowRepository}" .RepoID="${repo.id}"
          class="${(this.configuration.frontend_compact ? "compact" : "")}">
        <div class="card-content">
          <div>
            <ha-icon
              icon=${(repo.new ? "mdi:new-box" : "mdi:cube")}
              class="${this.StatusAndDescription(repo).status}"
              title="${this.StatusAndDescription(repo).description}"
              >
            </ha-icon>
            <div>
              <div class="title">${repo.name}</div>
              <div class="addition">${repo.description}</div>
            </div>
          </div>
        </div>
        </paper-card>

      ` : html `

      <paper-item .RepoID=${repo.id} @click="${this.ShowRepository}"
        class="${(this.configuration.frontend_compact ? "compact" : "")}">
        <div class="icon">
          <ha-icon
            icon=${(repo.new ? "mdi:new-box" : "mdi:cube")}
            class="${this.StatusAndDescription(repo).status}"
            title="${this.StatusAndDescription(repo).description}"
        </ha-icon>
        </div>
        <paper-item-body two-line>
          <div>${repo.name}</div>
          <div class="addition">${repo.description}</div>
        </paper-item-body>
      </paper-item>
      `)}


      `)}
    </div>`;
        }
    }
    SortRepo(a, b) {
        if (this.SortKey === "stars")
            return a.stars < b.stars;
        if (this.SortKey === "status")
            return a.status < b.status;
        return a[this.SortKey] > b[this.SortKey];
    }
    SetSortKey(ev) {
        if (ev.detail.value.length === 0)
            return;
        this.SortKey = ev.detail.value.replace(" ", "_").toLowerCase();
    }
    StatusAndDescription(repository) {
        var status = repository.status;
        var description = repository.status_description;
        if (repository.installed && !this.status.background_task) {
            if (repository.category === "plugin" && !AddedToLovelace(repository, this.lovelaceconfig, this.status)) {
                status = "not-loaded";
                description = "Not loaded in lovelace";
            }
        }
        return { status: status, description: description };
    }
    DoSearch(ev) {
        this.SearchTerm = ev.composedPath()[0].value.toLowerCase();
        localStorage.setItem("hacs-search", this.SearchTerm);
    }
    ;
    clearSearch() {
        this.SearchTerm = "";
        localStorage.setItem("hacs-search", this.SearchTerm);
    }
    ShowRepository(ev) {
        var RepoID;
        ev.composedPath().forEach((item) => {
            if (item.RepoID) {
                RepoID = item.RepoID;
            }
        });
        this.panel = `repository`;
        this.repository = RepoID;
        this.repository_view = true;
        this.requestUpdate();
        navigate(this, `/${this._rootPath}/repository/${RepoID}`);
    }
    get _rootPath() {
        if (window.location.pathname.split("/")[1] === "hacs_dev")
            return "hacs_dev";
        return "hacs";
    }
    static get styles() {
        return [
            HacsStyle,
            css `
      hr {
        width: 95%
      }
      paper-item.list {
        margin-bottom: 24px;
      }
      paper-item:hover {
        outline: 0;
        background: var(--table-row-alternative-background-color);
    }
      .search-bar {
        display: block;
        width: 60%;
        margin-left: 3.4%;
        margin-top: 2%;
        background-color: var(--primary-background-color);
        color: var(--primary-text-color);
        line-height: 32px;
        border-color: var(--dark-primary-color);
        border-width: inherit;
        border-bottom-width: thin;
      }

      .sort {
        display: block;
        width: 30%;
        margin-left: 3.4%;
        margin-top: 2%;
        background-color: var(--primary-background-color);
        color: var(--primary-text-color);
        line-height: 32px;
        border-color: var(--dark-primary-color);
        border-width: inherit;
        border-bottom-width: thin;
      }

      .store-top {
        display: flex;
      }

      .store-top-installed, .store-top-settings {
        display: none;
      }

      paper-card.compact {
        height: 80px !important;
        white-space: nowrap !important;
      }

      paper-item.compact {
        margin-bottom: 2px !important;
        white-space: nowrap !important;
      }

      .card-group {
          margin-top: 24px;
          width: 95%;
          margin-left: 2.5%;
        }

        .card-group .title {
          color: var(--primary-text-color);
          margin-bottom: 12px;
        }

        .card-group .description {
          font-size: 0.5em;
          font-weight: 500;
          margin-top: 4px;
        }

        .card-group paper-card {
          --card-group-columns: 5;
          width: calc((100% - 12px * var(--card-group-columns)) / var(--card-group-columns));
          margin: 4px;
          vertical-align: top;
          height: 136px;
        }

        @media screen and (max-width: 2400px) and (min-width: 1801px) {
          .card-group paper-card {
            --card-group-columns: 4;
          }
        }

        @media screen and (max-width: 1800px) and (min-width: 1201px) {
          .card-group paper-card {
            --card-group-columns: 3;
          }
        }

        @media screen and (max-width: 1200px) and (min-width: 601px) {
          .card-group paper-card {
            --card-group-columns: 2;
          }
        }

        @media screen and (max-width: 600px) and (min-width: 0) {
          .card-group paper-card {
            width: 100%;
            margin: 4px 0;
          }
          .content {
            padding: 0;
          }
        }
    `
        ];
    }
};
__decorate([
    property()
], HacsPanelStore.prototype, "hass", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "repositories", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "configuration", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "route", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "panel", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "status", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "repository_view", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "repository", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "SortKey", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "SearchTerm", void 0);
__decorate([
    property()
], HacsPanelStore.prototype, "lovelaceconfig", void 0);
HacsPanelStore = __decorate([
    customElement("hacs-panel")
], HacsPanelStore);

function RepositoryWebSocketAction(hass, repository, Action, Data = undefined) {
    let message;
    if (Data !== undefined) {
        message = {
            type: "hacs/repository/data",
            action: Action,
            repository: repository,
            data: Data
        };
    }
    else {
        message = {
            type: "hacs/repository",
            action: Action,
            repository: repository
        };
    }
    hass.connection.sendMessage(message);
}

var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

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

function getCjsExportFromNamespace (n) {
	return n && n['default'] || n;
}

var marked = createCommonjsModule(function (module, exports) {
(function(root) {

/**
 * Block-Level Grammar
 */

var block = {
  newline: /^\n+/,
  code: /^( {4}[^\n]+\n*)+/,
  fences: /^ {0,3}(`{3,}|~{3,})([^`~\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
  hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
  heading: /^ {0,3}(#{1,6}) +([^\n]*?)(?: +#+)? *(?:\n+|$)/,
  blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
  list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
  html: '^ {0,3}(?:' // optional indentation
    + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
    + '|comment[^\\n]*(\\n+|$)' // (2)
    + '|<\\?[\\s\\S]*?\\?>\\n*' // (3)
    + '|<![A-Z][\\s\\S]*?>\\n*' // (4)
    + '|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>\\n*' // (5)
    + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:\\n{2,}|$)' // (6)
    + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) open tag
    + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)' // (7) closing tag
    + ')',
  def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
  nptable: noop,
  table: noop,
  lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
  // regex template, placeholders will be replaced according to different paragraph
  // interruption rules of commonmark and the original markdown spec:
  _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html)[^\n]+)*)/,
  text: /^[^\n]+/
};

block._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
block._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
block.def = edit(block.def)
  .replace('label', block._label)
  .replace('title', block._title)
  .getRegex();

block.bullet = /(?:[*+-]|\d{1,9}\.)/;
block.item = /^( *)(bull) ?[^\n]*(?:\n(?!\1bull ?)[^\n]*)*/;
block.item = edit(block.item, 'gm')
  .replace(/bull/g, block.bullet)
  .getRegex();

block.list = edit(block.list)
  .replace(/bull/g, block.bullet)
  .replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))')
  .replace('def', '\\n+(?=' + block.def.source + ')')
  .getRegex();

block._tag = 'address|article|aside|base|basefont|blockquote|body|caption'
  + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'
  + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'
  + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'
  + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr'
  + '|track|ul';
block._comment = /<!--(?!-?>)[\s\S]*?-->/;
block.html = edit(block.html, 'i')
  .replace('comment', block._comment)
  .replace('tag', block._tag)
  .replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/)
  .getRegex();

block.paragraph = edit(block._paragraph)
  .replace('hr', block.hr)
  .replace('heading', ' {0,3}#{1,6} +')
  .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
  .replace('blockquote', ' {0,3}>')
  .replace('fences', ' {0,3}(?:`{3,}|~{3,})[^`\\n]*\\n')
  .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
  .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)')
  .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks
  .getRegex();

block.blockquote = edit(block.blockquote)
  .replace('paragraph', block.paragraph)
  .getRegex();

/**
 * Normal Block Grammar
 */

block.normal = merge({}, block);

/**
 * GFM Block Grammar
 */

block.gfm = merge({}, block.normal, {
  nptable: /^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,
  table: /^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/
});

/**
 * Pedantic grammar (original John Gruber's loose markdown specification)
 */

block.pedantic = merge({}, block.normal, {
  html: edit(
    '^ *(?:comment *(?:\\n|\\s*$)'
    + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
    + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))')
    .replace('comment', block._comment)
    .replace(/tag/g, '(?!(?:'
      + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'
      + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'
      + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b')
    .getRegex(),
  def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
  heading: /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,
  fences: noop, // fences not supported
  paragraph: edit(block.normal._paragraph)
    .replace('hr', block.hr)
    .replace('heading', ' *#{1,6} *[^\n]')
    .replace('lheading', block.lheading)
    .replace('blockquote', ' {0,3}>')
    .replace('|fences', '')
    .replace('|list', '')
    .replace('|html', '')
    .getRegex()
});

/**
 * Block Lexer
 */

function Lexer(options) {
  this.tokens = [];
  this.tokens.links = Object.create(null);
  this.options = options || marked.defaults;
  this.rules = block.normal;

  if (this.options.pedantic) {
    this.rules = block.pedantic;
  } else if (this.options.gfm) {
    this.rules = block.gfm;
  }
}

/**
 * Expose Block Rules
 */

Lexer.rules = block;

/**
 * Static Lex Method
 */

Lexer.lex = function(src, options) {
  var lexer = new Lexer(options);
  return lexer.lex(src);
};

/**
 * Preprocessing
 */

Lexer.prototype.lex = function(src) {
  src = src
    .replace(/\r\n|\r/g, '\n')
    .replace(/\t/g, '    ')
    .replace(/\u00a0/g, ' ')
    .replace(/\u2424/g, '\n');

  return this.token(src, true);
};

/**
 * Lexing
 */

Lexer.prototype.token = function(src, top) {
  src = src.replace(/^ +$/gm, '');
  var next,
      loose,
      cap,
      bull,
      b,
      item,
      listStart,
      listItems,
      t,
      space,
      i,
      tag,
      l,
      isordered,
      istask,
      ischecked;

  while (src) {
    // newline
    if (cap = this.rules.newline.exec(src)) {
      src = src.substring(cap[0].length);
      if (cap[0].length > 1) {
        this.tokens.push({
          type: 'space'
        });
      }
    }

    // code
    if (cap = this.rules.code.exec(src)) {
      var lastToken = this.tokens[this.tokens.length - 1];
      src = src.substring(cap[0].length);
      // An indented code block cannot interrupt a paragraph.
      if (lastToken && lastToken.type === 'paragraph') {
        lastToken.text += '\n' + cap[0].trimRight();
      } else {
        cap = cap[0].replace(/^ {4}/gm, '');
        this.tokens.push({
          type: 'code',
          codeBlockStyle: 'indented',
          text: !this.options.pedantic
            ? rtrim(cap, '\n')
            : cap
        });
      }
      continue;
    }

    // fences
    if (cap = this.rules.fences.exec(src)) {
      src = src.substring(cap[0].length);
      this.tokens.push({
        type: 'code',
        lang: cap[2] ? cap[2].trim() : cap[2],
        text: cap[3] || ''
      });
      continue;
    }

    // heading
    if (cap = this.rules.heading.exec(src)) {
      src = src.substring(cap[0].length);
      this.tokens.push({
        type: 'heading',
        depth: cap[1].length,
        text: cap[2]
      });
      continue;
    }

    // table no leading pipe (gfm)
    if (cap = this.rules.nptable.exec(src)) {
      item = {
        type: 'table',
        header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
        align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
        cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
      };

      if (item.header.length === item.align.length) {
        src = src.substring(cap[0].length);

        for (i = 0; i < item.align.length; i++) {
          if (/^ *-+: *$/.test(item.align[i])) {
            item.align[i] = 'right';
          } else if (/^ *:-+: *$/.test(item.align[i])) {
            item.align[i] = 'center';
          } else if (/^ *:-+ *$/.test(item.align[i])) {
            item.align[i] = 'left';
          } else {
            item.align[i] = null;
          }
        }

        for (i = 0; i < item.cells.length; i++) {
          item.cells[i] = splitCells(item.cells[i], item.header.length);
        }

        this.tokens.push(item);

        continue;
      }
    }

    // hr
    if (cap = this.rules.hr.exec(src)) {
      src = src.substring(cap[0].length);
      this.tokens.push({
        type: 'hr'
      });
      continue;
    }

    // blockquote
    if (cap = this.rules.blockquote.exec(src)) {
      src = src.substring(cap[0].length);

      this.tokens.push({
        type: 'blockquote_start'
      });

      cap = cap[0].replace(/^ *> ?/gm, '');

      // Pass `top` to keep the current
      // "toplevel" state. This is exactly
      // how markdown.pl works.
      this.token(cap, top);

      this.tokens.push({
        type: 'blockquote_end'
      });

      continue;
    }

    // list
    if (cap = this.rules.list.exec(src)) {
      src = src.substring(cap[0].length);
      bull = cap[2];
      isordered = bull.length > 1;

      listStart = {
        type: 'list_start',
        ordered: isordered,
        start: isordered ? +bull : '',
        loose: false
      };

      this.tokens.push(listStart);

      // Get each top-level item.
      cap = cap[0].match(this.rules.item);

      listItems = [];
      next = false;
      l = cap.length;
      i = 0;

      for (; i < l; i++) {
        item = cap[i];

        // Remove the list item's bullet
        // so it is seen as the next token.
        space = item.length;
        item = item.replace(/^ *([*+-]|\d+\.) */, '');

        // Outdent whatever the
        // list item contains. Hacky.
        if (~item.indexOf('\n ')) {
          space -= item.length;
          item = !this.options.pedantic
            ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
            : item.replace(/^ {1,4}/gm, '');
        }

        // Determine whether the next list item belongs here.
        // Backpedal if it does not belong in this list.
        if (i !== l - 1) {
          b = block.bullet.exec(cap[i + 1])[0];
          if (bull.length > 1 ? b.length === 1
            : (b.length > 1 || (this.options.smartLists && b !== bull))) {
            src = cap.slice(i + 1).join('\n') + src;
            i = l - 1;
          }
        }

        // Determine whether item is loose or not.
        // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
        // for discount behavior.
        loose = next || /\n\n(?!\s*$)/.test(item);
        if (i !== l - 1) {
          next = item.charAt(item.length - 1) === '\n';
          if (!loose) loose = next;
        }

        if (loose) {
          listStart.loose = true;
        }

        // Check for task list items
        istask = /^\[[ xX]\] /.test(item);
        ischecked = undefined;
        if (istask) {
          ischecked = item[1] !== ' ';
          item = item.replace(/^\[[ xX]\] +/, '');
        }

        t = {
          type: 'list_item_start',
          task: istask,
          checked: ischecked,
          loose: loose
        };

        listItems.push(t);
        this.tokens.push(t);

        // Recurse.
        this.token(item, false);

        this.tokens.push({
          type: 'list_item_end'
        });
      }

      if (listStart.loose) {
        l = listItems.length;
        i = 0;
        for (; i < l; i++) {
          listItems[i].loose = true;
        }
      }

      this.tokens.push({
        type: 'list_end'
      });

      continue;
    }

    // html
    if (cap = this.rules.html.exec(src)) {
      src = src.substring(cap[0].length);
      this.tokens.push({
        type: this.options.sanitize
          ? 'paragraph'
          : 'html',
        pre: !this.options.sanitizer
          && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
        text: this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]
      });
      continue;
    }

    // def
    if (top && (cap = this.rules.def.exec(src))) {
      src = src.substring(cap[0].length);
      if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
      tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
      if (!this.tokens.links[tag]) {
        this.tokens.links[tag] = {
          href: cap[2],
          title: cap[3]
        };
      }
      continue;
    }

    // table (gfm)
    if (cap = this.rules.table.exec(src)) {
      item = {
        type: 'table',
        header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
        align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
        cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
      };

      if (item.header.length === item.align.length) {
        src = src.substring(cap[0].length);

        for (i = 0; i < item.align.length; i++) {
          if (/^ *-+: *$/.test(item.align[i])) {
            item.align[i] = 'right';
          } else if (/^ *:-+: *$/.test(item.align[i])) {
            item.align[i] = 'center';
          } else if (/^ *:-+ *$/.test(item.align[i])) {
            item.align[i] = 'left';
          } else {
            item.align[i] = null;
          }
        }

        for (i = 0; i < item.cells.length; i++) {
          item.cells[i] = splitCells(
            item.cells[i].replace(/^ *\| *| *\| *$/g, ''),
            item.header.length);
        }

        this.tokens.push(item);

        continue;
      }
    }

    // lheading
    if (cap = this.rules.lheading.exec(src)) {
      src = src.substring(cap[0].length);
      this.tokens.push({
        type: 'heading',
        depth: cap[2].charAt(0) === '=' ? 1 : 2,
        text: cap[1]
      });
      continue;
    }

    // top-level paragraph
    if (top && (cap = this.rules.paragraph.exec(src))) {
      src = src.substring(cap[0].length);
      this.tokens.push({
        type: 'paragraph',
        text: cap[1].charAt(cap[1].length - 1) === '\n'
          ? cap[1].slice(0, -1)
          : cap[1]
      });
      continue;
    }

    // text
    if (cap = this.rules.text.exec(src)) {
      // Top-level should never reach here.
      src = src.substring(cap[0].length);
      this.tokens.push({
        type: 'text',
        text: cap[0]
      });
      continue;
    }

    if (src) {
      throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
    }
  }

  return this.tokens;
};

/**
 * Inline-Level Grammar
 */

var inline = {
  escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
  autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
  url: noop,
  tag: '^comment'
    + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
    + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
    + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
    + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
    + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>', // CDATA section
  link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
  reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
  nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
  strong: /^__([^\s_])__(?!_)|^\*\*([^\s*])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,
  em: /^_([^\s_])_(?!_)|^\*([^\s*<\[])\*(?!\*)|^_([^\s<][\s\S]*?[^\s_])_(?!_|[^\spunctuation])|^_([^\s_<][\s\S]*?[^\s])_(?!_|[^\spunctuation])|^\*([^\s<"][\s\S]*?[^\s\*])\*(?!\*|[^\spunctuation])|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,
  code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
  br: /^( {2,}|\\)\n(?!\s*$)/,
  del: noop,
  text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*]|\b_|$)|[^ ](?= {2,}\n))|(?= {2,}\n))/
};

// list of punctuation marks from common mark spec
// without ` and ] to workaround Rule 17 (inline code blocks/links)
inline._punctuation = '!"#$%&\'()*+,\\-./:;<=>?@\\[^_{|}~';
inline.em = edit(inline.em).replace(/punctuation/g, inline._punctuation).getRegex();

inline._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;

inline._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
inline._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
inline.autolink = edit(inline.autolink)
  .replace('scheme', inline._scheme)
  .replace('email', inline._email)
  .getRegex();

inline._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;

inline.tag = edit(inline.tag)
  .replace('comment', block._comment)
  .replace('attribute', inline._attribute)
  .getRegex();

inline._label = /(?:\[[^\[\]]*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
inline._href = /<(?:\\[<>]?|[^\s<>\\])*>|[^\s\x00-\x1f]*/;
inline._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;

inline.link = edit(inline.link)
  .replace('label', inline._label)
  .replace('href', inline._href)
  .replace('title', inline._title)
  .getRegex();

inline.reflink = edit(inline.reflink)
  .replace('label', inline._label)
  .getRegex();

/**
 * Normal Inline Grammar
 */

inline.normal = merge({}, inline);

/**
 * Pedantic Inline Grammar
 */

inline.pedantic = merge({}, inline.normal, {
  strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
  em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
  link: edit(/^!?\[(label)\]\((.*?)\)/)
    .replace('label', inline._label)
    .getRegex(),
  reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/)
    .replace('label', inline._label)
    .getRegex()
});

/**
 * GFM Inline Grammar
 */

inline.gfm = merge({}, inline.normal, {
  escape: edit(inline.escape).replace('])', '~|])').getRegex(),
  _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
  url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
  _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
  del: /^~+(?=\S)([\s\S]*?\S)~+/,
  text: /^(`+|[^`])(?:[\s\S]*?(?:(?=[\\<!\[`*~]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?= {2,}\n|[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
});

inline.gfm.url = edit(inline.gfm.url, 'i')
  .replace('email', inline.gfm._extended_email)
  .getRegex();
/**
 * GFM + Line Breaks Inline Grammar
 */

inline.breaks = merge({}, inline.gfm, {
  br: edit(inline.br).replace('{2,}', '*').getRegex(),
  text: edit(inline.gfm.text)
    .replace('\\b_', '\\b_| {2,}\\n')
    .replace(/\{2,\}/g, '*')
    .getRegex()
});

/**
 * Inline Lexer & Compiler
 */

function InlineLexer(links, options) {
  this.options = options || marked.defaults;
  this.links = links;
  this.rules = inline.normal;
  this.renderer = this.options.renderer || new Renderer();
  this.renderer.options = this.options;

  if (!this.links) {
    throw new Error('Tokens array requires a `links` property.');
  }

  if (this.options.pedantic) {
    this.rules = inline.pedantic;
  } else if (this.options.gfm) {
    if (this.options.breaks) {
      this.rules = inline.breaks;
    } else {
      this.rules = inline.gfm;
    }
  }
}

/**
 * Expose Inline Rules
 */

InlineLexer.rules = inline;

/**
 * Static Lexing/Compiling Method
 */

InlineLexer.output = function(src, links, options) {
  var inline = new InlineLexer(links, options);
  return inline.output(src);
};

/**
 * Lexing/Compiling
 */

InlineLexer.prototype.output = function(src) {
  var out = '',
      link,
      text,
      href,
      title,
      cap,
      prevCapZero;

  while (src) {
    // escape
    if (cap = this.rules.escape.exec(src)) {
      src = src.substring(cap[0].length);
      out += escape(cap[1]);
      continue;
    }

    // tag
    if (cap = this.rules.tag.exec(src)) {
      if (!this.inLink && /^<a /i.test(cap[0])) {
        this.inLink = true;
      } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
        this.inLink = false;
      }
      if (!this.inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
        this.inRawBlock = true;
      } else if (this.inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
        this.inRawBlock = false;
      }

      src = src.substring(cap[0].length);
      out += this.options.sanitize
        ? this.options.sanitizer
          ? this.options.sanitizer(cap[0])
          : escape(cap[0])
        : cap[0];
      continue;
    }

    // link
    if (cap = this.rules.link.exec(src)) {
      var lastParenIndex = findClosingBracket(cap[2], '()');
      if (lastParenIndex > -1) {
        var linkLen = 4 + cap[1].length + lastParenIndex;
        cap[2] = cap[2].substring(0, lastParenIndex);
        cap[0] = cap[0].substring(0, linkLen).trim();
        cap[3] = '';
      }
      src = src.substring(cap[0].length);
      this.inLink = true;
      href = cap[2];
      if (this.options.pedantic) {
        link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);

        if (link) {
          href = link[1];
          title = link[3];
        } else {
          title = '';
        }
      } else {
        title = cap[3] ? cap[3].slice(1, -1) : '';
      }
      href = href.trim().replace(/^<([\s\S]*)>$/, '$1');
      out += this.outputLink(cap, {
        href: InlineLexer.escapes(href),
        title: InlineLexer.escapes(title)
      });
      this.inLink = false;
      continue;
    }

    // reflink, nolink
    if ((cap = this.rules.reflink.exec(src))
        || (cap = this.rules.nolink.exec(src))) {
      src = src.substring(cap[0].length);
      link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
      link = this.links[link.toLowerCase()];
      if (!link || !link.href) {
        out += cap[0].charAt(0);
        src = cap[0].substring(1) + src;
        continue;
      }
      this.inLink = true;
      out += this.outputLink(cap, link);
      this.inLink = false;
      continue;
    }

    // strong
    if (cap = this.rules.strong.exec(src)) {
      src = src.substring(cap[0].length);
      out += this.renderer.strong(this.output(cap[4] || cap[3] || cap[2] || cap[1]));
      continue;
    }

    // em
    if (cap = this.rules.em.exec(src)) {
      src = src.substring(cap[0].length);
      out += this.renderer.em(this.output(cap[6] || cap[5] || cap[4] || cap[3] || cap[2] || cap[1]));
      continue;
    }

    // code
    if (cap = this.rules.code.exec(src)) {
      src = src.substring(cap[0].length);
      out += this.renderer.codespan(escape(cap[2].trim(), true));
      continue;
    }

    // br
    if (cap = this.rules.br.exec(src)) {
      src = src.substring(cap[0].length);
      out += this.renderer.br();
      continue;
    }

    // del (gfm)
    if (cap = this.rules.del.exec(src)) {
      src = src.substring(cap[0].length);
      out += this.renderer.del(this.output(cap[1]));
      continue;
    }

    // autolink
    if (cap = this.rules.autolink.exec(src)) {
      src = src.substring(cap[0].length);
      if (cap[2] === '@') {
        text = escape(this.mangle(cap[1]));
        href = 'mailto:' + text;
      } else {
        text = escape(cap[1]);
        href = text;
      }
      out += this.renderer.link(href, null, text);
      continue;
    }

    // url (gfm)
    if (!this.inLink && (cap = this.rules.url.exec(src))) {
      if (cap[2] === '@') {
        text = escape(cap[0]);
        href = 'mailto:' + text;
      } else {
        // do extended autolink path validation
        do {
          prevCapZero = cap[0];
          cap[0] = this.rules._backpedal.exec(cap[0])[0];
        } while (prevCapZero !== cap[0]);
        text = escape(cap[0]);
        if (cap[1] === 'www.') {
          href = 'http://' + text;
        } else {
          href = text;
        }
      }
      src = src.substring(cap[0].length);
      out += this.renderer.link(href, null, text);
      continue;
    }

    // text
    if (cap = this.rules.text.exec(src)) {
      src = src.substring(cap[0].length);
      if (this.inRawBlock) {
        out += this.renderer.text(this.options.sanitize ? (this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0])) : cap[0]);
      } else {
        out += this.renderer.text(escape(this.smartypants(cap[0])));
      }
      continue;
    }

    if (src) {
      throw new Error('Infinite loop on byte: ' + src.charCodeAt(0));
    }
  }

  return out;
};

InlineLexer.escapes = function(text) {
  return text ? text.replace(InlineLexer.rules._escapes, '$1') : text;
};

/**
 * Compile Link
 */

InlineLexer.prototype.outputLink = function(cap, link) {
  var href = link.href,
      title = link.title ? escape(link.title) : null;

  return cap[0].charAt(0) !== '!'
    ? this.renderer.link(href, title, this.output(cap[1]))
    : this.renderer.image(href, title, escape(cap[1]));
};

/**
 * Smartypants Transformations
 */

InlineLexer.prototype.smartypants = function(text) {
  if (!this.options.smartypants) return text;
  return text
    // em-dashes
    .replace(/---/g, '\u2014')
    // en-dashes
    .replace(/--/g, '\u2013')
    // opening singles
    .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
    // closing singles & apostrophes
    .replace(/'/g, '\u2019')
    // opening doubles
    .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
    // closing doubles
    .replace(/"/g, '\u201d')
    // ellipses
    .replace(/\.{3}/g, '\u2026');
};

/**
 * Mangle Links
 */

InlineLexer.prototype.mangle = function(text) {
  if (!this.options.mangle) return text;
  var out = '',
      l = text.length,
      i = 0,
      ch;

  for (; i < l; i++) {
    ch = text.charCodeAt(i);
    if (Math.random() > 0.5) {
      ch = 'x' + ch.toString(16);
    }
    out += '&#' + ch + ';';
  }

  return out;
};

/**
 * Renderer
 */

function Renderer(options) {
  this.options = options || marked.defaults;
}

Renderer.prototype.code = function(code, infostring, escaped) {
  var lang = (infostring || '').match(/\S*/)[0];
  if (this.options.highlight) {
    var out = this.options.highlight(code, lang);
    if (out != null && out !== code) {
      escaped = true;
      code = out;
    }
  }

  if (!lang) {
    return '<pre><code>'
      + (escaped ? code : escape(code, true))
      + '</code></pre>';
  }

  return '<pre><code class="'
    + this.options.langPrefix
    + escape(lang, true)
    + '">'
    + (escaped ? code : escape(code, true))
    + '</code></pre>\n';
};

Renderer.prototype.blockquote = function(quote) {
  return '<blockquote>\n' + quote + '</blockquote>\n';
};

Renderer.prototype.html = function(html) {
  return html;
};

Renderer.prototype.heading = function(text, level, raw, slugger) {
  if (this.options.headerIds) {
    return '<h'
      + level
      + ' id="'
      + this.options.headerPrefix
      + slugger.slug(raw)
      + '">'
      + text
      + '</h'
      + level
      + '>\n';
  }
  // ignore IDs
  return '<h' + level + '>' + text + '</h' + level + '>\n';
};

Renderer.prototype.hr = function() {
  return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
};

Renderer.prototype.list = function(body, ordered, start) {
  var type = ordered ? 'ol' : 'ul',
      startatt = (ordered && start !== 1) ? (' start="' + start + '"') : '';
  return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
};

Renderer.prototype.listitem = function(text) {
  return '<li>' + text + '</li>\n';
};

Renderer.prototype.checkbox = function(checked) {
  return '<input '
    + (checked ? 'checked="" ' : '')
    + 'disabled="" type="checkbox"'
    + (this.options.xhtml ? ' /' : '')
    + '> ';
};

Renderer.prototype.paragraph = function(text) {
  return '<p>' + text + '</p>\n';
};

Renderer.prototype.table = function(header, body) {
  if (body) body = '<tbody>' + body + '</tbody>';

  return '<table>\n'
    + '<thead>\n'
    + header
    + '</thead>\n'
    + body
    + '</table>\n';
};

Renderer.prototype.tablerow = function(content) {
  return '<tr>\n' + content + '</tr>\n';
};

Renderer.prototype.tablecell = function(content, flags) {
  var type = flags.header ? 'th' : 'td';
  var tag = flags.align
    ? '<' + type + ' align="' + flags.align + '">'
    : '<' + type + '>';
  return tag + content + '</' + type + '>\n';
};

// span level renderer
Renderer.prototype.strong = function(text) {
  return '<strong>' + text + '</strong>';
};

Renderer.prototype.em = function(text) {
  return '<em>' + text + '</em>';
};

Renderer.prototype.codespan = function(text) {
  return '<code>' + text + '</code>';
};

Renderer.prototype.br = function() {
  return this.options.xhtml ? '<br/>' : '<br>';
};

Renderer.prototype.del = function(text) {
  return '<del>' + text + '</del>';
};

Renderer.prototype.link = function(href, title, text) {
  href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
  if (href === null) {
    return text;
  }
  var out = '<a href="' + escape(href) + '"';
  if (title) {
    out += ' title="' + title + '"';
  }
  out += '>' + text + '</a>';
  return out;
};

Renderer.prototype.image = function(href, title, text) {
  href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
  if (href === null) {
    return text;
  }

  var out = '<img src="' + href + '" alt="' + text + '"';
  if (title) {
    out += ' title="' + title + '"';
  }
  out += this.options.xhtml ? '/>' : '>';
  return out;
};

Renderer.prototype.text = function(text) {
  return text;
};

/**
 * TextRenderer
 * returns only the textual part of the token
 */

function TextRenderer() {}

// no need for block level renderers

TextRenderer.prototype.strong =
TextRenderer.prototype.em =
TextRenderer.prototype.codespan =
TextRenderer.prototype.del =
TextRenderer.prototype.text = function(text) {
  return text;
};

TextRenderer.prototype.link =
TextRenderer.prototype.image = function(href, title, text) {
  return '' + text;
};

TextRenderer.prototype.br = function() {
  return '';
};

/**
 * Parsing & Compiling
 */

function Parser(options) {
  this.tokens = [];
  this.token = null;
  this.options = options || marked.defaults;
  this.options.renderer = this.options.renderer || new Renderer();
  this.renderer = this.options.renderer;
  this.renderer.options = this.options;
  this.slugger = new Slugger();
}

/**
 * Static Parse Method
 */

Parser.parse = function(src, options) {
  var parser = new Parser(options);
  return parser.parse(src);
};

/**
 * Parse Loop
 */

Parser.prototype.parse = function(src) {
  this.inline = new InlineLexer(src.links, this.options);
  // use an InlineLexer with a TextRenderer to extract pure text
  this.inlineText = new InlineLexer(
    src.links,
    merge({}, this.options, { renderer: new TextRenderer() })
  );
  this.tokens = src.reverse();

  var out = '';
  while (this.next()) {
    out += this.tok();
  }

  return out;
};

/**
 * Next Token
 */

Parser.prototype.next = function() {
  this.token = this.tokens.pop();
  return this.token;
};

/**
 * Preview Next Token
 */

Parser.prototype.peek = function() {
  return this.tokens[this.tokens.length - 1] || 0;
};

/**
 * Parse Text Tokens
 */

Parser.prototype.parseText = function() {
  var body = this.token.text;

  while (this.peek().type === 'text') {
    body += '\n' + this.next().text;
  }

  return this.inline.output(body);
};

/**
 * Parse Current Token
 */

Parser.prototype.tok = function() {
  switch (this.token.type) {
    case 'space': {
      return '';
    }
    case 'hr': {
      return this.renderer.hr();
    }
    case 'heading': {
      return this.renderer.heading(
        this.inline.output(this.token.text),
        this.token.depth,
        unescape(this.inlineText.output(this.token.text)),
        this.slugger);
    }
    case 'code': {
      return this.renderer.code(this.token.text,
        this.token.lang,
        this.token.escaped);
    }
    case 'table': {
      var header = '',
          body = '',
          i,
          row,
          cell,
          j;

      // header
      cell = '';
      for (i = 0; i < this.token.header.length; i++) {
        cell += this.renderer.tablecell(
          this.inline.output(this.token.header[i]),
          { header: true, align: this.token.align[i] }
        );
      }
      header += this.renderer.tablerow(cell);

      for (i = 0; i < this.token.cells.length; i++) {
        row = this.token.cells[i];

        cell = '';
        for (j = 0; j < row.length; j++) {
          cell += this.renderer.tablecell(
            this.inline.output(row[j]),
            { header: false, align: this.token.align[j] }
          );
        }

        body += this.renderer.tablerow(cell);
      }
      return this.renderer.table(header, body);
    }
    case 'blockquote_start': {
      body = '';

      while (this.next().type !== 'blockquote_end') {
        body += this.tok();
      }

      return this.renderer.blockquote(body);
    }
    case 'list_start': {
      body = '';
      var ordered = this.token.ordered,
          start = this.token.start;

      while (this.next().type !== 'list_end') {
        body += this.tok();
      }

      return this.renderer.list(body, ordered, start);
    }
    case 'list_item_start': {
      body = '';
      var loose = this.token.loose;
      var checked = this.token.checked;
      var task = this.token.task;

      if (this.token.task) {
        body += this.renderer.checkbox(checked);
      }

      while (this.next().type !== 'list_item_end') {
        body += !loose && this.token.type === 'text'
          ? this.parseText()
          : this.tok();
      }
      return this.renderer.listitem(body, task, checked);
    }
    case 'html': {
      // TODO parse inline content if parameter markdown=1
      return this.renderer.html(this.token.text);
    }
    case 'paragraph': {
      return this.renderer.paragraph(this.inline.output(this.token.text));
    }
    case 'text': {
      return this.renderer.paragraph(this.parseText());
    }
    default: {
      var errMsg = 'Token with "' + this.token.type + '" type was not found.';
      if (this.options.silent) {
        console.log(errMsg);
      } else {
        throw new Error(errMsg);
      }
    }
  }
};

/**
 * Slugger generates header id
 */

function Slugger() {
  this.seen = {};
}

/**
 * Convert string to unique id
 */

Slugger.prototype.slug = function(value) {
  var slug = value
    .toLowerCase()
    .trim()
    .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '')
    .replace(/\s/g, '-');

  if (this.seen.hasOwnProperty(slug)) {
    var originalSlug = slug;
    do {
      this.seen[originalSlug]++;
      slug = originalSlug + '-' + this.seen[originalSlug];
    } while (this.seen.hasOwnProperty(slug));
  }
  this.seen[slug] = 0;

  return slug;
};

/**
 * Helpers
 */

function escape(html, encode) {
  if (encode) {
    if (escape.escapeTest.test(html)) {
      return html.replace(escape.escapeReplace, function(ch) { return escape.replacements[ch]; });
    }
  } else {
    if (escape.escapeTestNoEncode.test(html)) {
      return html.replace(escape.escapeReplaceNoEncode, function(ch) { return escape.replacements[ch]; });
    }
  }

  return html;
}

escape.escapeTest = /[&<>"']/;
escape.escapeReplace = /[&<>"']/g;
escape.replacements = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  "'": '&#39;'
};

escape.escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
escape.escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;

function unescape(html) {
  // explicitly match decimal, hex, and named HTML entities
  return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig, function(_, n) {
    n = n.toLowerCase();
    if (n === 'colon') return ':';
    if (n.charAt(0) === '#') {
      return n.charAt(1) === 'x'
        ? String.fromCharCode(parseInt(n.substring(2), 16))
        : String.fromCharCode(+n.substring(1));
    }
    return '';
  });
}

function edit(regex, opt) {
  regex = regex.source || regex;
  opt = opt || '';
  return {
    replace: function(name, val) {
      val = val.source || val;
      val = val.replace(/(^|[^\[])\^/g, '$1');
      regex = regex.replace(name, val);
      return this;
    },
    getRegex: function() {
      return new RegExp(regex, opt);
    }
  };
}

function cleanUrl(sanitize, base, href) {
  if (sanitize) {
    try {
      var prot = decodeURIComponent(unescape(href))
        .replace(/[^\w:]/g, '')
        .toLowerCase();
    } catch (e) {
      return null;
    }
    if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
      return null;
    }
  }
  if (base && !originIndependentUrl.test(href)) {
    href = resolveUrl(base, href);
  }
  try {
    href = encodeURI(href).replace(/%25/g, '%');
  } catch (e) {
    return null;
  }
  return href;
}

function resolveUrl(base, href) {
  if (!baseUrls[' ' + base]) {
    // we can ignore everything in base after the last slash of its path component,
    // but we might need to add _that_
    // https://tools.ietf.org/html/rfc3986#section-3
    if (/^[^:]+:\/*[^/]*$/.test(base)) {
      baseUrls[' ' + base] = base + '/';
    } else {
      baseUrls[' ' + base] = rtrim(base, '/', true);
    }
  }
  base = baseUrls[' ' + base];

  if (href.slice(0, 2) === '//') {
    return base.replace(/:[\s\S]*/, ':') + href;
  } else if (href.charAt(0) === '/') {
    return base.replace(/(:\/*[^/]*)[\s\S]*/, '$1') + href;
  } else {
    return base + href;
  }
}
var baseUrls = {};
var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;

function noop() {}
noop.exec = noop;

function merge(obj) {
  var i = 1,
      target,
      key;

  for (; i < arguments.length; i++) {
    target = arguments[i];
    for (key in target) {
      if (Object.prototype.hasOwnProperty.call(target, key)) {
        obj[key] = target[key];
      }
    }
  }

  return obj;
}

function splitCells(tableRow, count) {
  // ensure that every cell-delimiting pipe has a space
  // before it to distinguish it from an escaped pipe
  var row = tableRow.replace(/\|/g, function(match, offset, str) {
        var escaped = false,
            curr = offset;
        while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
        if (escaped) {
          // odd number of slashes means | is escaped
          // so we leave it alone
          return '|';
        } else {
          // add space before unescaped |
          return ' |';
        }
      }),
      cells = row.split(/ \|/),
      i = 0;

  if (cells.length > count) {
    cells.splice(count);
  } else {
    while (cells.length < count) cells.push('');
  }

  for (; i < cells.length; i++) {
    // leading or trailing whitespace is ignored per the gfm spec
    cells[i] = cells[i].trim().replace(/\\\|/g, '|');
  }
  return cells;
}

// Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
// /c*$/ is vulnerable to REDOS.
// invert: Remove suffix of non-c chars instead. Default falsey.
function rtrim(str, c, invert) {
  if (str.length === 0) {
    return '';
  }

  // Length of suffix matching the invert condition.
  var suffLen = 0;

  // Step left until we fail to match the invert condition.
  while (suffLen < str.length) {
    var currChar = str.charAt(str.length - suffLen - 1);
    if (currChar === c && !invert) {
      suffLen++;
    } else if (currChar !== c && invert) {
      suffLen++;
    } else {
      break;
    }
  }

  return str.substr(0, str.length - suffLen);
}

function findClosingBracket(str, b) {
  if (str.indexOf(b[1]) === -1) {
    return -1;
  }
  var level = 0;
  for (var i = 0; i < str.length; i++) {
    if (str[i] === '\\') {
      i++;
    } else if (str[i] === b[0]) {
      level++;
    } else if (str[i] === b[1]) {
      level--;
      if (level < 0) {
        return i;
      }
    }
  }
  return -1;
}

function checkSanitizeDeprecation(opt) {
  if (opt && opt.sanitize && !opt.silent) {
    console.warn('marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options');
  }
}

/**
 * Marked
 */

function marked(src, opt, callback) {
  // throw error in case of non string input
  if (typeof src === 'undefined' || src === null) {
    throw new Error('marked(): input parameter is undefined or null');
  }
  if (typeof src !== 'string') {
    throw new Error('marked(): input parameter is of type '
      + Object.prototype.toString.call(src) + ', string expected');
  }

  if (callback || typeof opt === 'function') {
    if (!callback) {
      callback = opt;
      opt = null;
    }

    opt = merge({}, marked.defaults, opt || {});
    checkSanitizeDeprecation(opt);

    var highlight = opt.highlight,
        tokens,
        pending,
        i = 0;

    try {
      tokens = Lexer.lex(src, opt);
    } catch (e) {
      return callback(e);
    }

    pending = tokens.length;

    var done = function(err) {
      if (err) {
        opt.highlight = highlight;
        return callback(err);
      }

      var out;

      try {
        out = Parser.parse(tokens, opt);
      } catch (e) {
        err = e;
      }

      opt.highlight = highlight;

      return err
        ? callback(err)
        : callback(null, out);
    };

    if (!highlight || highlight.length < 3) {
      return done();
    }

    delete opt.highlight;

    if (!pending) return done();

    for (; i < tokens.length; i++) {
      (function(token) {
        if (token.type !== 'code') {
          return --pending || done();
        }
        return highlight(token.text, token.lang, function(err, code) {
          if (err) return done(err);
          if (code == null || code === token.text) {
            return --pending || done();
          }
          token.text = code;
          token.escaped = true;
          --pending || done();
        });
      })(tokens[i]);
    }

    return;
  }
  try {
    if (opt) opt = merge({}, marked.defaults, opt);
    checkSanitizeDeprecation(opt);
    return Parser.parse(Lexer.lex(src, opt), opt);
  } catch (e) {
    e.message += '\nPlease report this to https://github.com/markedjs/marked.';
    if ((opt || marked.defaults).silent) {
      return '<p>An error occurred:</p><pre>'
        + escape(e.message + '', true)
        + '</pre>';
    }
    throw e;
  }
}

/**
 * Options
 */

marked.options =
marked.setOptions = function(opt) {
  merge(marked.defaults, opt);
  return marked;
};

marked.getDefaults = function() {
  return {
    baseUrl: null,
    breaks: false,
    gfm: true,
    headerIds: true,
    headerPrefix: '',
    highlight: null,
    langPrefix: 'language-',
    mangle: true,
    pedantic: false,
    renderer: new Renderer(),
    sanitize: false,
    sanitizer: null,
    silent: false,
    smartLists: false,
    smartypants: false,
    xhtml: false
  };
};

marked.defaults = marked.getDefaults();

/**
 * Expose
 */

marked.Parser = Parser;
marked.parser = Parser.parse;

marked.Renderer = Renderer;
marked.TextRenderer = TextRenderer;

marked.Lexer = Lexer;
marked.lexer = Lexer.lex;

marked.InlineLexer = InlineLexer;
marked.inlineLexer = InlineLexer.output;

marked.Slugger = Slugger;

marked.parse = marked;

{
  module.exports = marked;
}
})();
});

/**
 * cssfilter
 *
 * @author 老雷<leizongmin@gmail.com>
 */

function getDefaultWhiteList () {
  // 白名单值说明：
  // true: 允许该属性
  // Function: function (val) { } 返回true表示允许该属性，其他值均表示不允许
  // RegExp: regexp.test(val) 返回true表示允许该属性，其他值均表示不允许
  // 除上面列出的值外均表示不允许
  var whiteList = {};

  whiteList['align-content'] = false; // default: auto
  whiteList['align-items'] = false; // default: auto
  whiteList['align-self'] = false; // default: auto
  whiteList['alignment-adjust'] = false; // default: auto
  whiteList['alignment-baseline'] = false; // default: baseline
  whiteList['all'] = false; // default: depending on individual properties
  whiteList['anchor-point'] = false; // default: none
  whiteList['animation'] = false; // default: depending on individual properties
  whiteList['animation-delay'] = false; // default: 0
  whiteList['animation-direction'] = false; // default: normal
  whiteList['animation-duration'] = false; // default: 0
  whiteList['animation-fill-mode'] = false; // default: none
  whiteList['animation-iteration-count'] = false; // default: 1
  whiteList['animation-name'] = false; // default: none
  whiteList['animation-play-state'] = false; // default: running
  whiteList['animation-timing-function'] = false; // default: ease
  whiteList['azimuth'] = false; // default: center
  whiteList['backface-visibility'] = false; // default: visible
  whiteList['background'] = true; // default: depending on individual properties
  whiteList['background-attachment'] = true; // default: scroll
  whiteList['background-clip'] = true; // default: border-box
  whiteList['background-color'] = true; // default: transparent
  whiteList['background-image'] = true; // default: none
  whiteList['background-origin'] = true; // default: padding-box
  whiteList['background-position'] = true; // default: 0% 0%
  whiteList['background-repeat'] = true; // default: repeat
  whiteList['background-size'] = true; // default: auto
  whiteList['baseline-shift'] = false; // default: baseline
  whiteList['binding'] = false; // default: none
  whiteList['bleed'] = false; // default: 6pt
  whiteList['bookmark-label'] = false; // default: content()
  whiteList['bookmark-level'] = false; // default: none
  whiteList['bookmark-state'] = false; // default: open
  whiteList['border'] = true; // default: depending on individual properties
  whiteList['border-bottom'] = true; // default: depending on individual properties
  whiteList['border-bottom-color'] = true; // default: current color
  whiteList['border-bottom-left-radius'] = true; // default: 0
  whiteList['border-bottom-right-radius'] = true; // default: 0
  whiteList['border-bottom-style'] = true; // default: none
  whiteList['border-bottom-width'] = true; // default: medium
  whiteList['border-collapse'] = true; // default: separate
  whiteList['border-color'] = true; // default: depending on individual properties
  whiteList['border-image'] = true; // default: none
  whiteList['border-image-outset'] = true; // default: 0
  whiteList['border-image-repeat'] = true; // default: stretch
  whiteList['border-image-slice'] = true; // default: 100%
  whiteList['border-image-source'] = true; // default: none
  whiteList['border-image-width'] = true; // default: 1
  whiteList['border-left'] = true; // default: depending on individual properties
  whiteList['border-left-color'] = true; // default: current color
  whiteList['border-left-style'] = true; // default: none
  whiteList['border-left-width'] = true; // default: medium
  whiteList['border-radius'] = true; // default: 0
  whiteList['border-right'] = true; // default: depending on individual properties
  whiteList['border-right-color'] = true; // default: current color
  whiteList['border-right-style'] = true; // default: none
  whiteList['border-right-width'] = true; // default: medium
  whiteList['border-spacing'] = true; // default: 0
  whiteList['border-style'] = true; // default: depending on individual properties
  whiteList['border-top'] = true; // default: depending on individual properties
  whiteList['border-top-color'] = true; // default: current color
  whiteList['border-top-left-radius'] = true; // default: 0
  whiteList['border-top-right-radius'] = true; // default: 0
  whiteList['border-top-style'] = true; // default: none
  whiteList['border-top-width'] = true; // default: medium
  whiteList['border-width'] = true; // default: depending on individual properties
  whiteList['bottom'] = false; // default: auto
  whiteList['box-decoration-break'] = true; // default: slice
  whiteList['box-shadow'] = true; // default: none
  whiteList['box-sizing'] = true; // default: content-box
  whiteList['box-snap'] = true; // default: none
  whiteList['box-suppress'] = true; // default: show
  whiteList['break-after'] = true; // default: auto
  whiteList['break-before'] = true; // default: auto
  whiteList['break-inside'] = true; // default: auto
  whiteList['caption-side'] = false; // default: top
  whiteList['chains'] = false; // default: none
  whiteList['clear'] = true; // default: none
  whiteList['clip'] = false; // default: auto
  whiteList['clip-path'] = false; // default: none
  whiteList['clip-rule'] = false; // default: nonzero
  whiteList['color'] = true; // default: implementation dependent
  whiteList['color-interpolation-filters'] = true; // default: auto
  whiteList['column-count'] = false; // default: auto
  whiteList['column-fill'] = false; // default: balance
  whiteList['column-gap'] = false; // default: normal
  whiteList['column-rule'] = false; // default: depending on individual properties
  whiteList['column-rule-color'] = false; // default: current color
  whiteList['column-rule-style'] = false; // default: medium
  whiteList['column-rule-width'] = false; // default: medium
  whiteList['column-span'] = false; // default: none
  whiteList['column-width'] = false; // default: auto
  whiteList['columns'] = false; // default: depending on individual properties
  whiteList['contain'] = false; // default: none
  whiteList['content'] = false; // default: normal
  whiteList['counter-increment'] = false; // default: none
  whiteList['counter-reset'] = false; // default: none
  whiteList['counter-set'] = false; // default: none
  whiteList['crop'] = false; // default: auto
  whiteList['cue'] = false; // default: depending on individual properties
  whiteList['cue-after'] = false; // default: none
  whiteList['cue-before'] = false; // default: none
  whiteList['cursor'] = false; // default: auto
  whiteList['direction'] = false; // default: ltr
  whiteList['display'] = true; // default: depending on individual properties
  whiteList['display-inside'] = true; // default: auto
  whiteList['display-list'] = true; // default: none
  whiteList['display-outside'] = true; // default: inline-level
  whiteList['dominant-baseline'] = false; // default: auto
  whiteList['elevation'] = false; // default: level
  whiteList['empty-cells'] = false; // default: show
  whiteList['filter'] = false; // default: none
  whiteList['flex'] = false; // default: depending on individual properties
  whiteList['flex-basis'] = false; // default: auto
  whiteList['flex-direction'] = false; // default: row
  whiteList['flex-flow'] = false; // default: depending on individual properties
  whiteList['flex-grow'] = false; // default: 0
  whiteList['flex-shrink'] = false; // default: 1
  whiteList['flex-wrap'] = false; // default: nowrap
  whiteList['float'] = false; // default: none
  whiteList['float-offset'] = false; // default: 0 0
  whiteList['flood-color'] = false; // default: black
  whiteList['flood-opacity'] = false; // default: 1
  whiteList['flow-from'] = false; // default: none
  whiteList['flow-into'] = false; // default: none
  whiteList['font'] = true; // default: depending on individual properties
  whiteList['font-family'] = true; // default: implementation dependent
  whiteList['font-feature-settings'] = true; // default: normal
  whiteList['font-kerning'] = true; // default: auto
  whiteList['font-language-override'] = true; // default: normal
  whiteList['font-size'] = true; // default: medium
  whiteList['font-size-adjust'] = true; // default: none
  whiteList['font-stretch'] = true; // default: normal
  whiteList['font-style'] = true; // default: normal
  whiteList['font-synthesis'] = true; // default: weight style
  whiteList['font-variant'] = true; // default: normal
  whiteList['font-variant-alternates'] = true; // default: normal
  whiteList['font-variant-caps'] = true; // default: normal
  whiteList['font-variant-east-asian'] = true; // default: normal
  whiteList['font-variant-ligatures'] = true; // default: normal
  whiteList['font-variant-numeric'] = true; // default: normal
  whiteList['font-variant-position'] = true; // default: normal
  whiteList['font-weight'] = true; // default: normal
  whiteList['grid'] = false; // default: depending on individual properties
  whiteList['grid-area'] = false; // default: depending on individual properties
  whiteList['grid-auto-columns'] = false; // default: auto
  whiteList['grid-auto-flow'] = false; // default: none
  whiteList['grid-auto-rows'] = false; // default: auto
  whiteList['grid-column'] = false; // default: depending on individual properties
  whiteList['grid-column-end'] = false; // default: auto
  whiteList['grid-column-start'] = false; // default: auto
  whiteList['grid-row'] = false; // default: depending on individual properties
  whiteList['grid-row-end'] = false; // default: auto
  whiteList['grid-row-start'] = false; // default: auto
  whiteList['grid-template'] = false; // default: depending on individual properties
  whiteList['grid-template-areas'] = false; // default: none
  whiteList['grid-template-columns'] = false; // default: none
  whiteList['grid-template-rows'] = false; // default: none
  whiteList['hanging-punctuation'] = false; // default: none
  whiteList['height'] = true; // default: auto
  whiteList['hyphens'] = false; // default: manual
  whiteList['icon'] = false; // default: auto
  whiteList['image-orientation'] = false; // default: auto
  whiteList['image-resolution'] = false; // default: normal
  whiteList['ime-mode'] = false; // default: auto
  whiteList['initial-letters'] = false; // default: normal
  whiteList['inline-box-align'] = false; // default: last
  whiteList['justify-content'] = false; // default: auto
  whiteList['justify-items'] = false; // default: auto
  whiteList['justify-self'] = false; // default: auto
  whiteList['left'] = false; // default: auto
  whiteList['letter-spacing'] = true; // default: normal
  whiteList['lighting-color'] = true; // default: white
  whiteList['line-box-contain'] = false; // default: block inline replaced
  whiteList['line-break'] = false; // default: auto
  whiteList['line-grid'] = false; // default: match-parent
  whiteList['line-height'] = false; // default: normal
  whiteList['line-snap'] = false; // default: none
  whiteList['line-stacking'] = false; // default: depending on individual properties
  whiteList['line-stacking-ruby'] = false; // default: exclude-ruby
  whiteList['line-stacking-shift'] = false; // default: consider-shifts
  whiteList['line-stacking-strategy'] = false; // default: inline-line-height
  whiteList['list-style'] = true; // default: depending on individual properties
  whiteList['list-style-image'] = true; // default: none
  whiteList['list-style-position'] = true; // default: outside
  whiteList['list-style-type'] = true; // default: disc
  whiteList['margin'] = true; // default: depending on individual properties
  whiteList['margin-bottom'] = true; // default: 0
  whiteList['margin-left'] = true; // default: 0
  whiteList['margin-right'] = true; // default: 0
  whiteList['margin-top'] = true; // default: 0
  whiteList['marker-offset'] = false; // default: auto
  whiteList['marker-side'] = false; // default: list-item
  whiteList['marks'] = false; // default: none
  whiteList['mask'] = false; // default: border-box
  whiteList['mask-box'] = false; // default: see individual properties
  whiteList['mask-box-outset'] = false; // default: 0
  whiteList['mask-box-repeat'] = false; // default: stretch
  whiteList['mask-box-slice'] = false; // default: 0 fill
  whiteList['mask-box-source'] = false; // default: none
  whiteList['mask-box-width'] = false; // default: auto
  whiteList['mask-clip'] = false; // default: border-box
  whiteList['mask-image'] = false; // default: none
  whiteList['mask-origin'] = false; // default: border-box
  whiteList['mask-position'] = false; // default: center
  whiteList['mask-repeat'] = false; // default: no-repeat
  whiteList['mask-size'] = false; // default: border-box
  whiteList['mask-source-type'] = false; // default: auto
  whiteList['mask-type'] = false; // default: luminance
  whiteList['max-height'] = true; // default: none
  whiteList['max-lines'] = false; // default: none
  whiteList['max-width'] = true; // default: none
  whiteList['min-height'] = true; // default: 0
  whiteList['min-width'] = true; // default: 0
  whiteList['move-to'] = false; // default: normal
  whiteList['nav-down'] = false; // default: auto
  whiteList['nav-index'] = false; // default: auto
  whiteList['nav-left'] = false; // default: auto
  whiteList['nav-right'] = false; // default: auto
  whiteList['nav-up'] = false; // default: auto
  whiteList['object-fit'] = false; // default: fill
  whiteList['object-position'] = false; // default: 50% 50%
  whiteList['opacity'] = false; // default: 1
  whiteList['order'] = false; // default: 0
  whiteList['orphans'] = false; // default: 2
  whiteList['outline'] = false; // default: depending on individual properties
  whiteList['outline-color'] = false; // default: invert
  whiteList['outline-offset'] = false; // default: 0
  whiteList['outline-style'] = false; // default: none
  whiteList['outline-width'] = false; // default: medium
  whiteList['overflow'] = false; // default: depending on individual properties
  whiteList['overflow-wrap'] = false; // default: normal
  whiteList['overflow-x'] = false; // default: visible
  whiteList['overflow-y'] = false; // default: visible
  whiteList['padding'] = true; // default: depending on individual properties
  whiteList['padding-bottom'] = true; // default: 0
  whiteList['padding-left'] = true; // default: 0
  whiteList['padding-right'] = true; // default: 0
  whiteList['padding-top'] = true; // default: 0
  whiteList['page'] = false; // default: auto
  whiteList['page-break-after'] = false; // default: auto
  whiteList['page-break-before'] = false; // default: auto
  whiteList['page-break-inside'] = false; // default: auto
  whiteList['page-policy'] = false; // default: start
  whiteList['pause'] = false; // default: implementation dependent
  whiteList['pause-after'] = false; // default: implementation dependent
  whiteList['pause-before'] = false; // default: implementation dependent
  whiteList['perspective'] = false; // default: none
  whiteList['perspective-origin'] = false; // default: 50% 50%
  whiteList['pitch'] = false; // default: medium
  whiteList['pitch-range'] = false; // default: 50
  whiteList['play-during'] = false; // default: auto
  whiteList['position'] = false; // default: static
  whiteList['presentation-level'] = false; // default: 0
  whiteList['quotes'] = false; // default: text
  whiteList['region-fragment'] = false; // default: auto
  whiteList['resize'] = false; // default: none
  whiteList['rest'] = false; // default: depending on individual properties
  whiteList['rest-after'] = false; // default: none
  whiteList['rest-before'] = false; // default: none
  whiteList['richness'] = false; // default: 50
  whiteList['right'] = false; // default: auto
  whiteList['rotation'] = false; // default: 0
  whiteList['rotation-point'] = false; // default: 50% 50%
  whiteList['ruby-align'] = false; // default: auto
  whiteList['ruby-merge'] = false; // default: separate
  whiteList['ruby-position'] = false; // default: before
  whiteList['shape-image-threshold'] = false; // default: 0.0
  whiteList['shape-outside'] = false; // default: none
  whiteList['shape-margin'] = false; // default: 0
  whiteList['size'] = false; // default: auto
  whiteList['speak'] = false; // default: auto
  whiteList['speak-as'] = false; // default: normal
  whiteList['speak-header'] = false; // default: once
  whiteList['speak-numeral'] = false; // default: continuous
  whiteList['speak-punctuation'] = false; // default: none
  whiteList['speech-rate'] = false; // default: medium
  whiteList['stress'] = false; // default: 50
  whiteList['string-set'] = false; // default: none
  whiteList['tab-size'] = false; // default: 8
  whiteList['table-layout'] = false; // default: auto
  whiteList['text-align'] = true; // default: start
  whiteList['text-align-last'] = true; // default: auto
  whiteList['text-combine-upright'] = true; // default: none
  whiteList['text-decoration'] = true; // default: none
  whiteList['text-decoration-color'] = true; // default: currentColor
  whiteList['text-decoration-line'] = true; // default: none
  whiteList['text-decoration-skip'] = true; // default: objects
  whiteList['text-decoration-style'] = true; // default: solid
  whiteList['text-emphasis'] = true; // default: depending on individual properties
  whiteList['text-emphasis-color'] = true; // default: currentColor
  whiteList['text-emphasis-position'] = true; // default: over right
  whiteList['text-emphasis-style'] = true; // default: none
  whiteList['text-height'] = true; // default: auto
  whiteList['text-indent'] = true; // default: 0
  whiteList['text-justify'] = true; // default: auto
  whiteList['text-orientation'] = true; // default: mixed
  whiteList['text-overflow'] = true; // default: clip
  whiteList['text-shadow'] = true; // default: none
  whiteList['text-space-collapse'] = true; // default: collapse
  whiteList['text-transform'] = true; // default: none
  whiteList['text-underline-position'] = true; // default: auto
  whiteList['text-wrap'] = true; // default: normal
  whiteList['top'] = false; // default: auto
  whiteList['transform'] = false; // default: none
  whiteList['transform-origin'] = false; // default: 50% 50% 0
  whiteList['transform-style'] = false; // default: flat
  whiteList['transition'] = false; // default: depending on individual properties
  whiteList['transition-delay'] = false; // default: 0s
  whiteList['transition-duration'] = false; // default: 0s
  whiteList['transition-property'] = false; // default: all
  whiteList['transition-timing-function'] = false; // default: ease
  whiteList['unicode-bidi'] = false; // default: normal
  whiteList['vertical-align'] = false; // default: baseline
  whiteList['visibility'] = false; // default: visible
  whiteList['voice-balance'] = false; // default: center
  whiteList['voice-duration'] = false; // default: auto
  whiteList['voice-family'] = false; // default: implementation dependent
  whiteList['voice-pitch'] = false; // default: medium
  whiteList['voice-range'] = false; // default: medium
  whiteList['voice-rate'] = false; // default: normal
  whiteList['voice-stress'] = false; // default: normal
  whiteList['voice-volume'] = false; // default: medium
  whiteList['volume'] = false; // default: medium
  whiteList['white-space'] = false; // default: normal
  whiteList['widows'] = false; // default: 2
  whiteList['width'] = true; // default: auto
  whiteList['will-change'] = false; // default: auto
  whiteList['word-break'] = true; // default: normal
  whiteList['word-spacing'] = true; // default: normal
  whiteList['word-wrap'] = true; // default: normal
  whiteList['wrap-flow'] = false; // default: auto
  whiteList['wrap-through'] = false; // default: wrap
  whiteList['writing-mode'] = false; // default: horizontal-tb
  whiteList['z-index'] = false; // default: auto

  return whiteList;
}


/**
 * 匹配到白名单上的一个属性时
 *
 * @param {String} name
 * @param {String} value
 * @param {Object} options
 * @return {String}
 */
function onAttr (name, value, options) {
  // do nothing
}

/**
 * 匹配到不在白名单上的一个属性时
 *
 * @param {String} name
 * @param {String} value
 * @param {Object} options
 * @return {String}
 */
function onIgnoreAttr (name, value, options) {
  // do nothing
}

var REGEXP_URL_JAVASCRIPT = /javascript\s*\:/img;

/**
 * 过滤属性值
 *
 * @param {String} name
 * @param {String} value
 * @return {String}
 */
function safeAttrValue(name, value) {
  if (REGEXP_URL_JAVASCRIPT.test(value)) return '';
  return value;
}


var whiteList = getDefaultWhiteList();
var getDefaultWhiteList_1 = getDefaultWhiteList;
var onAttr_1 = onAttr;
var onIgnoreAttr_1 = onIgnoreAttr;
var safeAttrValue_1 = safeAttrValue;

var _default = {
	whiteList: whiteList,
	getDefaultWhiteList: getDefaultWhiteList_1,
	onAttr: onAttr_1,
	onIgnoreAttr: onIgnoreAttr_1,
	safeAttrValue: safeAttrValue_1
};

var util = {
  indexOf: function (arr, item) {
    var i, j;
    if (Array.prototype.indexOf) {
      return arr.indexOf(item);
    }
    for (i = 0, j = arr.length; i < j; i++) {
      if (arr[i] === item) {
        return i;
      }
    }
    return -1;
  },
  forEach: function (arr, fn, scope) {
    var i, j;
    if (Array.prototype.forEach) {
      return arr.forEach(fn, scope);
    }
    for (i = 0, j = arr.length; i < j; i++) {
      fn.call(scope, arr[i], i, arr);
    }
  },
  trim: function (str) {
    if (String.prototype.trim) {
      return str.trim();
    }
    return str.replace(/(^\s*)|(\s*$)/g, '');
  },
  trimRight: function (str) {
    if (String.prototype.trimRight) {
      return str.trimRight();
    }
    return str.replace(/(\s*$)/g, '');
  }
};

/**
 * cssfilter
 *
 * @author 老雷<leizongmin@gmail.com>
 */




/**
 * 解析style
 *
 * @param {String} css
 * @param {Function} onAttr 处理属性的函数
 *   参数格式： function (sourcePosition, position, name, value, source)
 * @return {String}
 */
function parseStyle (css, onAttr) {
  css = util.trimRight(css);
  if (css[css.length - 1] !== ';') css += ';';
  var cssLength = css.length;
  var isParenthesisOpen = false;
  var lastPos = 0;
  var i = 0;
  var retCSS = '';

  function addNewAttr () {
    // 如果没有正常的闭合圆括号，则直接忽略当前属性
    if (!isParenthesisOpen) {
      var source = util.trim(css.slice(lastPos, i));
      var j = source.indexOf(':');
      if (j !== -1) {
        var name = util.trim(source.slice(0, j));
        var value = util.trim(source.slice(j + 1));
        // 必须有属性名称
        if (name) {
          var ret = onAttr(lastPos, retCSS.length, name, value, source);
          if (ret) retCSS += ret + '; ';
        }
      }
    }
    lastPos = i + 1;
  }

  for (; i < cssLength; i++) {
    var c = css[i];
    if (c === '/' && css[i + 1] === '*') {
      // 备注开始
      var j = css.indexOf('*/', i + 2);
      // 如果没有正常的备注结束，则后面的部分全部跳过
      if (j === -1) break;
      // 直接将当前位置调到备注结尾，并且初始化状态
      i = j + 1;
      lastPos = i + 1;
      isParenthesisOpen = false;
    } else if (c === '(') {
      isParenthesisOpen = true;
    } else if (c === ')') {
      isParenthesisOpen = false;
    } else if (c === ';') {
      if (isParenthesisOpen) ; else {
        addNewAttr();
      }
    } else if (c === '\n') {
      addNewAttr();
    }
  }

  return util.trim(retCSS);
}

var parser = parseStyle;

/**
 * cssfilter
 *
 * @author 老雷<leizongmin@gmail.com>
 */






/**
 * 返回值是否为空
 *
 * @param {Object} obj
 * @return {Boolean}
 */
function isNull (obj) {
  return (obj === undefined || obj === null);
}

/**
 * 浅拷贝对象
 *
 * @param {Object} obj
 * @return {Object}
 */
function shallowCopyObject (obj) {
  var ret = {};
  for (var i in obj) {
    ret[i] = obj[i];
  }
  return ret;
}

/**
 * 创建CSS过滤器
 *
 * @param {Object} options
 *   - {Object} whiteList
 *   - {Function} onAttr
 *   - {Function} onIgnoreAttr
 *   - {Function} safeAttrValue
 */
function FilterCSS (options) {
  options = shallowCopyObject(options || {});
  options.whiteList = options.whiteList || _default.whiteList;
  options.onAttr = options.onAttr || _default.onAttr;
  options.onIgnoreAttr = options.onIgnoreAttr || _default.onIgnoreAttr;
  options.safeAttrValue = options.safeAttrValue || _default.safeAttrValue;
  this.options = options;
}

FilterCSS.prototype.process = function (css) {
  // 兼容各种奇葩输入
  css = css || '';
  css = css.toString();
  if (!css) return '';

  var me = this;
  var options = me.options;
  var whiteList = options.whiteList;
  var onAttr = options.onAttr;
  var onIgnoreAttr = options.onIgnoreAttr;
  var safeAttrValue = options.safeAttrValue;

  var retCSS = parser(css, function (sourcePosition, position, name, value, source) {

    var check = whiteList[name];
    var isWhite = false;
    if (check === true) isWhite = check;
    else if (typeof check === 'function') isWhite = check(value);
    else if (check instanceof RegExp) isWhite = check.test(value);
    if (isWhite !== true) isWhite = false;

    // 如果过滤后 value 为空则直接忽略
    value = safeAttrValue(name, value);
    if (!value) return;

    var opts = {
      position: position,
      sourcePosition: sourcePosition,
      source: source,
      isWhite: isWhite
    };

    if (isWhite) {

      var ret = onAttr(name, value, opts);
      if (isNull(ret)) {
        return name + ':' + value;
      } else {
        return ret;
      }

    } else {

      var ret = onIgnoreAttr(name, value, opts);
      if (!isNull(ret)) {
        return ret;
      }

    }
  });

  return retCSS;
};


var css$1 = FilterCSS;

var lib = createCommonjsModule(function (module, exports) {
/**
 * cssfilter
 *
 * @author 老雷<leizongmin@gmail.com>
 */





/**
 * XSS过滤
 *
 * @param {String} css 要过滤的CSS代码
 * @param {Object} options 选项：whiteList, onAttr, onIgnoreAttr
 * @return {String}
 */
function filterCSS (html, options) {
  var xss = new css$1(options);
  return xss.process(html);
}


// 输出
exports = module.exports = filterCSS;
exports.FilterCSS = css$1;
for (var i in _default) exports[i] = _default[i];

// 在浏览器端使用
if (typeof window !== 'undefined') {
  window.filterCSS = module.exports;
}
});
var lib_1 = lib.FilterCSS;

var util$1 = {
  indexOf: function(arr, item) {
    var i, j;
    if (Array.prototype.indexOf) {
      return arr.indexOf(item);
    }
    for (i = 0, j = arr.length; i < j; i++) {
      if (arr[i] === item) {
        return i;
      }
    }
    return -1;
  },
  forEach: function(arr, fn, scope) {
    var i, j;
    if (Array.prototype.forEach) {
      return arr.forEach(fn, scope);
    }
    for (i = 0, j = arr.length; i < j; i++) {
      fn.call(scope, arr[i], i, arr);
    }
  },
  trim: function(str) {
    if (String.prototype.trim) {
      return str.trim();
    }
    return str.replace(/(^\s*)|(\s*$)/g, "");
  },
  spaceIndex: function(str) {
    var reg = /\s|\n|\t/;
    var match = reg.exec(str);
    return match ? match.index : -1;
  }
};

/**
 * default settings
 *
 * @author Zongmin Lei<leizongmin@gmail.com>
 */

var FilterCSS$1 = lib.FilterCSS;
var getDefaultCSSWhiteList = lib.getDefaultWhiteList;


function getDefaultWhiteList$1() {
  return {
    a: ["target", "href", "title"],
    abbr: ["title"],
    address: [],
    area: ["shape", "coords", "href", "alt"],
    article: [],
    aside: [],
    audio: ["autoplay", "controls", "loop", "preload", "src"],
    b: [],
    bdi: ["dir"],
    bdo: ["dir"],
    big: [],
    blockquote: ["cite"],
    br: [],
    caption: [],
    center: [],
    cite: [],
    code: [],
    col: ["align", "valign", "span", "width"],
    colgroup: ["align", "valign", "span", "width"],
    dd: [],
    del: ["datetime"],
    details: ["open"],
    div: [],
    dl: [],
    dt: [],
    em: [],
    font: ["color", "size", "face"],
    footer: [],
    h1: [],
    h2: [],
    h3: [],
    h4: [],
    h5: [],
    h6: [],
    header: [],
    hr: [],
    i: [],
    img: ["src", "alt", "title", "width", "height"],
    ins: ["datetime"],
    li: [],
    mark: [],
    nav: [],
    ol: [],
    p: [],
    pre: [],
    s: [],
    section: [],
    small: [],
    span: [],
    sub: [],
    sup: [],
    strong: [],
    table: ["width", "border", "align", "valign"],
    tbody: ["align", "valign"],
    td: ["width", "rowspan", "colspan", "align", "valign"],
    tfoot: ["align", "valign"],
    th: ["width", "rowspan", "colspan", "align", "valign"],
    thead: ["align", "valign"],
    tr: ["rowspan", "align", "valign"],
    tt: [],
    u: [],
    ul: [],
    video: ["autoplay", "controls", "loop", "preload", "src", "height", "width"]
  };
}

var defaultCSSFilter = new FilterCSS$1();

/**
 * default onTag function
 *
 * @param {String} tag
 * @param {String} html
 * @param {Object} options
 * @return {String}
 */
function onTag(tag, html, options) {
  // do nothing
}

/**
 * default onIgnoreTag function
 *
 * @param {String} tag
 * @param {String} html
 * @param {Object} options
 * @return {String}
 */
function onIgnoreTag(tag, html, options) {
  // do nothing
}

/**
 * default onTagAttr function
 *
 * @param {String} tag
 * @param {String} name
 * @param {String} value
 * @return {String}
 */
function onTagAttr(tag, name, value) {
  // do nothing
}

/**
 * default onIgnoreTagAttr function
 *
 * @param {String} tag
 * @param {String} name
 * @param {String} value
 * @return {String}
 */
function onIgnoreTagAttr(tag, name, value) {
  // do nothing
}

/**
 * default escapeHtml function
 *
 * @param {String} html
 */
function escapeHtml(html) {
  return html.replace(REGEXP_LT, "&lt;").replace(REGEXP_GT, "&gt;");
}

/**
 * default safeAttrValue function
 *
 * @param {String} tag
 * @param {String} name
 * @param {String} value
 * @param {Object} cssFilter
 * @return {String}
 */
function safeAttrValue$1(tag, name, value, cssFilter) {
  // unescape attribute value firstly
  value = friendlyAttrValue(value);

  if (name === "href" || name === "src") {
    // filter `href` and `src` attribute
    // only allow the value that starts with `http://` | `https://` | `mailto:` | `/` | `#`
    value = util$1.trim(value);
    if (value === "#") return "#";
    if (
      !(
        value.substr(0, 7) === "http://" ||
        value.substr(0, 8) === "https://" ||
        value.substr(0, 7) === "mailto:" ||
        value.substr(0, 4) === "tel:" ||
        value[0] === "#" ||
        value[0] === "/"
      )
    ) {
      return "";
    }
  } else if (name === "background") {
    // filter `background` attribute (maybe no use)
    // `javascript:`
    REGEXP_DEFAULT_ON_TAG_ATTR_4.lastIndex = 0;
    if (REGEXP_DEFAULT_ON_TAG_ATTR_4.test(value)) {
      return "";
    }
  } else if (name === "style") {
    // `expression()`
    REGEXP_DEFAULT_ON_TAG_ATTR_7.lastIndex = 0;
    if (REGEXP_DEFAULT_ON_TAG_ATTR_7.test(value)) {
      return "";
    }
    // `url()`
    REGEXP_DEFAULT_ON_TAG_ATTR_8.lastIndex = 0;
    if (REGEXP_DEFAULT_ON_TAG_ATTR_8.test(value)) {
      REGEXP_DEFAULT_ON_TAG_ATTR_4.lastIndex = 0;
      if (REGEXP_DEFAULT_ON_TAG_ATTR_4.test(value)) {
        return "";
      }
    }
    if (cssFilter !== false) {
      cssFilter = cssFilter || defaultCSSFilter;
      value = cssFilter.process(value);
    }
  }

  // escape `<>"` before returns
  value = escapeAttrValue(value);
  return value;
}

// RegExp list
var REGEXP_LT = /</g;
var REGEXP_GT = />/g;
var REGEXP_QUOTE = /"/g;
var REGEXP_QUOTE_2 = /&quot;/g;
var REGEXP_ATTR_VALUE_1 = /&#([a-zA-Z0-9]*);?/gim;
var REGEXP_ATTR_VALUE_COLON = /&colon;?/gim;
var REGEXP_ATTR_VALUE_NEWLINE = /&newline;?/gim;
var REGEXP_DEFAULT_ON_TAG_ATTR_4 = /((j\s*a\s*v\s*a|v\s*b|l\s*i\s*v\s*e)\s*s\s*c\s*r\s*i\s*p\s*t\s*|m\s*o\s*c\s*h\s*a)\:/gi;
var REGEXP_DEFAULT_ON_TAG_ATTR_7 = /e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n\s*\(.*/gi;
var REGEXP_DEFAULT_ON_TAG_ATTR_8 = /u\s*r\s*l\s*\(.*/gi;

/**
 * escape doube quote
 *
 * @param {String} str
 * @return {String} str
 */
function escapeQuote(str) {
  return str.replace(REGEXP_QUOTE, "&quot;");
}

/**
 * unescape double quote
 *
 * @param {String} str
 * @return {String} str
 */
function unescapeQuote(str) {
  return str.replace(REGEXP_QUOTE_2, '"');
}

/**
 * escape html entities
 *
 * @param {String} str
 * @return {String}
 */
function escapeHtmlEntities(str) {
  return str.replace(REGEXP_ATTR_VALUE_1, function replaceUnicode(str, code) {
    return code[0] === "x" || code[0] === "X"
      ? String.fromCharCode(parseInt(code.substr(1), 16))
      : String.fromCharCode(parseInt(code, 10));
  });
}

/**
 * escape html5 new danger entities
 *
 * @param {String} str
 * @return {String}
 */
function escapeDangerHtml5Entities(str) {
  return str
    .replace(REGEXP_ATTR_VALUE_COLON, ":")
    .replace(REGEXP_ATTR_VALUE_NEWLINE, " ");
}

/**
 * clear nonprintable characters
 *
 * @param {String} str
 * @return {String}
 */
function clearNonPrintableCharacter(str) {
  var str2 = "";
  for (var i = 0, len = str.length; i < len; i++) {
    str2 += str.charCodeAt(i) < 32 ? " " : str.charAt(i);
  }
  return util$1.trim(str2);
}

/**
 * get friendly attribute value
 *
 * @param {String} str
 * @return {String}
 */
function friendlyAttrValue(str) {
  str = unescapeQuote(str);
  str = escapeHtmlEntities(str);
  str = escapeDangerHtml5Entities(str);
  str = clearNonPrintableCharacter(str);
  return str;
}

/**
 * unescape attribute value
 *
 * @param {String} str
 * @return {String}
 */
function escapeAttrValue(str) {
  str = escapeQuote(str);
  str = escapeHtml(str);
  return str;
}

/**
 * `onIgnoreTag` function for removing all the tags that are not in whitelist
 */
function onIgnoreTagStripAll() {
  return "";
}

/**
 * remove tag body
 * specify a `tags` list, if the tag is not in the `tags` list then process by the specify function (optional)
 *
 * @param {array} tags
 * @param {function} next
 */
function StripTagBody(tags, next) {
  if (typeof next !== "function") {
    next = function() {};
  }

  var isRemoveAllTag = !Array.isArray(tags);
  function isRemoveTag(tag) {
    if (isRemoveAllTag) return true;
    return util$1.indexOf(tags, tag) !== -1;
  }

  var removeList = [];
  var posStart = false;

  return {
    onIgnoreTag: function(tag, html, options) {
      if (isRemoveTag(tag)) {
        if (options.isClosing) {
          var ret = "[/removed]";
          var end = options.position + ret.length;
          removeList.push([
            posStart !== false ? posStart : options.position,
            end
          ]);
          posStart = false;
          return ret;
        } else {
          if (!posStart) {
            posStart = options.position;
          }
          return "[removed]";
        }
      } else {
        return next(tag, html, options);
      }
    },
    remove: function(html) {
      var rethtml = "";
      var lastPos = 0;
      util$1.forEach(removeList, function(pos) {
        rethtml += html.slice(lastPos, pos[0]);
        lastPos = pos[1];
      });
      rethtml += html.slice(lastPos);
      return rethtml;
    }
  };
}

/**
 * remove html comments
 *
 * @param {String} html
 * @return {String}
 */
function stripCommentTag(html) {
  return html.replace(STRIP_COMMENT_TAG_REGEXP, "");
}
var STRIP_COMMENT_TAG_REGEXP = /<!--[\s\S]*?-->/g;

/**
 * remove invisible characters
 *
 * @param {String} html
 * @return {String}
 */
function stripBlankChar(html) {
  var chars = html.split("");
  chars = chars.filter(function(char) {
    var c = char.charCodeAt(0);
    if (c === 127) return false;
    if (c <= 31) {
      if (c === 10 || c === 13) return true;
      return false;
    }
    return true;
  });
  return chars.join("");
}

var whiteList$1 = getDefaultWhiteList$1();
var getDefaultWhiteList_1$1 = getDefaultWhiteList$1;
var onTag_1 = onTag;
var onIgnoreTag_1 = onIgnoreTag;
var onTagAttr_1 = onTagAttr;
var onIgnoreTagAttr_1 = onIgnoreTagAttr;
var safeAttrValue_1$1 = safeAttrValue$1;
var escapeHtml_1 = escapeHtml;
var escapeQuote_1 = escapeQuote;
var unescapeQuote_1 = unescapeQuote;
var escapeHtmlEntities_1 = escapeHtmlEntities;
var escapeDangerHtml5Entities_1 = escapeDangerHtml5Entities;
var clearNonPrintableCharacter_1 = clearNonPrintableCharacter;
var friendlyAttrValue_1 = friendlyAttrValue;
var escapeAttrValue_1 = escapeAttrValue;
var onIgnoreTagStripAll_1 = onIgnoreTagStripAll;
var StripTagBody_1 = StripTagBody;
var stripCommentTag_1 = stripCommentTag;
var stripBlankChar_1 = stripBlankChar;
var cssFilter = defaultCSSFilter;
var getDefaultCSSWhiteList_1 = getDefaultCSSWhiteList;

var _default$1 = {
	whiteList: whiteList$1,
	getDefaultWhiteList: getDefaultWhiteList_1$1,
	onTag: onTag_1,
	onIgnoreTag: onIgnoreTag_1,
	onTagAttr: onTagAttr_1,
	onIgnoreTagAttr: onIgnoreTagAttr_1,
	safeAttrValue: safeAttrValue_1$1,
	escapeHtml: escapeHtml_1,
	escapeQuote: escapeQuote_1,
	unescapeQuote: unescapeQuote_1,
	escapeHtmlEntities: escapeHtmlEntities_1,
	escapeDangerHtml5Entities: escapeDangerHtml5Entities_1,
	clearNonPrintableCharacter: clearNonPrintableCharacter_1,
	friendlyAttrValue: friendlyAttrValue_1,
	escapeAttrValue: escapeAttrValue_1,
	onIgnoreTagStripAll: onIgnoreTagStripAll_1,
	StripTagBody: StripTagBody_1,
	stripCommentTag: stripCommentTag_1,
	stripBlankChar: stripBlankChar_1,
	cssFilter: cssFilter,
	getDefaultCSSWhiteList: getDefaultCSSWhiteList_1
};

/**
 * Simple HTML Parser
 *
 * @author Zongmin Lei<leizongmin@gmail.com>
 */



/**
 * get tag name
 *
 * @param {String} html e.g. '<a hef="#">'
 * @return {String}
 */
function getTagName(html) {
  var i = util$1.spaceIndex(html);
  if (i === -1) {
    var tagName = html.slice(1, -1);
  } else {
    var tagName = html.slice(1, i + 1);
  }
  tagName = util$1.trim(tagName).toLowerCase();
  if (tagName.slice(0, 1) === "/") tagName = tagName.slice(1);
  if (tagName.slice(-1) === "/") tagName = tagName.slice(0, -1);
  return tagName;
}

/**
 * is close tag?
 *
 * @param {String} html 如：'<a hef="#">'
 * @return {Boolean}
 */
function isClosing(html) {
  return html.slice(0, 2) === "</";
}

/**
 * parse input html and returns processed html
 *
 * @param {String} html
 * @param {Function} onTag e.g. function (sourcePosition, position, tag, html, isClosing)
 * @param {Function} escapeHtml
 * @return {String}
 */
function parseTag(html, onTag, escapeHtml) {
  "user strict";

  var rethtml = "";
  var lastPos = 0;
  var tagStart = false;
  var quoteStart = false;
  var currentPos = 0;
  var len = html.length;
  var currentTagName = "";
  var currentHtml = "";

  for (currentPos = 0; currentPos < len; currentPos++) {
    var c = html.charAt(currentPos);
    if (tagStart === false) {
      if (c === "<") {
        tagStart = currentPos;
        continue;
      }
    } else {
      if (quoteStart === false) {
        if (c === "<") {
          rethtml += escapeHtml(html.slice(lastPos, currentPos));
          tagStart = currentPos;
          lastPos = currentPos;
          continue;
        }
        if (c === ">") {
          rethtml += escapeHtml(html.slice(lastPos, tagStart));
          currentHtml = html.slice(tagStart, currentPos + 1);
          currentTagName = getTagName(currentHtml);
          rethtml += onTag(
            tagStart,
            rethtml.length,
            currentTagName,
            currentHtml,
            isClosing(currentHtml)
          );
          lastPos = currentPos + 1;
          tagStart = false;
          continue;
        }
        if ((c === '"' || c === "'") && html.charAt(currentPos - 1) === "=") {
          quoteStart = c;
          continue;
        }
      } else {
        if (c === quoteStart) {
          quoteStart = false;
          continue;
        }
      }
    }
  }
  if (lastPos < html.length) {
    rethtml += escapeHtml(html.substr(lastPos));
  }

  return rethtml;
}

var REGEXP_ILLEGAL_ATTR_NAME = /[^a-zA-Z0-9_:\.\-]/gim;

/**
 * parse input attributes and returns processed attributes
 *
 * @param {String} html e.g. `href="#" target="_blank"`
 * @param {Function} onAttr e.g. `function (name, value)`
 * @return {String}
 */
function parseAttr(html, onAttr) {
  "user strict";

  var lastPos = 0;
  var retAttrs = [];
  var tmpName = false;
  var len = html.length;

  function addAttr(name, value) {
    name = util$1.trim(name);
    name = name.replace(REGEXP_ILLEGAL_ATTR_NAME, "").toLowerCase();
    if (name.length < 1) return;
    var ret = onAttr(name, value || "");
    if (ret) retAttrs.push(ret);
  }

  // 逐个分析字符
  for (var i = 0; i < len; i++) {
    var c = html.charAt(i);
    var v, j;
    if (tmpName === false && c === "=") {
      tmpName = html.slice(lastPos, i);
      lastPos = i + 1;
      continue;
    }
    if (tmpName !== false) {
      if (
        i === lastPos &&
        (c === '"' || c === "'") &&
        html.charAt(i - 1) === "="
      ) {
        j = html.indexOf(c, i + 1);
        if (j === -1) {
          break;
        } else {
          v = util$1.trim(html.slice(lastPos + 1, j));
          addAttr(tmpName, v);
          tmpName = false;
          i = j;
          lastPos = i + 1;
          continue;
        }
      }
    }
    if (/\s|\n|\t/.test(c)) {
      html = html.replace(/\s|\n|\t/g, " ");
      if (tmpName === false) {
        j = findNextEqual(html, i);
        if (j === -1) {
          v = util$1.trim(html.slice(lastPos, i));
          addAttr(v);
          tmpName = false;
          lastPos = i + 1;
          continue;
        } else {
          i = j - 1;
          continue;
        }
      } else {
        j = findBeforeEqual(html, i - 1);
        if (j === -1) {
          v = util$1.trim(html.slice(lastPos, i));
          v = stripQuoteWrap(v);
          addAttr(tmpName, v);
          tmpName = false;
          lastPos = i + 1;
          continue;
        } else {
          continue;
        }
      }
    }
  }

  if (lastPos < html.length) {
    if (tmpName === false) {
      addAttr(html.slice(lastPos));
    } else {
      addAttr(tmpName, stripQuoteWrap(util$1.trim(html.slice(lastPos))));
    }
  }

  return util$1.trim(retAttrs.join(" "));
}

function findNextEqual(str, i) {
  for (; i < str.length; i++) {
    var c = str[i];
    if (c === " ") continue;
    if (c === "=") return i;
    return -1;
  }
}

function findBeforeEqual(str, i) {
  for (; i > 0; i--) {
    var c = str[i];
    if (c === " ") continue;
    if (c === "=") return i;
    return -1;
  }
}

function isQuoteWrapString(text) {
  if (
    (text[0] === '"' && text[text.length - 1] === '"') ||
    (text[0] === "'" && text[text.length - 1] === "'")
  ) {
    return true;
  } else {
    return false;
  }
}

function stripQuoteWrap(text) {
  if (isQuoteWrapString(text)) {
    return text.substr(1, text.length - 2);
  } else {
    return text;
  }
}

var parseTag_1 = parseTag;
var parseAttr_1 = parseAttr;

var parser$1 = {
	parseTag: parseTag_1,
	parseAttr: parseAttr_1
};

/**
 * filter xss
 *
 * @author Zongmin Lei<leizongmin@gmail.com>
 */

var FilterCSS$2 = lib.FilterCSS;


var parseTag$1 = parser$1.parseTag;
var parseAttr$1 = parser$1.parseAttr;


/**
 * returns `true` if the input value is `undefined` or `null`
 *
 * @param {Object} obj
 * @return {Boolean}
 */
function isNull$1(obj) {
  return obj === undefined || obj === null;
}

/**
 * get attributes for a tag
 *
 * @param {String} html
 * @return {Object}
 *   - {String} html
 *   - {Boolean} closing
 */
function getAttrs(html) {
  var i = util$1.spaceIndex(html);
  if (i === -1) {
    return {
      html: "",
      closing: html[html.length - 2] === "/"
    };
  }
  html = util$1.trim(html.slice(i + 1, -1));
  var isClosing = html[html.length - 1] === "/";
  if (isClosing) html = util$1.trim(html.slice(0, -1));
  return {
    html: html,
    closing: isClosing
  };
}

/**
 * shallow copy
 *
 * @param {Object} obj
 * @return {Object}
 */
function shallowCopyObject$1(obj) {
  var ret = {};
  for (var i in obj) {
    ret[i] = obj[i];
  }
  return ret;
}

/**
 * FilterXSS class
 *
 * @param {Object} options
 *        whiteList, onTag, onTagAttr, onIgnoreTag,
 *        onIgnoreTagAttr, safeAttrValue, escapeHtml
 *        stripIgnoreTagBody, allowCommentTag, stripBlankChar
 *        css{whiteList, onAttr, onIgnoreAttr} `css=false` means don't use `cssfilter`
 */
function FilterXSS(options) {
  options = shallowCopyObject$1(options || {});

  if (options.stripIgnoreTag) {
    if (options.onIgnoreTag) {
      console.error(
        'Notes: cannot use these two options "stripIgnoreTag" and "onIgnoreTag" at the same time'
      );
    }
    options.onIgnoreTag = _default$1.onIgnoreTagStripAll;
  }

  options.whiteList = options.whiteList || _default$1.whiteList;
  options.onTag = options.onTag || _default$1.onTag;
  options.onTagAttr = options.onTagAttr || _default$1.onTagAttr;
  options.onIgnoreTag = options.onIgnoreTag || _default$1.onIgnoreTag;
  options.onIgnoreTagAttr = options.onIgnoreTagAttr || _default$1.onIgnoreTagAttr;
  options.safeAttrValue = options.safeAttrValue || _default$1.safeAttrValue;
  options.escapeHtml = options.escapeHtml || _default$1.escapeHtml;
  this.options = options;

  if (options.css === false) {
    this.cssFilter = false;
  } else {
    options.css = options.css || {};
    this.cssFilter = new FilterCSS$2(options.css);
  }
}

/**
 * start process and returns result
 *
 * @param {String} html
 * @return {String}
 */
FilterXSS.prototype.process = function(html) {
  // compatible with the input
  html = html || "";
  html = html.toString();
  if (!html) return "";

  var me = this;
  var options = me.options;
  var whiteList = options.whiteList;
  var onTag = options.onTag;
  var onIgnoreTag = options.onIgnoreTag;
  var onTagAttr = options.onTagAttr;
  var onIgnoreTagAttr = options.onIgnoreTagAttr;
  var safeAttrValue = options.safeAttrValue;
  var escapeHtml = options.escapeHtml;
  var cssFilter = me.cssFilter;

  // remove invisible characters
  if (options.stripBlankChar) {
    html = _default$1.stripBlankChar(html);
  }

  // remove html comments
  if (!options.allowCommentTag) {
    html = _default$1.stripCommentTag(html);
  }

  // if enable stripIgnoreTagBody
  var stripIgnoreTagBody = false;
  if (options.stripIgnoreTagBody) {
    var stripIgnoreTagBody = _default$1.StripTagBody(
      options.stripIgnoreTagBody,
      onIgnoreTag
    );
    onIgnoreTag = stripIgnoreTagBody.onIgnoreTag;
  }

  var retHtml = parseTag$1(
    html,
    function(sourcePosition, position, tag, html, isClosing) {
      var info = {
        sourcePosition: sourcePosition,
        position: position,
        isClosing: isClosing,
        isWhite: whiteList.hasOwnProperty(tag)
      };

      // call `onTag()`
      var ret = onTag(tag, html, info);
      if (!isNull$1(ret)) return ret;

      if (info.isWhite) {
        if (info.isClosing) {
          return "</" + tag + ">";
        }

        var attrs = getAttrs(html);
        var whiteAttrList = whiteList[tag];
        var attrsHtml = parseAttr$1(attrs.html, function(name, value) {
          // call `onTagAttr()`
          var isWhiteAttr = util$1.indexOf(whiteAttrList, name) !== -1;
          var ret = onTagAttr(tag, name, value, isWhiteAttr);
          if (!isNull$1(ret)) return ret;

          if (isWhiteAttr) {
            // call `safeAttrValue()`
            value = safeAttrValue(tag, name, value, cssFilter);
            if (value) {
              return name + '="' + value + '"';
            } else {
              return name;
            }
          } else {
            // call `onIgnoreTagAttr()`
            var ret = onIgnoreTagAttr(tag, name, value, isWhiteAttr);
            if (!isNull$1(ret)) return ret;
            return;
          }
        });

        // build new tag html
        var html = "<" + tag;
        if (attrsHtml) html += " " + attrsHtml;
        if (attrs.closing) html += " /";
        html += ">";
        return html;
      } else {
        // call `onIgnoreTag()`
        var ret = onIgnoreTag(tag, html, info);
        if (!isNull$1(ret)) return ret;
        return escapeHtml(html);
      }
    },
    escapeHtml
  );

  // if enable stripIgnoreTagBody
  if (stripIgnoreTagBody) {
    retHtml = stripIgnoreTagBody.remove(retHtml);
  }

  return retHtml;
};

var xss = FilterXSS;

var lib$1 = createCommonjsModule(function (module, exports) {
/**
 * xss
 *
 * @author Zongmin Lei<leizongmin@gmail.com>
 */





/**
 * filter xss function
 *
 * @param {String} html
 * @param {Object} options { whiteList, onTag, onTagAttr, onIgnoreTag, onIgnoreTagAttr, safeAttrValue, escapeHtml }
 * @return {String}
 */
function filterXSS(html, options) {
  var xss$1 = new xss(options);
  return xss$1.process(html);
}

exports = module.exports = filterXSS;
exports.filterXSS = filterXSS;
exports.FilterXSS = xss;
for (var i in _default$1) exports[i] = _default$1[i];
for (var i in parser$1) exports[i] = parser$1[i];

// using `xss` on the browser, output `filterXSS` to the globals
if (typeof window !== "undefined") {
  window.filterXSS = module.exports;
}

// using `xss` on the WebWorker, output `filterXSS` to the globals
function isWorkerEnv() {
  return typeof self !== 'undefined' && typeof DedicatedWorkerGlobalScope !== 'undefined' && self instanceof DedicatedWorkerGlobalScope;
}
if (isWorkerEnv()) {
  self.filterXSS = module.exports;
}
});
var lib_1$1 = lib$1.filterXSS;
var lib_2 = lib$1.FilterXSS;

/**
 * lodash (Custom Build) <https://lodash.com/>
 * Build: `lodash modularize exports="npm" -o ./`
 * Copyright jQuery Foundation and other contributors <https://jquery.org/>
 * Released under MIT license <https://lodash.com/license>
 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
 */

/** Used as references for various `Number` constants. */
var MAX_SAFE_INTEGER = 9007199254740991;

/** `Object#toString` result references. */
var argsTag = '[object Arguments]',
    funcTag = '[object Function]',
    genTag = '[object GeneratorFunction]',
    mapTag = '[object Map]',
    objectTag = '[object Object]',
    promiseTag = '[object Promise]',
    setTag = '[object Set]',
    stringTag = '[object String]',
    weakMapTag = '[object WeakMap]';

var dataViewTag = '[object DataView]';

/**
 * Used to match `RegExp`
 * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
 */
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;

/** Used to detect host constructors (Safari). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;

/** Used to detect unsigned integer values. */
var reIsUint = /^(?:0|[1-9]\d*)$/;

/** Used to compose unicode character classes. */
var rsAstralRange = '\\ud800-\\udfff',
    rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23',
    rsComboSymbolsRange = '\\u20d0-\\u20f0',
    rsVarRange = '\\ufe0e\\ufe0f';

/** Used to compose unicode capture groups. */
var rsAstral = '[' + rsAstralRange + ']',
    rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']',
    rsFitz = '\\ud83c[\\udffb-\\udfff]',
    rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
    rsNonAstral = '[^' + rsAstralRange + ']',
    rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
    rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
    rsZWJ = '\\u200d';

/** Used to compose unicode regexes. */
var reOptMod = rsModifier + '?',
    rsOptVar = '[' + rsVarRange + ']?',
    rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
    rsSeq = rsOptVar + reOptMod + rsOptJoin,
    rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';

/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');

/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange  + rsComboMarksRange + rsComboSymbolsRange + rsVarRange + ']');

/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;

/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;

/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();

/**
 * A specialized version of `_.map` for arrays without support for iteratee
 * shorthands.
 *
 * @private
 * @param {Array} [array] The array to iterate over.
 * @param {Function} iteratee The function invoked per iteration.
 * @returns {Array} Returns the new mapped array.
 */
function arrayMap(array, iteratee) {
  var index = -1,
      length = array ? array.length : 0,
      result = Array(length);

  while (++index < length) {
    result[index] = iteratee(array[index], index, array);
  }
  return result;
}

/**
 * Converts an ASCII `string` to an array.
 *
 * @private
 * @param {string} string The string to convert.
 * @returns {Array} Returns the converted array.
 */
function asciiToArray(string) {
  return string.split('');
}

/**
 * The base implementation of `_.times` without support for iteratee shorthands
 * or max array length checks.
 *
 * @private
 * @param {number} n The number of times to invoke `iteratee`.
 * @param {Function} iteratee The function invoked per iteration.
 * @returns {Array} Returns the array of results.
 */
function baseTimes(n, iteratee) {
  var index = -1,
      result = Array(n);

  while (++index < n) {
    result[index] = iteratee(index);
  }
  return result;
}

/**
 * The base implementation of `_.values` and `_.valuesIn` which creates an
 * array of `object` property values corresponding to the property names
 * of `props`.
 *
 * @private
 * @param {Object} object The object to query.
 * @param {Array} props The property names to get values for.
 * @returns {Object} Returns the array of property values.
 */
function baseValues(object, props) {
  return arrayMap(props, function(key) {
    return object[key];
  });
}

/**
 * Gets the value at `key` of `object`.
 *
 * @private
 * @param {Object} [object] The object to query.
 * @param {string} key The key of the property to get.
 * @returns {*} Returns the property value.
 */
function getValue(object, key) {
  return object == null ? undefined : object[key];
}

/**
 * Checks if `string` contains Unicode symbols.
 *
 * @private
 * @param {string} string The string to inspect.
 * @returns {boolean} Returns `true` if a symbol is found, else `false`.
 */
function hasUnicode(string) {
  return reHasUnicode.test(string);
}

/**
 * Checks if `value` is a host object in IE < 9.
 *
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
 */
function isHostObject(value) {
  // Many host objects are `Object` objects that can coerce to strings
  // despite having improperly defined `toString` methods.
  var result = false;
  if (value != null && typeof value.toString != 'function') {
    try {
      result = !!(value + '');
    } catch (e) {}
  }
  return result;
}

/**
 * Converts `iterator` to an array.
 *
 * @private
 * @param {Object} iterator The iterator to convert.
 * @returns {Array} Returns the converted array.
 */
function iteratorToArray(iterator) {
  var data,
      result = [];

  while (!(data = iterator.next()).done) {
    result.push(data.value);
  }
  return result;
}

/**
 * Converts `map` to its key-value pairs.
 *
 * @private
 * @param {Object} map The map to convert.
 * @returns {Array} Returns the key-value pairs.
 */
function mapToArray(map) {
  var index = -1,
      result = Array(map.size);

  map.forEach(function(value, key) {
    result[++index] = [key, value];
  });
  return result;
}

/**
 * Creates a unary function that invokes `func` with its argument transformed.
 *
 * @private
 * @param {Function} func The function to wrap.
 * @param {Function} transform The argument transform.
 * @returns {Function} Returns the new function.
 */
function overArg(func, transform) {
  return function(arg) {
    return func(transform(arg));
  };
}

/**
 * Converts `set` to an array of its values.
 *
 * @private
 * @param {Object} set The set to convert.
 * @returns {Array} Returns the values.
 */
function setToArray(set) {
  var index = -1,
      result = Array(set.size);

  set.forEach(function(value) {
    result[++index] = value;
  });
  return result;
}

/**
 * Converts `string` to an array.
 *
 * @private
 * @param {string} string The string to convert.
 * @returns {Array} Returns the converted array.
 */
function stringToArray(string) {
  return hasUnicode(string)
    ? unicodeToArray(string)
    : asciiToArray(string);
}

/**
 * Converts a Unicode `string` to an array.
 *
 * @private
 * @param {string} string The string to convert.
 * @returns {Array} Returns the converted array.
 */
function unicodeToArray(string) {
  return string.match(reUnicode) || [];
}

/** Used for built-in method references. */
var funcProto = Function.prototype,
    objectProto = Object.prototype;

/** Used to detect overreaching core-js shims. */
var coreJsData = root['__core-js_shared__'];

/** Used to detect methods masquerading as native. */
var maskSrcKey = (function() {
  var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
  return uid ? ('Symbol(src)_1.' + uid) : '';
}());

/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;

/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;

/**
 * Used to resolve the
 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
 * of values.
 */
var objectToString = objectProto.toString;

/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
  funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);

/** Built-in value references. */
var Symbol$1 = root.Symbol,
    iteratorSymbol = Symbol$1 ? Symbol$1.iterator : undefined,
    propertyIsEnumerable = objectProto.propertyIsEnumerable;

/* Built-in method references for those with the same name as other `lodash` methods. */
var nativeKeys = overArg(Object.keys, Object);

/* Built-in method references that are verified to be native. */
var DataView = getNative(root, 'DataView'),
    Map$1 = getNative(root, 'Map'),
    Promise$1 = getNative(root, 'Promise'),
    Set$1 = getNative(root, 'Set'),
    WeakMap$1 = getNative(root, 'WeakMap');

/** Used to detect maps, sets, and weakmaps. */
var dataViewCtorString = toSource(DataView),
    mapCtorString = toSource(Map$1),
    promiseCtorString = toSource(Promise$1),
    setCtorString = toSource(Set$1),
    weakMapCtorString = toSource(WeakMap$1);

/**
 * Creates an array of the enumerable property names of the array-like `value`.
 *
 * @private
 * @param {*} value The value to query.
 * @param {boolean} inherited Specify returning inherited property names.
 * @returns {Array} Returns the array of property names.
 */
function arrayLikeKeys(value, inherited) {
  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
  // Safari 9 makes `arguments.length` enumerable in strict mode.
  var result = (isArray(value) || isArguments(value))
    ? baseTimes(value.length, String)
    : [];

  var length = result.length,
      skipIndexes = !!length;

  for (var key in value) {
    if ((inherited || hasOwnProperty.call(value, key)) &&
        !(skipIndexes && (key == 'length' || isIndex(key, length)))) {
      result.push(key);
    }
  }
  return result;
}

/**
 * The base implementation of `getTag`.
 *
 * @private
 * @param {*} value The value to query.
 * @returns {string} Returns the `toStringTag`.
 */
function baseGetTag(value) {
  return objectToString.call(value);
}

/**
 * The base implementation of `_.isNative` without bad shim checks.
 *
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a native function,
 *  else `false`.
 */
function baseIsNative(value) {
  if (!isObject(value) || isMasked(value)) {
    return false;
  }
  var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
  return pattern.test(toSource(value));
}

/**
 * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
 *
 * @private
 * @param {Object} object The object to query.
 * @returns {Array} Returns the array of property names.
 */
function baseKeys(object) {
  if (!isPrototype(object)) {
    return nativeKeys(object);
  }
  var result = [];
  for (var key in Object(object)) {
    if (hasOwnProperty.call(object, key) && key != 'constructor') {
      result.push(key);
    }
  }
  return result;
}

/**
 * Copies the values of `source` to `array`.
 *
 * @private
 * @param {Array} source The array to copy values from.
 * @param {Array} [array=[]] The array to copy values to.
 * @returns {Array} Returns `array`.
 */
function copyArray(source, array) {
  var index = -1,
      length = source.length;

  array || (array = Array(length));
  while (++index < length) {
    array[index] = source[index];
  }
  return array;
}

/**
 * Gets the native function at `key` of `object`.
 *
 * @private
 * @param {Object} object The object to query.
 * @param {string} key The key of the method to get.
 * @returns {*} Returns the function if it's native, else `undefined`.
 */
function getNative(object, key) {
  var value = getValue(object, key);
  return baseIsNative(value) ? value : undefined;
}

/**
 * Gets the `toStringTag` of `value`.
 *
 * @private
 * @param {*} value The value to query.
 * @returns {string} Returns the `toStringTag`.
 */
var getTag = baseGetTag;

// Fallback for data views, maps, sets, and weak maps in IE 11,
// for data views in Edge < 14, and promises in Node.js.
if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
    (Map$1 && getTag(new Map$1) != mapTag) ||
    (Promise$1 && getTag(Promise$1.resolve()) != promiseTag) ||
    (Set$1 && getTag(new Set$1) != setTag) ||
    (WeakMap$1 && getTag(new WeakMap$1) != weakMapTag)) {
  getTag = function(value) {
    var result = objectToString.call(value),
        Ctor = result == objectTag ? value.constructor : undefined,
        ctorString = Ctor ? toSource(Ctor) : undefined;

    if (ctorString) {
      switch (ctorString) {
        case dataViewCtorString: return dataViewTag;
        case mapCtorString: return mapTag;
        case promiseCtorString: return promiseTag;
        case setCtorString: return setTag;
        case weakMapCtorString: return weakMapTag;
      }
    }
    return result;
  };
}

/**
 * Checks if `value` is a valid array-like index.
 *
 * @private
 * @param {*} value The value to check.
 * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
 * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
 */
function isIndex(value, length) {
  length = length == null ? MAX_SAFE_INTEGER : length;
  return !!length &&
    (typeof value == 'number' || reIsUint.test(value)) &&
    (value > -1 && value % 1 == 0 && value < length);
}

/**
 * Checks if `func` has its source masked.
 *
 * @private
 * @param {Function} func The function to check.
 * @returns {boolean} Returns `true` if `func` is masked, else `false`.
 */
function isMasked(func) {
  return !!maskSrcKey && (maskSrcKey in func);
}

/**
 * Checks if `value` is likely a prototype object.
 *
 * @private
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
 */
function isPrototype(value) {
  var Ctor = value && value.constructor,
      proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;

  return value === proto;
}

/**
 * Converts `func` to its source code.
 *
 * @private
 * @param {Function} func The function to process.
 * @returns {string} Returns the source code.
 */
function toSource(func) {
  if (func != null) {
    try {
      return funcToString.call(func);
    } catch (e) {}
    try {
      return (func + '');
    } catch (e) {}
  }
  return '';
}

/**
 * Checks if `value` is likely an `arguments` object.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an `arguments` object,
 *  else `false`.
 * @example
 *
 * _.isArguments(function() { return arguments; }());
 * // => true
 *
 * _.isArguments([1, 2, 3]);
 * // => false
 */
function isArguments(value) {
  // Safari 8.1 makes `arguments.callee` enumerable in strict mode.
  return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
    (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
}

/**
 * Checks if `value` is classified as an `Array` object.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an array, else `false`.
 * @example
 *
 * _.isArray([1, 2, 3]);
 * // => true
 *
 * _.isArray(document.body.children);
 * // => false
 *
 * _.isArray('abc');
 * // => false
 *
 * _.isArray(_.noop);
 * // => false
 */
var isArray = Array.isArray;

/**
 * Checks if `value` is array-like. A value is considered array-like if it's
 * not a function and has a `value.length` that's an integer greater than or
 * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
 * @example
 *
 * _.isArrayLike([1, 2, 3]);
 * // => true
 *
 * _.isArrayLike(document.body.children);
 * // => true
 *
 * _.isArrayLike('abc');
 * // => true
 *
 * _.isArrayLike(_.noop);
 * // => false
 */
function isArrayLike(value) {
  return value != null && isLength(value.length) && !isFunction(value);
}

/**
 * This method is like `_.isArrayLike` except that it also checks if `value`
 * is an object.
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an array-like object,
 *  else `false`.
 * @example
 *
 * _.isArrayLikeObject([1, 2, 3]);
 * // => true
 *
 * _.isArrayLikeObject(document.body.children);
 * // => true
 *
 * _.isArrayLikeObject('abc');
 * // => false
 *
 * _.isArrayLikeObject(_.noop);
 * // => false
 */
function isArrayLikeObject(value) {
  return isObjectLike(value) && isArrayLike(value);
}

/**
 * Checks if `value` is classified as a `Function` object.
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a function, else `false`.
 * @example
 *
 * _.isFunction(_);
 * // => true
 *
 * _.isFunction(/abc/);
 * // => false
 */
function isFunction(value) {
  // The use of `Object#toString` avoids issues with the `typeof` operator
  // in Safari 8-9 which returns 'object' for typed array and other constructors.
  var tag = isObject(value) ? objectToString.call(value) : '';
  return tag == funcTag || tag == genTag;
}

/**
 * Checks if `value` is a valid array-like length.
 *
 * **Note:** This method is loosely based on
 * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
 * @example
 *
 * _.isLength(3);
 * // => true
 *
 * _.isLength(Number.MIN_VALUE);
 * // => false
 *
 * _.isLength(Infinity);
 * // => false
 *
 * _.isLength('3');
 * // => false
 */
function isLength(value) {
  return typeof value == 'number' &&
    value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}

/**
 * Checks if `value` is the
 * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
 *
 * @static
 * @memberOf _
 * @since 0.1.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
 * @example
 *
 * _.isObject({});
 * // => true
 *
 * _.isObject([1, 2, 3]);
 * // => true
 *
 * _.isObject(_.noop);
 * // => true
 *
 * _.isObject(null);
 * // => false
 */
function isObject(value) {
  var type = typeof value;
  return !!value && (type == 'object' || type == 'function');
}

/**
 * Checks if `value` is object-like. A value is object-like if it's not `null`
 * and has a `typeof` result of "object".
 *
 * @static
 * @memberOf _
 * @since 4.0.0
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
 * @example
 *
 * _.isObjectLike({});
 * // => true
 *
 * _.isObjectLike([1, 2, 3]);
 * // => true
 *
 * _.isObjectLike(_.noop);
 * // => false
 *
 * _.isObjectLike(null);
 * // => false
 */
function isObjectLike(value) {
  return !!value && typeof value == 'object';
}

/**
 * Checks if `value` is classified as a `String` primitive or object.
 *
 * @static
 * @since 0.1.0
 * @memberOf _
 * @category Lang
 * @param {*} value The value to check.
 * @returns {boolean} Returns `true` if `value` is a string, else `false`.
 * @example
 *
 * _.isString('abc');
 * // => true
 *
 * _.isString(1);
 * // => false
 */
function isString(value) {
  return typeof value == 'string' ||
    (!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag);
}

/**
 * Converts `value` to an array.
 *
 * @static
 * @since 0.1.0
 * @memberOf _
 * @category Lang
 * @param {*} value The value to convert.
 * @returns {Array} Returns the converted array.
 * @example
 *
 * _.toArray({ 'a': 1, 'b': 2 });
 * // => [1, 2]
 *
 * _.toArray('abc');
 * // => ['a', 'b', 'c']
 *
 * _.toArray(1);
 * // => []
 *
 * _.toArray(null);
 * // => []
 */
function toArray(value) {
  if (!value) {
    return [];
  }
  if (isArrayLike(value)) {
    return isString(value) ? stringToArray(value) : copyArray(value);
  }
  if (iteratorSymbol && value[iteratorSymbol]) {
    return iteratorToArray(value[iteratorSymbol]());
  }
  var tag = getTag(value),
      func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);

  return func(value);
}

/**
 * Creates an array of the own enumerable property names of `object`.
 *
 * **Note:** Non-object values are coerced to objects. See the
 * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
 * for more details.
 *
 * @static
 * @since 0.1.0
 * @memberOf _
 * @category Object
 * @param {Object} object The object to query.
 * @returns {Array} Returns the array of property names.
 * @example
 *
 * function Foo() {
 *   this.a = 1;
 *   this.b = 2;
 * }
 *
 * Foo.prototype.c = 3;
 *
 * _.keys(new Foo);
 * // => ['a', 'b'] (iteration order is not guaranteed)
 *
 * _.keys('hi');
 * // => ['0', '1']
 */
function keys(object) {
  return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
}

/**
 * Creates an array of the own enumerable string keyed property values of `object`.
 *
 * **Note:** Non-object values are coerced to objects.
 *
 * @static
 * @since 0.1.0
 * @memberOf _
 * @category Object
 * @param {Object} object The object to query.
 * @returns {Array} Returns the array of property values.
 * @example
 *
 * function Foo() {
 *   this.a = 1;
 *   this.b = 2;
 * }
 *
 * Foo.prototype.c = 3;
 *
 * _.values(new Foo);
 * // => [1, 2] (iteration order is not guaranteed)
 *
 * _.values('hi');
 * // => ['h', 'i']
 */
function values(object) {
  return object ? baseValues(object, keys(object)) : [];
}

var lodash_toarray = toArray;

var umbrella_with_rain_drops = "☔";
var coffee = "☕";
var aries = "♈";
var taurus = "♉";
var sagittarius = "♐";
var capricorn = "♑";
var aquarius = "♒";
var pisces = "♓";
var anchor = "⚓";
var white_check_mark = "✅";
var sparkles = "✨";
var question = "❓";
var grey_question = "❔";
var grey_exclamation = "❕";
var exclamation = "❗";
var heavy_exclamation_mark = "❗";
var heavy_plus_sign = "➕";
var heavy_minus_sign = "➖";
var heavy_division_sign = "➗";
var hash = "#️⃣";
var keycap_star = "*️⃣";
var zero = "0️⃣";
var one = "1️⃣";
var two = "2️⃣";
var three = "3️⃣";
var four = "4️⃣";
var five = "5️⃣";
var six = "6️⃣";
var seven = "7️⃣";
var eight = "8️⃣";
var nine = "9️⃣";
var copyright = "©️";
var registered = "®️";
var mahjong = "🀄";
var black_joker = "🃏";
var a = "🅰️";
var b = "🅱️";
var o2 = "🅾️";
var parking = "🅿️";
var ab = "🆎";
var cl = "🆑";
var cool = "🆒";
var free = "🆓";
var id = "🆔";
var ng = "🆖";
var ok = "🆗";
var sos = "🆘";
var up = "🆙";
var vs = "🆚";
var cn = "🇨🇳";
var de = "🇩🇪";
var es = "🇪🇸";
var fr = "🇫🇷";
var gb = "🇬🇧";
var uk = "🇬🇧";
var it = "🇮🇹";
var jp = "🇯🇵";
var kr = "🇰🇷";
var ru = "🇷🇺";
var us = "🇺🇸";
var koko = "🈁";
var sa = "🈂️";
var u7121 = "🈚";
var u6307 = "🈯";
var u7981 = "🈲";
var u7a7a = "🈳";
var u5408 = "🈴";
var u6e80 = "🈵";
var u6709 = "🈶";
var u6708 = "🈷️";
var u7533 = "🈸";
var u5272 = "🈹";
var u55b6 = "🈺";
var ideograph_advantage = "🉐";
var accept = "🉑";
var cyclone = "🌀";
var foggy = "🌁";
var closed_umbrella = "🌂";
var night_with_stars = "🌃";
var sunrise_over_mountains = "🌄";
var sunrise = "🌅";
var city_sunset = "🌆";
var city_sunrise = "🌇";
var rainbow = "🌈";
var bridge_at_night = "🌉";
var ocean = "🌊";
var volcano = "🌋";
var milky_way = "🌌";
var earth_africa = "🌍";
var earth_americas = "🌎";
var earth_asia = "🌏";
var globe_with_meridians = "🌐";
var new_moon = "🌑";
var waxing_crescent_moon = "🌒";
var first_quarter_moon = "🌓";
var moon = "🌔";
var waxing_gibbous_moon = "🌔";
var full_moon = "🌕";
var waning_gibbous_moon = "🌖";
var last_quarter_moon = "🌗";
var waning_crescent_moon = "🌘";
var crescent_moon = "🌙";
var new_moon_with_face = "🌚";
var first_quarter_moon_with_face = "🌛";
var last_quarter_moon_with_face = "🌜";
var full_moon_with_face = "🌝";
var sun_with_face = "🌞";
var star2 = "🌟";
var stars = "🌠";
var thermometer = "🌡️";
var mostly_sunny = "🌤️";
var sun_small_cloud = "🌤️";
var barely_sunny = "🌥️";
var sun_behind_cloud = "🌥️";
var partly_sunny_rain = "🌦️";
var sun_behind_rain_cloud = "🌦️";
var rain_cloud = "🌧️";
var snow_cloud = "🌨️";
var lightning = "🌩️";
var lightning_cloud = "🌩️";
var tornado = "🌪️";
var tornado_cloud = "🌪️";
var fog = "🌫️";
var wind_blowing_face = "🌬️";
var hotdog = "🌭";
var taco = "🌮";
var burrito = "🌯";
var chestnut = "🌰";
var seedling = "🌱";
var evergreen_tree = "🌲";
var deciduous_tree = "🌳";
var palm_tree = "🌴";
var cactus = "🌵";
var hot_pepper = "🌶️";
var tulip = "🌷";
var cherry_blossom = "🌸";
var rose = "🌹";
var hibiscus = "🌺";
var sunflower = "🌻";
var blossom = "🌼";
var corn = "🌽";
var ear_of_rice = "🌾";
var herb = "🌿";
var four_leaf_clover = "🍀";
var maple_leaf = "🍁";
var fallen_leaf = "🍂";
var leaves = "🍃";
var mushroom = "🍄";
var tomato = "🍅";
var eggplant = "🍆";
var grapes = "🍇";
var melon = "🍈";
var watermelon = "🍉";
var tangerine = "🍊";
var lemon = "🍋";
var banana = "🍌";
var pineapple = "🍍";
var apple = "🍎";
var green_apple = "🍏";
var pear = "🍐";
var peach = "🍑";
var cherries = "🍒";
var strawberry = "🍓";
var hamburger = "🍔";
var pizza = "🍕";
var meat_on_bone = "🍖";
var poultry_leg = "🍗";
var rice_cracker = "🍘";
var rice_ball = "🍙";
var rice = "🍚";
var curry = "🍛";
var ramen = "🍜";
var spaghetti = "🍝";
var bread = "🍞";
var fries = "🍟";
var sweet_potato = "🍠";
var dango = "🍡";
var oden = "🍢";
var sushi = "🍣";
var fried_shrimp = "🍤";
var fish_cake = "🍥";
var icecream = "🍦";
var shaved_ice = "🍧";
var ice_cream = "🍨";
var doughnut = "🍩";
var cookie = "🍪";
var chocolate_bar = "🍫";
var candy = "🍬";
var lollipop = "🍭";
var custard = "🍮";
var honey_pot = "🍯";
var cake = "🍰";
var bento = "🍱";
var stew = "🍲";
var fried_egg = "🍳";
var cooking = "🍳";
var fork_and_knife = "🍴";
var tea = "🍵";
var sake = "🍶";
var wine_glass = "🍷";
var cocktail = "🍸";
var tropical_drink = "🍹";
var beer = "🍺";
var beers = "🍻";
var baby_bottle = "🍼";
var knife_fork_plate = "🍽️";
var champagne = "🍾";
var popcorn = "🍿";
var ribbon = "🎀";
var gift = "🎁";
var birthday = "🎂";
var jack_o_lantern = "🎃";
var christmas_tree = "🎄";
var santa = "🎅";
var fireworks = "🎆";
var sparkler = "🎇";
var balloon = "🎈";
var tada = "🎉";
var confetti_ball = "🎊";
var tanabata_tree = "🎋";
var crossed_flags = "🎌";
var bamboo = "🎍";
var dolls = "🎎";
var flags = "🎏";
var wind_chime = "🎐";
var rice_scene = "🎑";
var school_satchel = "🎒";
var mortar_board = "🎓";
var medal = "🎖️";
var reminder_ribbon = "🎗️";
var studio_microphone = "🎙️";
var level_slider = "🎚️";
var control_knobs = "🎛️";
var film_frames = "🎞️";
var admission_tickets = "🎟️";
var carousel_horse = "🎠";
var ferris_wheel = "🎡";
var roller_coaster = "🎢";
var fishing_pole_and_fish = "🎣";
var microphone = "🎤";
var movie_camera = "🎥";
var cinema = "🎦";
var headphones = "🎧";
var art = "🎨";
var tophat = "🎩";
var circus_tent = "🎪";
var ticket = "🎫";
var clapper = "🎬";
var performing_arts = "🎭";
var video_game = "🎮";
var dart = "🎯";
var slot_machine = "🎰";
var game_die = "🎲";
var bowling = "🎳";
var flower_playing_cards = "🎴";
var musical_note = "🎵";
var notes = "🎶";
var saxophone = "🎷";
var guitar = "🎸";
var musical_keyboard = "🎹";
var trumpet = "🎺";
var violin = "🎻";
var musical_score = "🎼";
var running_shirt_with_sash = "🎽";
var tennis = "🎾";
var ski = "🎿";
var basketball = "🏀";
var checkered_flag = "🏁";
var snowboarder = "🏂";
var runner = "🏃‍♂️";
var running = "🏃‍♂️";
var surfer = "🏄‍♂️";
var sports_medal = "🏅";
var trophy = "🏆";
var horse_racing = "🏇";
var football = "🏈";
var rugby_football = "🏉";
var swimmer = "🏊‍♂️";
var weight_lifter = "🏋️‍♂️";
var golfer = "🏌️‍♂️";
var racing_motorcycle = "🏍️";
var racing_car = "🏎️";
var cricket_bat_and_ball = "🏏";
var volleyball = "🏐";
var field_hockey_stick_and_ball = "🏑";
var ice_hockey_stick_and_puck = "🏒";
var table_tennis_paddle_and_ball = "🏓";
var snow_capped_mountain = "🏔️";
var camping = "🏕️";
var beach_with_umbrella = "🏖️";
var building_construction = "🏗️";
var house_buildings = "🏘️";
var cityscape = "🏙️";
var derelict_house_building = "🏚️";
var classical_building = "🏛️";
var desert = "🏜️";
var desert_island = "🏝️";
var national_park = "🏞️";
var stadium = "🏟️";
var house = "🏠";
var house_with_garden = "🏡";
var office = "🏢";
var post_office = "🏣";
var european_post_office = "🏤";
var hospital = "🏥";
var bank = "🏦";
var atm = "🏧";
var hotel = "🏨";
var love_hotel = "🏩";
var convenience_store = "🏪";
var school = "🏫";
var department_store = "🏬";
var factory = "🏭";
var izakaya_lantern = "🏮";
var lantern = "🏮";
var japanese_castle = "🏯";
var european_castle = "🏰";
var waving_white_flag = "🏳️";
var waving_black_flag = "🏴";
var rosette = "🏵️";
var label = "🏷️";
var badminton_racquet_and_shuttlecock = "🏸";
var bow_and_arrow = "🏹";
var amphora = "🏺";
var rat = "🐀";
var mouse2 = "🐁";
var ox = "🐂";
var water_buffalo = "🐃";
var cow2 = "🐄";
var tiger2 = "🐅";
var leopard = "🐆";
var rabbit2 = "🐇";
var cat2 = "🐈";
var dragon = "🐉";
var crocodile = "🐊";
var whale2 = "🐋";
var snail = "🐌";
var snake = "🐍";
var racehorse = "🐎";
var ram = "🐏";
var goat = "🐐";
var sheep = "🐑";
var monkey = "🐒";
var rooster = "🐓";
var chicken = "🐔";
var dog2 = "🐕";
var pig2 = "🐖";
var boar = "🐗";
var elephant = "🐘";
var octopus = "🐙";
var shell = "🐚";
var bug = "🐛";
var ant = "🐜";
var bee = "🐝";
var honeybee = "🐝";
var beetle = "🐞";
var fish = "🐟";
var tropical_fish = "🐠";
var blowfish = "🐡";
var turtle = "🐢";
var hatching_chick = "🐣";
var baby_chick = "🐤";
var hatched_chick = "🐥";
var bird = "🐦";
var penguin = "🐧";
var koala = "🐨";
var poodle = "🐩";
var dromedary_camel = "🐪";
var camel = "🐫";
var dolphin = "🐬";
var flipper = "🐬";
var mouse = "🐭";
var cow = "🐮";
var tiger = "🐯";
var rabbit = "🐰";
var cat = "🐱";
var dragon_face = "🐲";
var whale = "🐳";
var horse = "🐴";
var monkey_face = "🐵";
var dog = "🐶";
var pig = "🐷";
var frog = "🐸";
var hamster = "🐹";
var wolf = "🐺";
var bear = "🐻";
var panda_face = "🐼";
var pig_nose = "🐽";
var feet = "🐾";
var paw_prints = "🐾";
var chipmunk = "🐿️";
var eyes = "👀";
var eye = "👁️";
var ear = "👂";
var nose = "👃";
var lips = "👄";
var tongue = "👅";
var point_up_2 = "👆";
var point_down = "👇";
var point_left = "👈";
var point_right = "👉";
var facepunch = "👊";
var punch = "👊";
var wave = "👋";
var ok_hand = "👌";
var thumbsup = "👍";
var thumbsdown = "👎";
var clap = "👏";
var open_hands = "👐";
var crown = "👑";
var womans_hat = "👒";
var eyeglasses = "👓";
var necktie = "👔";
var shirt = "👕";
var tshirt = "👕";
var jeans = "👖";
var dress = "👗";
var kimono = "👘";
var bikini = "👙";
var womans_clothes = "👚";
var purse = "👛";
var handbag = "👜";
var pouch = "👝";
var mans_shoe = "👞";
var shoe = "👞";
var athletic_shoe = "👟";
var high_heel = "👠";
var sandal = "👡";
var boot = "👢";
var footprints = "👣";
var bust_in_silhouette = "👤";
var busts_in_silhouette = "👥";
var boy = "👦";
var girl = "👧";
var family = "👨‍👩‍👦";
var man = "👨";
var couple_with_heart = "👩‍❤️‍👨";
var couplekiss = "👩‍❤️‍💋‍👨";
var woman = "👩";
var couple = "👫";
var man_and_woman_holding_hands = "👫";
var two_men_holding_hands = "👬";
var two_women_holding_hands = "👭";
var cop = "👮‍♂️";
var dancers = "👯‍♀️";
var bride_with_veil = "👰";
var person_with_blond_hair = "👱‍♂️";
var man_with_gua_pi_mao = "👲";
var man_with_turban = "👳‍♂️";
var older_man = "👴";
var older_woman = "👵";
var baby = "👶";
var construction_worker = "👷‍♂️";
var princess = "👸";
var japanese_ogre = "👹";
var japanese_goblin = "👺";
var ghost = "👻";
var angel = "👼";
var alien = "👽";
var space_invader = "👾";
var imp = "👿";
var skull = "💀";
var information_desk_person = "💁‍♀️";
var guardsman = "💂‍♂️";
var dancer = "💃";
var lipstick = "💄";
var nail_care = "💅";
var massage = "💆‍♀️";
var haircut = "💇‍♀️";
var barber = "💈";
var syringe = "💉";
var pill = "💊";
var kiss = "💋";
var love_letter = "💌";
var ring = "💍";
var gem = "💎";
var bouquet = "💐";
var wedding = "💒";
var heartbeat = "💓";
var broken_heart = "💔";
var two_hearts = "💕";
var sparkling_heart = "💖";
var heartpulse = "💗";
var cupid = "💘";
var blue_heart = "💙";
var green_heart = "💚";
var yellow_heart = "💛";
var purple_heart = "💜";
var gift_heart = "💝";
var revolving_hearts = "💞";
var heart_decoration = "💟";
var diamond_shape_with_a_dot_inside = "💠";
var bulb = "💡";
var anger = "💢";
var bomb = "💣";
var zzz = "💤";
var boom = "💥";
var collision = "💥";
var sweat_drops = "💦";
var droplet = "💧";
var dash = "💨";
var hankey = "💩";
var poop = "💩";
var shit = "💩";
var muscle = "💪";
var dizzy = "💫";
var speech_balloon = "💬";
var thought_balloon = "💭";
var white_flower = "💮";
var moneybag = "💰";
var currency_exchange = "💱";
var heavy_dollar_sign = "💲";
var credit_card = "💳";
var yen = "💴";
var dollar = "💵";
var euro = "💶";
var pound = "💷";
var money_with_wings = "💸";
var chart = "💹";
var seat = "💺";
var computer = "💻";
var briefcase = "💼";
var minidisc = "💽";
var floppy_disk = "💾";
var cd = "💿";
var dvd = "📀";
var file_folder = "📁";
var open_file_folder = "📂";
var page_with_curl = "📃";
var page_facing_up = "📄";
var date = "📅";
var calendar = "📆";
var card_index = "📇";
var chart_with_upwards_trend = "📈";
var chart_with_downwards_trend = "📉";
var bar_chart = "📊";
var clipboard = "📋";
var pushpin = "📌";
var round_pushpin = "📍";
var paperclip = "📎";
var straight_ruler = "📏";
var triangular_ruler = "📐";
var bookmark_tabs = "📑";
var ledger = "📒";
var notebook = "📓";
var notebook_with_decorative_cover = "📔";
var closed_book = "📕";
var book = "📖";
var open_book = "📖";
var green_book = "📗";
var blue_book = "📘";
var orange_book = "📙";
var books = "📚";
var name_badge = "📛";
var scroll = "📜";
var memo = "📝";
var pencil = "📝";
var telephone_receiver = "📞";
var pager = "📟";
var fax = "📠";
var satellite_antenna = "📡";
var loudspeaker = "📢";
var mega = "📣";
var outbox_tray = "📤";
var inbox_tray = "📥";
var incoming_envelope = "📨";
var envelope_with_arrow = "📩";
var mailbox_closed = "📪";
var mailbox = "📫";
var mailbox_with_mail = "📬";
var mailbox_with_no_mail = "📭";
var postbox = "📮";
var postal_horn = "📯";
var newspaper = "📰";
var iphone = "📱";
var calling = "📲";
var vibration_mode = "📳";
var mobile_phone_off = "📴";
var no_mobile_phones = "📵";
var signal_strength = "📶";
var camera = "📷";
var camera_with_flash = "📸";
var video_camera = "📹";
var tv = "📺";
var radio = "📻";
var vhs = "📼";
var film_projector = "📽️";
var prayer_beads = "📿";
var twisted_rightwards_arrows = "🔀";
var repeat = "🔁";
var repeat_one = "🔂";
var arrows_clockwise = "🔃";
var arrows_counterclockwise = "🔄";
var low_brightness = "🔅";
var high_brightness = "🔆";
var mute = "🔇";
var speaker = "🔈";
var sound = "🔉";
var loud_sound = "🔊";
var battery = "🔋";
var electric_plug = "🔌";
var mag = "🔍";
var mag_right = "🔎";
var lock_with_ink_pen = "🔏";
var closed_lock_with_key = "🔐";
var key = "🔑";
var lock = "🔒";
var unlock = "🔓";
var bell = "🔔";
var no_bell = "🔕";
var bookmark = "🔖";
var link = "🔗";
var radio_button = "🔘";
var back = "🔙";
var end = "🔚";
var on = "🔛";
var soon = "🔜";
var top = "🔝";
var underage = "🔞";
var keycap_ten = "🔟";
var capital_abcd = "🔠";
var abcd = "🔡";
var symbols = "🔣";
var abc = "🔤";
var fire = "🔥";
var flashlight = "🔦";
var wrench = "🔧";
var hammer = "🔨";
var nut_and_bolt = "🔩";
var hocho = "🔪";
var knife = "🔪";
var gun = "🔫";
var microscope = "🔬";
var telescope = "🔭";
var crystal_ball = "🔮";
var six_pointed_star = "🔯";
var beginner = "🔰";
var trident = "🔱";
var black_square_button = "🔲";
var white_square_button = "🔳";
var red_circle = "🔴";
var large_blue_circle = "🔵";
var large_orange_diamond = "🔶";
var large_blue_diamond = "🔷";
var small_orange_diamond = "🔸";
var small_blue_diamond = "🔹";
var small_red_triangle = "🔺";
var small_red_triangle_down = "🔻";
var arrow_up_small = "🔼";
var arrow_down_small = "🔽";
var om_symbol = "🕉️";
var dove_of_peace = "🕊️";
var kaaba = "🕋";
var mosque = "🕌";
var synagogue = "🕍";
var menorah_with_nine_branches = "🕎";
var clock1 = "🕐";
var clock2 = "🕑";
var clock3 = "🕒";
var clock4 = "🕓";
var clock5 = "🕔";
var clock6 = "🕕";
var clock7 = "🕖";
var clock8 = "🕗";
var clock9 = "🕘";
var clock10 = "🕙";
var clock11 = "🕚";
var clock12 = "🕛";
var clock130 = "🕜";
var clock230 = "🕝";
var clock330 = "🕞";
var clock430 = "🕟";
var clock530 = "🕠";
var clock630 = "🕡";
var clock730 = "🕢";
var clock830 = "🕣";
var clock930 = "🕤";
var clock1030 = "🕥";
var clock1130 = "🕦";
var clock1230 = "🕧";
var candle = "🕯️";
var mantelpiece_clock = "🕰️";
var hole = "🕳️";
var man_in_business_suit_levitating = "🕴️";
var sleuth_or_spy = "🕵️‍♂️";
var dark_sunglasses = "🕶️";
var spider = "🕷️";
var spider_web = "🕸️";
var joystick = "🕹️";
var man_dancing = "🕺";
var linked_paperclips = "🖇️";
var lower_left_ballpoint_pen = "🖊️";
var lower_left_fountain_pen = "🖋️";
var lower_left_paintbrush = "🖌️";
var lower_left_crayon = "🖍️";
var raised_hand_with_fingers_splayed = "🖐️";
var middle_finger = "🖕";
var reversed_hand_with_middle_finger_extended = "🖕";
var black_heart = "🖤";
var desktop_computer = "🖥️";
var printer = "🖨️";
var three_button_mouse = "🖱️";
var trackball = "🖲️";
var frame_with_picture = "🖼️";
var card_index_dividers = "🗂️";
var card_file_box = "🗃️";
var file_cabinet = "🗄️";
var wastebasket = "🗑️";
var spiral_note_pad = "🗒️";
var spiral_calendar_pad = "🗓️";
var compression = "🗜️";
var old_key = "🗝️";
var rolled_up_newspaper = "🗞️";
var dagger_knife = "🗡️";
var speaking_head_in_silhouette = "🗣️";
var left_speech_bubble = "🗨️";
var right_anger_bubble = "🗯️";
var ballot_box_with_ballot = "🗳️";
var world_map = "🗺️";
var mount_fuji = "🗻";
var tokyo_tower = "🗼";
var statue_of_liberty = "🗽";
var japan = "🗾";
var moyai = "🗿";
var grinning = "😀";
var grin = "😁";
var joy = "😂";
var smiley = "😃";
var smile = "😄";
var sweat_smile = "😅";
var laughing = "😆";
var satisfied = "😆";
var innocent = "😇";
var smiling_imp = "😈";
var wink = "😉";
var blush = "😊";
var yum = "😋";
var relieved = "😌";
var heart_eyes = "😍";
var sunglasses = "😎";
var smirk = "😏";
var neutral_face = "😐";
var expressionless = "😑";
var unamused = "😒";
var sweat = "😓";
var pensive = "😔";
var confused = "😕";
var confounded = "😖";
var kissing = "😗";
var kissing_heart = "😘";
var kissing_smiling_eyes = "😙";
var kissing_closed_eyes = "😚";
var stuck_out_tongue = "😛";
var stuck_out_tongue_winking_eye = "😜";
var stuck_out_tongue_closed_eyes = "😝";
var disappointed = "😞";
var worried = "😟";
var angry = "😠";
var rage = "😡";
var cry = "😢";
var persevere = "😣";
var triumph = "😤";
var disappointed_relieved = "😥";
var frowning = "😦";
var anguished = "😧";
var fearful = "😨";
var weary = "😩";
var sleepy = "😪";
var tired_face = "😫";
var grimacing = "😬";
var sob = "😭";
var open_mouth = "😮";
var hushed = "😯";
var cold_sweat = "😰";
var scream = "😱";
var astonished = "😲";
var flushed = "😳";
var sleeping = "😴";
var dizzy_face = "😵";
var no_mouth = "😶";
var mask = "😷";
var smile_cat = "😸";
var joy_cat = "😹";
var smiley_cat = "😺";
var heart_eyes_cat = "😻";
var smirk_cat = "😼";
var kissing_cat = "😽";
var pouting_cat = "😾";
var crying_cat_face = "😿";
var scream_cat = "🙀";
var slightly_frowning_face = "🙁";
var slightly_smiling_face = "🙂";
var upside_down_face = "🙃";
var face_with_rolling_eyes = "🙄";
var no_good = "🙅‍♀️";
var ok_woman = "🙆‍♀️";
var bow = "🙇‍♂️";
var see_no_evil = "🙈";
var hear_no_evil = "🙉";
var speak_no_evil = "🙊";
var raising_hand = "🙋‍♀️";
var raised_hands = "🙌";
var person_frowning = "🙍‍♀️";
var person_with_pouting_face = "🙎‍♀️";
var pray = "🙏";
var rocket = "🚀";
var helicopter = "🚁";
var steam_locomotive = "🚂";
var railway_car = "🚃";
var bullettrain_side = "🚄";
var bullettrain_front = "🚅";
var train2 = "🚆";
var metro = "🚇";
var light_rail = "🚈";
var station = "🚉";
var tram = "🚊";
var train = "🚋";
var bus = "🚌";
var oncoming_bus = "🚍";
var trolleybus = "🚎";
var busstop = "🚏";
var minibus = "🚐";
var ambulance = "🚑";
var fire_engine = "🚒";
var police_car = "🚓";
var oncoming_police_car = "🚔";
var taxi = "🚕";
var oncoming_taxi = "🚖";
var car = "🚗";
var red_car = "🚗";
var oncoming_automobile = "🚘";
var blue_car = "🚙";
var truck = "🚚";
var articulated_lorry = "🚛";
var tractor = "🚜";
var monorail = "🚝";
var mountain_railway = "🚞";
var suspension_railway = "🚟";
var mountain_cableway = "🚠";
var aerial_tramway = "🚡";
var ship = "🚢";
var rowboat = "🚣‍♂️";
var speedboat = "🚤";
var traffic_light = "🚥";
var vertical_traffic_light = "🚦";
var construction = "🚧";
var rotating_light = "🚨";
var triangular_flag_on_post = "🚩";
var door = "🚪";
var no_entry_sign = "🚫";
var smoking = "🚬";
var no_smoking = "🚭";
var put_litter_in_its_place = "🚮";
var do_not_litter = "🚯";
var potable_water = "🚰";
var bike = "🚲";
var no_bicycles = "🚳";
var bicyclist = "🚴‍♂️";
var mountain_bicyclist = "🚵‍♂️";
var walking = "🚶‍♂️";
var no_pedestrians = "🚷";
var children_crossing = "🚸";
var mens = "🚹";
var womens = "🚺";
var restroom = "🚻";
var baby_symbol = "🚼";
var toilet = "🚽";
var wc = "🚾";
var shower = "🚿";
var bath = "🛀";
var bathtub = "🛁";
var passport_control = "🛂";
var customs = "🛃";
var baggage_claim = "🛄";
var left_luggage = "🛅";
var couch_and_lamp = "🛋️";
var sleeping_accommodation = "🛌";
var shopping_bags = "🛍️";
var bellhop_bell = "🛎️";
var bed = "🛏️";
var place_of_worship = "🛐";
var octagonal_sign = "🛑";
var shopping_trolley = "🛒";
var hammer_and_wrench = "🛠️";
var shield = "🛡️";
var oil_drum = "🛢️";
var motorway = "🛣️";
var railway_track = "🛤️";
var motor_boat = "🛥️";
var small_airplane = "🛩️";
var airplane_departure = "🛫";
var airplane_arriving = "🛬";
var satellite = "🛰️";
var passenger_ship = "🛳️";
var scooter = "🛴";
var motor_scooter = "🛵";
var canoe = "🛶";
var sled = "🛷";
var flying_saucer = "🛸";
var zipper_mouth_face = "🤐";
var money_mouth_face = "🤑";
var face_with_thermometer = "🤒";
var nerd_face = "🤓";
var thinking_face = "🤔";
var face_with_head_bandage = "🤕";
var robot_face = "🤖";
var hugging_face = "🤗";
var the_horns = "🤘";
var sign_of_the_horns = "🤘";
var call_me_hand = "🤙";
var raised_back_of_hand = "🤚";
var handshake = "🤝";
var crossed_fingers = "🤞";
var hand_with_index_and_middle_fingers_crossed = "🤞";
var i_love_you_hand_sign = "🤟";
var face_with_cowboy_hat = "🤠";
var clown_face = "🤡";
var nauseated_face = "🤢";
var rolling_on_the_floor_laughing = "🤣";
var drooling_face = "🤤";
var lying_face = "🤥";
var face_palm = "🤦";
var sneezing_face = "🤧";
var face_with_raised_eyebrow = "🤨";
var face_with_one_eyebrow_raised = "🤨";
var grinning_face_with_star_eyes = "🤩";
var zany_face = "🤪";
var grinning_face_with_one_large_and_one_small_eye = "🤪";
var shushing_face = "🤫";
var face_with_finger_covering_closed_lips = "🤫";
var face_with_symbols_on_mouth = "🤬";
var serious_face_with_symbols_covering_mouth = "🤬";
var face_with_hand_over_mouth = "🤭";
var smiling_face_with_smiling_eyes_and_hand_covering_mouth = "🤭";
var face_vomiting = "🤮";
var face_with_open_mouth_vomiting = "🤮";
var exploding_head = "🤯";
var shocked_face_with_exploding_head = "🤯";
var pregnant_woman = "🤰";
var palms_up_together = "🤲";
var selfie = "🤳";
var prince = "🤴";
var man_in_tuxedo = "🤵";
var mrs_claus = "🤶";
var mother_christmas = "🤶";
var shrug = "🤷";
var person_doing_cartwheel = "🤸";
var juggling = "🤹";
var fencer = "🤺";
var wrestlers = "🤼";
var water_polo = "🤽";
var handball = "🤾";
var wilted_flower = "🥀";
var drum_with_drumsticks = "🥁";
var clinking_glasses = "🥂";
var tumbler_glass = "🥃";
var spoon = "🥄";
var goal_net = "🥅";
var first_place_medal = "🥇";
var second_place_medal = "🥈";
var third_place_medal = "🥉";
var boxing_glove = "🥊";
var martial_arts_uniform = "🥋";
var curling_stone = "🥌";
var croissant = "🥐";
var avocado = "🥑";
var cucumber = "🥒";
var bacon = "🥓";
var potato = "🥔";
var carrot = "🥕";
var baguette_bread = "🥖";
var green_salad = "🥗";
var shallow_pan_of_food = "🥘";
var stuffed_flatbread = "🥙";
var egg = "🥚";
var glass_of_milk = "🥛";
var peanuts = "🥜";
var kiwifruit = "🥝";
var pancakes = "🥞";
var dumpling = "🥟";
var fortune_cookie = "🥠";
var takeout_box = "🥡";
var chopsticks = "🥢";
var bowl_with_spoon = "🥣";
var cup_with_straw = "🥤";
var coconut = "🥥";
var broccoli = "🥦";
var pie = "🥧";
var pretzel = "🥨";
var cut_of_meat = "🥩";
var sandwich = "🥪";
var canned_food = "🥫";
var crab = "🦀";
var lion_face = "🦁";
var scorpion = "🦂";
var turkey = "🦃";
var unicorn_face = "🦄";
var eagle = "🦅";
var duck = "🦆";
var bat = "🦇";
var shark = "🦈";
var owl = "🦉";
var fox_face = "🦊";
var butterfly = "🦋";
var deer = "🦌";
var gorilla = "🦍";
var lizard = "🦎";
var rhinoceros = "🦏";
var shrimp = "🦐";
var squid = "🦑";
var giraffe_face = "🦒";
var zebra_face = "🦓";
var hedgehog = "🦔";
var sauropod = "🦕";
var cricket = "🦗";
var cheese_wedge = "🧀";
var face_with_monocle = "🧐";
var adult = "🧑";
var child = "🧒";
var older_adult = "🧓";
var bearded_person = "🧔";
var person_with_headscarf = "🧕";
var woman_in_steamy_room = "🧖‍♀️";
var man_in_steamy_room = "🧖‍♂️";
var person_in_steamy_room = "🧖‍♂️";
var woman_climbing = "🧗‍♀️";
var person_climbing = "🧗‍♀️";
var man_climbing = "🧗‍♂️";
var woman_in_lotus_position = "🧘‍♀️";
var person_in_lotus_position = "🧘‍♀️";
var man_in_lotus_position = "🧘‍♂️";
var female_mage = "🧙‍♀️";
var mage = "🧙‍♀️";
var male_mage = "🧙‍♂️";
var female_fairy = "🧚‍♀️";
var fairy = "🧚‍♀️";
var male_fairy = "🧚‍♂️";
var female_vampire = "🧛‍♀️";
var vampire = "🧛‍♀️";
var male_vampire = "🧛‍♂️";
var mermaid = "🧜‍♀️";
var merman = "🧜‍♂️";
var merperson = "🧜‍♂️";
var female_elf = "🧝‍♀️";
var male_elf = "🧝‍♂️";
var elf = "🧝‍♂️";
var female_genie = "🧞‍♀️";
var male_genie = "🧞‍♂️";
var genie = "🧞‍♂️";
var female_zombie = "🧟‍♀️";
var male_zombie = "🧟‍♂️";
var zombie = "🧟‍♂️";
var brain = "🧠";
var orange_heart = "🧡";
var billed_cap = "🧢";
var scarf = "🧣";
var gloves = "🧤";
var coat = "🧥";
var socks = "🧦";
var bangbang = "‼️";
var interrobang = "⁉️";
var tm = "™️";
var information_source = "ℹ️";
var left_right_arrow = "↔️";
var arrow_up_down = "↕️";
var arrow_upper_left = "↖️";
var arrow_upper_right = "↗️";
var arrow_lower_right = "↘️";
var arrow_lower_left = "↙️";
var leftwards_arrow_with_hook = "↩️";
var arrow_right_hook = "↪️";
var watch = "⌚";
var hourglass = "⌛";
var keyboard = "⌨️";
var eject = "⏏️";
var fast_forward = "⏩";
var rewind = "⏪";
var arrow_double_up = "⏫";
var arrow_double_down = "⏬";
var black_right_pointing_double_triangle_with_vertical_bar = "⏭️";
var black_left_pointing_double_triangle_with_vertical_bar = "⏮️";
var black_right_pointing_triangle_with_double_vertical_bar = "⏯️";
var alarm_clock = "⏰";
var stopwatch = "⏱️";
var timer_clock = "⏲️";
var hourglass_flowing_sand = "⏳";
var double_vertical_bar = "⏸️";
var black_square_for_stop = "⏹️";
var black_circle_for_record = "⏺️";
var m = "Ⓜ️";
var black_small_square = "▪️";
var white_small_square = "▫️";
var arrow_forward = "▶️";
var arrow_backward = "◀️";
var white_medium_square = "◻️";
var black_medium_square = "◼️";
var white_medium_small_square = "◽";
var black_medium_small_square = "◾";
var sunny = "☀️";
var cloud = "☁️";
var umbrella = "☂️";
var snowman = "☃️";
var comet = "☄️";
var phone = "☎️";
var telephone = "☎️";
var ballot_box_with_check = "☑️";
var shamrock = "☘️";
var point_up = "☝️";
var skull_and_crossbones = "☠️";
var radioactive_sign = "☢️";
var biohazard_sign = "☣️";
var orthodox_cross = "☦️";
var star_and_crescent = "☪️";
var peace_symbol = "☮️";
var yin_yang = "☯️";
var wheel_of_dharma = "☸️";
var white_frowning_face = "☹️";
var relaxed = "☺️";
var female_sign = "♀️";
var male_sign = "♂️";
var gemini = "♊";
var cancer = "♋";
var leo = "♌";
var virgo = "♍";
var libra = "♎";
var scorpius = "♏";
var spades = "♠️";
var clubs = "♣️";
var hearts = "♥️";
var diamonds = "♦️";
var hotsprings = "♨️";
var recycle = "♻️";
var wheelchair = "♿";
var hammer_and_pick = "⚒️";
var crossed_swords = "⚔️";
var medical_symbol = "⚕️";
var staff_of_aesculapius = "⚕️";
var scales = "⚖️";
var alembic = "⚗️";
var gear = "⚙️";
var atom_symbol = "⚛️";
var fleur_de_lis = "⚜️";
var warning = "⚠️";
var zap = "⚡";
var white_circle = "⚪";
var black_circle = "⚫";
var coffin = "⚰️";
var funeral_urn = "⚱️";
var soccer = "⚽";
var baseball = "⚾";
var snowman_without_snow = "⛄";
var partly_sunny = "⛅";
var thunder_cloud_and_rain = "⛈️";
var ophiuchus = "⛎";
var pick = "⛏️";
var helmet_with_white_cross = "⛑️";
var chains = "⛓️";
var no_entry = "⛔";
var shinto_shrine = "⛩️";
var church = "⛪";
var mountain = "⛰️";
var umbrella_on_ground = "⛱️";
var fountain = "⛲";
var golf = "⛳";
var ferry = "⛴️";
var boat = "⛵";
var sailboat = "⛵";
var skier = "⛷️";
var ice_skate = "⛸️";
var person_with_ball = "⛹️‍♂️";
var tent = "⛺";
var fuelpump = "⛽";
var scissors = "✂️";
var airplane = "✈️";
var email = "✉️";
var envelope = "✉️";
var fist = "✊";
var hand = "✋";
var raised_hand = "✋";
var v = "✌️";
var writing_hand = "✍️";
var pencil2 = "✏️";
var black_nib = "✒️";
var heavy_check_mark = "✔️";
var heavy_multiplication_x = "✖️";
var latin_cross = "✝️";
var star_of_david = "✡️";
var eight_spoked_asterisk = "✳️";
var eight_pointed_black_star = "✴️";
var snowflake = "❄️";
var sparkle = "❇️";
var x = "❌";
var negative_squared_cross_mark = "❎";
var heavy_heart_exclamation_mark_ornament = "❣️";
var heart = "❤️";
var arrow_right = "➡️";
var curly_loop = "➰";
var loop = "➿";
var arrow_heading_up = "⤴️";
var arrow_heading_down = "⤵️";
var arrow_left = "⬅️";
var arrow_up = "⬆️";
var arrow_down = "⬇️";
var black_large_square = "⬛";
var white_large_square = "⬜";
var star = "⭐";
var o = "⭕";
var wavy_dash = "〰️";
var part_alternation_mark = "〽️";
var congratulations = "㊗️";
var secret = "㊙️";
var emoji = {
	"100": "💯",
	"1234": "🔢",
	umbrella_with_rain_drops: umbrella_with_rain_drops,
	coffee: coffee,
	aries: aries,
	taurus: taurus,
	sagittarius: sagittarius,
	capricorn: capricorn,
	aquarius: aquarius,
	pisces: pisces,
	anchor: anchor,
	white_check_mark: white_check_mark,
	sparkles: sparkles,
	question: question,
	grey_question: grey_question,
	grey_exclamation: grey_exclamation,
	exclamation: exclamation,
	heavy_exclamation_mark: heavy_exclamation_mark,
	heavy_plus_sign: heavy_plus_sign,
	heavy_minus_sign: heavy_minus_sign,
	heavy_division_sign: heavy_division_sign,
	hash: hash,
	keycap_star: keycap_star,
	zero: zero,
	one: one,
	two: two,
	three: three,
	four: four,
	five: five,
	six: six,
	seven: seven,
	eight: eight,
	nine: nine,
	copyright: copyright,
	registered: registered,
	mahjong: mahjong,
	black_joker: black_joker,
	a: a,
	b: b,
	o2: o2,
	parking: parking,
	ab: ab,
	cl: cl,
	cool: cool,
	free: free,
	id: id,
	"new": "🆕",
	ng: ng,
	ok: ok,
	sos: sos,
	up: up,
	vs: vs,
	"flag-ac": "🇦🇨",
	"flag-ad": "🇦🇩",
	"flag-ae": "🇦🇪",
	"flag-af": "🇦🇫",
	"flag-ag": "🇦🇬",
	"flag-ai": "🇦🇮",
	"flag-al": "🇦🇱",
	"flag-am": "🇦🇲",
	"flag-ao": "🇦🇴",
	"flag-aq": "🇦🇶",
	"flag-ar": "🇦🇷",
	"flag-as": "🇦🇸",
	"flag-at": "🇦🇹",
	"flag-au": "🇦🇺",
	"flag-aw": "🇦🇼",
	"flag-ax": "🇦🇽",
	"flag-az": "🇦🇿",
	"flag-ba": "🇧🇦",
	"flag-bb": "🇧🇧",
	"flag-bd": "🇧🇩",
	"flag-be": "🇧🇪",
	"flag-bf": "🇧🇫",
	"flag-bg": "🇧🇬",
	"flag-bh": "🇧🇭",
	"flag-bi": "🇧🇮",
	"flag-bj": "🇧🇯",
	"flag-bl": "🇧🇱",
	"flag-bm": "🇧🇲",
	"flag-bn": "🇧🇳",
	"flag-bo": "🇧🇴",
	"flag-bq": "🇧🇶",
	"flag-br": "🇧🇷",
	"flag-bs": "🇧🇸",
	"flag-bt": "🇧🇹",
	"flag-bv": "🇧🇻",
	"flag-bw": "🇧🇼",
	"flag-by": "🇧🇾",
	"flag-bz": "🇧🇿",
	"flag-ca": "🇨🇦",
	"flag-cc": "🇨🇨",
	"flag-cd": "🇨🇩",
	"flag-cf": "🇨🇫",
	"flag-cg": "🇨🇬",
	"flag-ch": "🇨🇭",
	"flag-ci": "🇨🇮",
	"flag-ck": "🇨🇰",
	"flag-cl": "🇨🇱",
	"flag-cm": "🇨🇲",
	cn: cn,
	"flag-cn": "🇨🇳",
	"flag-co": "🇨🇴",
	"flag-cp": "🇨🇵",
	"flag-cr": "🇨🇷",
	"flag-cu": "🇨🇺",
	"flag-cv": "🇨🇻",
	"flag-cw": "🇨🇼",
	"flag-cx": "🇨🇽",
	"flag-cy": "🇨🇾",
	"flag-cz": "🇨🇿",
	de: de,
	"flag-de": "🇩🇪",
	"flag-dg": "🇩🇬",
	"flag-dj": "🇩🇯",
	"flag-dk": "🇩🇰",
	"flag-dm": "🇩🇲",
	"flag-do": "🇩🇴",
	"flag-dz": "🇩🇿",
	"flag-ea": "🇪🇦",
	"flag-ec": "🇪🇨",
	"flag-ee": "🇪🇪",
	"flag-eg": "🇪🇬",
	"flag-eh": "🇪🇭",
	"flag-er": "🇪🇷",
	es: es,
	"flag-es": "🇪🇸",
	"flag-et": "🇪🇹",
	"flag-eu": "🇪🇺",
	"flag-fi": "🇫🇮",
	"flag-fj": "🇫🇯",
	"flag-fk": "🇫🇰",
	"flag-fm": "🇫🇲",
	"flag-fo": "🇫🇴",
	fr: fr,
	"flag-fr": "🇫🇷",
	"flag-ga": "🇬🇦",
	gb: gb,
	uk: uk,
	"flag-gb": "🇬🇧",
	"flag-gd": "🇬🇩",
	"flag-ge": "🇬🇪",
	"flag-gf": "🇬🇫",
	"flag-gg": "🇬🇬",
	"flag-gh": "🇬🇭",
	"flag-gi": "🇬🇮",
	"flag-gl": "🇬🇱",
	"flag-gm": "🇬🇲",
	"flag-gn": "🇬🇳",
	"flag-gp": "🇬🇵",
	"flag-gq": "🇬🇶",
	"flag-gr": "🇬🇷",
	"flag-gs": "🇬🇸",
	"flag-gt": "🇬🇹",
	"flag-gu": "🇬🇺",
	"flag-gw": "🇬🇼",
	"flag-gy": "🇬🇾",
	"flag-hk": "🇭🇰",
	"flag-hm": "🇭🇲",
	"flag-hn": "🇭🇳",
	"flag-hr": "🇭🇷",
	"flag-ht": "🇭🇹",
	"flag-hu": "🇭🇺",
	"flag-ic": "🇮🇨",
	"flag-id": "🇮🇩",
	"flag-ie": "🇮🇪",
	"flag-il": "🇮🇱",
	"flag-im": "🇮🇲",
	"flag-in": "🇮🇳",
	"flag-io": "🇮🇴",
	"flag-iq": "🇮🇶",
	"flag-ir": "🇮🇷",
	"flag-is": "🇮🇸",
	it: it,
	"flag-it": "🇮🇹",
	"flag-je": "🇯🇪",
	"flag-jm": "🇯🇲",
	"flag-jo": "🇯🇴",
	jp: jp,
	"flag-jp": "🇯🇵",
	"flag-ke": "🇰🇪",
	"flag-kg": "🇰🇬",
	"flag-kh": "🇰🇭",
	"flag-ki": "🇰🇮",
	"flag-km": "🇰🇲",
	"flag-kn": "🇰🇳",
	"flag-kp": "🇰🇵",
	kr: kr,
	"flag-kr": "🇰🇷",
	"flag-kw": "🇰🇼",
	"flag-ky": "🇰🇾",
	"flag-kz": "🇰🇿",
	"flag-la": "🇱🇦",
	"flag-lb": "🇱🇧",
	"flag-lc": "🇱🇨",
	"flag-li": "🇱🇮",
	"flag-lk": "🇱🇰",
	"flag-lr": "🇱🇷",
	"flag-ls": "🇱🇸",
	"flag-lt": "🇱🇹",
	"flag-lu": "🇱🇺",
	"flag-lv": "🇱🇻",
	"flag-ly": "🇱🇾",
	"flag-ma": "🇲🇦",
	"flag-mc": "🇲🇨",
	"flag-md": "🇲🇩",
	"flag-me": "🇲🇪",
	"flag-mf": "🇲🇫",
	"flag-mg": "🇲🇬",
	"flag-mh": "🇲🇭",
	"flag-mk": "🇲🇰",
	"flag-ml": "🇲🇱",
	"flag-mm": "🇲🇲",
	"flag-mn": "🇲🇳",
	"flag-mo": "🇲🇴",
	"flag-mp": "🇲🇵",
	"flag-mq": "🇲🇶",
	"flag-mr": "🇲🇷",
	"flag-ms": "🇲🇸",
	"flag-mt": "🇲🇹",
	"flag-mu": "🇲🇺",
	"flag-mv": "🇲🇻",
	"flag-mw": "🇲🇼",
	"flag-mx": "🇲🇽",
	"flag-my": "🇲🇾",
	"flag-mz": "🇲🇿",
	"flag-na": "🇳🇦",
	"flag-nc": "🇳🇨",
	"flag-ne": "🇳🇪",
	"flag-nf": "🇳🇫",
	"flag-ng": "🇳🇬",
	"flag-ni": "🇳🇮",
	"flag-nl": "🇳🇱",
	"flag-no": "🇳🇴",
	"flag-np": "🇳🇵",
	"flag-nr": "🇳🇷",
	"flag-nu": "🇳🇺",
	"flag-nz": "🇳🇿",
	"flag-om": "🇴🇲",
	"flag-pa": "🇵🇦",
	"flag-pe": "🇵🇪",
	"flag-pf": "🇵🇫",
	"flag-pg": "🇵🇬",
	"flag-ph": "🇵🇭",
	"flag-pk": "🇵🇰",
	"flag-pl": "🇵🇱",
	"flag-pm": "🇵🇲",
	"flag-pn": "🇵🇳",
	"flag-pr": "🇵🇷",
	"flag-ps": "🇵🇸",
	"flag-pt": "🇵🇹",
	"flag-pw": "🇵🇼",
	"flag-py": "🇵🇾",
	"flag-qa": "🇶🇦",
	"flag-re": "🇷🇪",
	"flag-ro": "🇷🇴",
	"flag-rs": "🇷🇸",
	ru: ru,
	"flag-ru": "🇷🇺",
	"flag-rw": "🇷🇼",
	"flag-sa": "🇸🇦",
	"flag-sb": "🇸🇧",
	"flag-sc": "🇸🇨",
	"flag-sd": "🇸🇩",
	"flag-se": "🇸🇪",
	"flag-sg": "🇸🇬",
	"flag-sh": "🇸🇭",
	"flag-si": "🇸🇮",
	"flag-sj": "🇸🇯",
	"flag-sk": "🇸🇰",
	"flag-sl": "🇸🇱",
	"flag-sm": "🇸🇲",
	"flag-sn": "🇸🇳",
	"flag-so": "🇸🇴",
	"flag-sr": "🇸🇷",
	"flag-ss": "🇸🇸",
	"flag-st": "🇸🇹",
	"flag-sv": "🇸🇻",
	"flag-sx": "🇸🇽",
	"flag-sy": "🇸🇾",
	"flag-sz": "🇸🇿",
	"flag-ta": "🇹🇦",
	"flag-tc": "🇹🇨",
	"flag-td": "🇹🇩",
	"flag-tf": "🇹🇫",
	"flag-tg": "🇹🇬",
	"flag-th": "🇹🇭",
	"flag-tj": "🇹🇯",
	"flag-tk": "🇹🇰",
	"flag-tl": "🇹🇱",
	"flag-tm": "🇹🇲",
	"flag-tn": "🇹🇳",
	"flag-to": "🇹🇴",
	"flag-tr": "🇹🇷",
	"flag-tt": "🇹🇹",
	"flag-tv": "🇹🇻",
	"flag-tw": "🇹🇼",
	"flag-tz": "🇹🇿",
	"flag-ua": "🇺🇦",
	"flag-ug": "🇺🇬",
	"flag-um": "🇺🇲",
	"flag-un": "🇺🇳",
	us: us,
	"flag-us": "🇺🇸",
	"flag-uy": "🇺🇾",
	"flag-uz": "🇺🇿",
	"flag-va": "🇻🇦",
	"flag-vc": "🇻🇨",
	"flag-ve": "🇻🇪",
	"flag-vg": "🇻🇬",
	"flag-vi": "🇻🇮",
	"flag-vn": "🇻🇳",
	"flag-vu": "🇻🇺",
	"flag-wf": "🇼🇫",
	"flag-ws": "🇼🇸",
	"flag-xk": "🇽🇰",
	"flag-ye": "🇾🇪",
	"flag-yt": "🇾🇹",
	"flag-za": "🇿🇦",
	"flag-zm": "🇿🇲",
	"flag-zw": "🇿🇼",
	koko: koko,
	sa: sa,
	u7121: u7121,
	u6307: u6307,
	u7981: u7981,
	u7a7a: u7a7a,
	u5408: u5408,
	u6e80: u6e80,
	u6709: u6709,
	u6708: u6708,
	u7533: u7533,
	u5272: u5272,
	u55b6: u55b6,
	ideograph_advantage: ideograph_advantage,
	accept: accept,
	cyclone: cyclone,
	foggy: foggy,
	closed_umbrella: closed_umbrella,
	night_with_stars: night_with_stars,
	sunrise_over_mountains: sunrise_over_mountains,
	sunrise: sunrise,
	city_sunset: city_sunset,
	city_sunrise: city_sunrise,
	rainbow: rainbow,
	bridge_at_night: bridge_at_night,
	ocean: ocean,
	volcano: volcano,
	milky_way: milky_way,
	earth_africa: earth_africa,
	earth_americas: earth_americas,
	earth_asia: earth_asia,
	globe_with_meridians: globe_with_meridians,
	new_moon: new_moon,
	waxing_crescent_moon: waxing_crescent_moon,
	first_quarter_moon: first_quarter_moon,
	moon: moon,
	waxing_gibbous_moon: waxing_gibbous_moon,
	full_moon: full_moon,
	waning_gibbous_moon: waning_gibbous_moon,
	last_quarter_moon: last_quarter_moon,
	waning_crescent_moon: waning_crescent_moon,
	crescent_moon: crescent_moon,
	new_moon_with_face: new_moon_with_face,
	first_quarter_moon_with_face: first_quarter_moon_with_face,
	last_quarter_moon_with_face: last_quarter_moon_with_face,
	full_moon_with_face: full_moon_with_face,
	sun_with_face: sun_with_face,
	star2: star2,
	stars: stars,
	thermometer: thermometer,
	mostly_sunny: mostly_sunny,
	sun_small_cloud: sun_small_cloud,
	barely_sunny: barely_sunny,
	sun_behind_cloud: sun_behind_cloud,
	partly_sunny_rain: partly_sunny_rain,
	sun_behind_rain_cloud: sun_behind_rain_cloud,
	rain_cloud: rain_cloud,
	snow_cloud: snow_cloud,
	lightning: lightning,
	lightning_cloud: lightning_cloud,
	tornado: tornado,
	tornado_cloud: tornado_cloud,
	fog: fog,
	wind_blowing_face: wind_blowing_face,
	hotdog: hotdog,
	taco: taco,
	burrito: burrito,
	chestnut: chestnut,
	seedling: seedling,
	evergreen_tree: evergreen_tree,
	deciduous_tree: deciduous_tree,
	palm_tree: palm_tree,
	cactus: cactus,
	hot_pepper: hot_pepper,
	tulip: tulip,
	cherry_blossom: cherry_blossom,
	rose: rose,
	hibiscus: hibiscus,
	sunflower: sunflower,
	blossom: blossom,
	corn: corn,
	ear_of_rice: ear_of_rice,
	herb: herb,
	four_leaf_clover: four_leaf_clover,
	maple_leaf: maple_leaf,
	fallen_leaf: fallen_leaf,
	leaves: leaves,
	mushroom: mushroom,
	tomato: tomato,
	eggplant: eggplant,
	grapes: grapes,
	melon: melon,
	watermelon: watermelon,
	tangerine: tangerine,
	lemon: lemon,
	banana: banana,
	pineapple: pineapple,
	apple: apple,
	green_apple: green_apple,
	pear: pear,
	peach: peach,
	cherries: cherries,
	strawberry: strawberry,
	hamburger: hamburger,
	pizza: pizza,
	meat_on_bone: meat_on_bone,
	poultry_leg: poultry_leg,
	rice_cracker: rice_cracker,
	rice_ball: rice_ball,
	rice: rice,
	curry: curry,
	ramen: ramen,
	spaghetti: spaghetti,
	bread: bread,
	fries: fries,
	sweet_potato: sweet_potato,
	dango: dango,
	oden: oden,
	sushi: sushi,
	fried_shrimp: fried_shrimp,
	fish_cake: fish_cake,
	icecream: icecream,
	shaved_ice: shaved_ice,
	ice_cream: ice_cream,
	doughnut: doughnut,
	cookie: cookie,
	chocolate_bar: chocolate_bar,
	candy: candy,
	lollipop: lollipop,
	custard: custard,
	honey_pot: honey_pot,
	cake: cake,
	bento: bento,
	stew: stew,
	fried_egg: fried_egg,
	cooking: cooking,
	fork_and_knife: fork_and_knife,
	tea: tea,
	sake: sake,
	wine_glass: wine_glass,
	cocktail: cocktail,
	tropical_drink: tropical_drink,
	beer: beer,
	beers: beers,
	baby_bottle: baby_bottle,
	knife_fork_plate: knife_fork_plate,
	champagne: champagne,
	popcorn: popcorn,
	ribbon: ribbon,
	gift: gift,
	birthday: birthday,
	jack_o_lantern: jack_o_lantern,
	christmas_tree: christmas_tree,
	santa: santa,
	fireworks: fireworks,
	sparkler: sparkler,
	balloon: balloon,
	tada: tada,
	confetti_ball: confetti_ball,
	tanabata_tree: tanabata_tree,
	crossed_flags: crossed_flags,
	bamboo: bamboo,
	dolls: dolls,
	flags: flags,
	wind_chime: wind_chime,
	rice_scene: rice_scene,
	school_satchel: school_satchel,
	mortar_board: mortar_board,
	medal: medal,
	reminder_ribbon: reminder_ribbon,
	studio_microphone: studio_microphone,
	level_slider: level_slider,
	control_knobs: control_knobs,
	film_frames: film_frames,
	admission_tickets: admission_tickets,
	carousel_horse: carousel_horse,
	ferris_wheel: ferris_wheel,
	roller_coaster: roller_coaster,
	fishing_pole_and_fish: fishing_pole_and_fish,
	microphone: microphone,
	movie_camera: movie_camera,
	cinema: cinema,
	headphones: headphones,
	art: art,
	tophat: tophat,
	circus_tent: circus_tent,
	ticket: ticket,
	clapper: clapper,
	performing_arts: performing_arts,
	video_game: video_game,
	dart: dart,
	slot_machine: slot_machine,
	"8ball": "🎱",
	game_die: game_die,
	bowling: bowling,
	flower_playing_cards: flower_playing_cards,
	musical_note: musical_note,
	notes: notes,
	saxophone: saxophone,
	guitar: guitar,
	musical_keyboard: musical_keyboard,
	trumpet: trumpet,
	violin: violin,
	musical_score: musical_score,
	running_shirt_with_sash: running_shirt_with_sash,
	tennis: tennis,
	ski: ski,
	basketball: basketball,
	checkered_flag: checkered_flag,
	snowboarder: snowboarder,
	"woman-running": "🏃‍♀️",
	"man-running": "🏃‍♂️",
	runner: runner,
	running: running,
	"woman-surfing": "🏄‍♀️",
	"man-surfing": "🏄‍♂️",
	surfer: surfer,
	sports_medal: sports_medal,
	trophy: trophy,
	horse_racing: horse_racing,
	football: football,
	rugby_football: rugby_football,
	"woman-swimming": "🏊‍♀️",
	"man-swimming": "🏊‍♂️",
	swimmer: swimmer,
	"woman-lifting-weights": "🏋️‍♀️",
	"man-lifting-weights": "🏋️‍♂️",
	weight_lifter: weight_lifter,
	"woman-golfing": "🏌️‍♀️",
	"man-golfing": "🏌️‍♂️",
	golfer: golfer,
	racing_motorcycle: racing_motorcycle,
	racing_car: racing_car,
	cricket_bat_and_ball: cricket_bat_and_ball,
	volleyball: volleyball,
	field_hockey_stick_and_ball: field_hockey_stick_and_ball,
	ice_hockey_stick_and_puck: ice_hockey_stick_and_puck,
	table_tennis_paddle_and_ball: table_tennis_paddle_and_ball,
	snow_capped_mountain: snow_capped_mountain,
	camping: camping,
	beach_with_umbrella: beach_with_umbrella,
	building_construction: building_construction,
	house_buildings: house_buildings,
	cityscape: cityscape,
	derelict_house_building: derelict_house_building,
	classical_building: classical_building,
	desert: desert,
	desert_island: desert_island,
	national_park: national_park,
	stadium: stadium,
	house: house,
	house_with_garden: house_with_garden,
	office: office,
	post_office: post_office,
	european_post_office: european_post_office,
	hospital: hospital,
	bank: bank,
	atm: atm,
	hotel: hotel,
	love_hotel: love_hotel,
	convenience_store: convenience_store,
	school: school,
	department_store: department_store,
	factory: factory,
	izakaya_lantern: izakaya_lantern,
	lantern: lantern,
	japanese_castle: japanese_castle,
	european_castle: european_castle,
	"rainbow-flag": "🏳️‍🌈",
	waving_white_flag: waving_white_flag,
	"flag-england": "🏴󠁧󠁢󠁥󠁮󠁧󠁿",
	"flag-scotland": "🏴󠁧󠁢󠁳󠁣󠁴󠁿",
	"flag-wales": "🏴󠁧󠁢󠁷󠁬󠁳󠁿",
	waving_black_flag: waving_black_flag,
	rosette: rosette,
	label: label,
	badminton_racquet_and_shuttlecock: badminton_racquet_and_shuttlecock,
	bow_and_arrow: bow_and_arrow,
	amphora: amphora,
	"skin-tone-2": "🏻",
	"skin-tone-3": "🏼",
	"skin-tone-4": "🏽",
	"skin-tone-5": "🏾",
	"skin-tone-6": "🏿",
	rat: rat,
	mouse2: mouse2,
	ox: ox,
	water_buffalo: water_buffalo,
	cow2: cow2,
	tiger2: tiger2,
	leopard: leopard,
	rabbit2: rabbit2,
	cat2: cat2,
	dragon: dragon,
	crocodile: crocodile,
	whale2: whale2,
	snail: snail,
	snake: snake,
	racehorse: racehorse,
	ram: ram,
	goat: goat,
	sheep: sheep,
	monkey: monkey,
	rooster: rooster,
	chicken: chicken,
	dog2: dog2,
	pig2: pig2,
	boar: boar,
	elephant: elephant,
	octopus: octopus,
	shell: shell,
	bug: bug,
	ant: ant,
	bee: bee,
	honeybee: honeybee,
	beetle: beetle,
	fish: fish,
	tropical_fish: tropical_fish,
	blowfish: blowfish,
	turtle: turtle,
	hatching_chick: hatching_chick,
	baby_chick: baby_chick,
	hatched_chick: hatched_chick,
	bird: bird,
	penguin: penguin,
	koala: koala,
	poodle: poodle,
	dromedary_camel: dromedary_camel,
	camel: camel,
	dolphin: dolphin,
	flipper: flipper,
	mouse: mouse,
	cow: cow,
	tiger: tiger,
	rabbit: rabbit,
	cat: cat,
	dragon_face: dragon_face,
	whale: whale,
	horse: horse,
	monkey_face: monkey_face,
	dog: dog,
	pig: pig,
	frog: frog,
	hamster: hamster,
	wolf: wolf,
	bear: bear,
	panda_face: panda_face,
	pig_nose: pig_nose,
	feet: feet,
	paw_prints: paw_prints,
	chipmunk: chipmunk,
	eyes: eyes,
	"eye-in-speech-bubble": "👁️‍🗨️",
	eye: eye,
	ear: ear,
	nose: nose,
	lips: lips,
	tongue: tongue,
	point_up_2: point_up_2,
	point_down: point_down,
	point_left: point_left,
	point_right: point_right,
	facepunch: facepunch,
	punch: punch,
	wave: wave,
	ok_hand: ok_hand,
	"+1": "👍",
	thumbsup: thumbsup,
	"-1": "👎",
	thumbsdown: thumbsdown,
	clap: clap,
	open_hands: open_hands,
	crown: crown,
	womans_hat: womans_hat,
	eyeglasses: eyeglasses,
	necktie: necktie,
	shirt: shirt,
	tshirt: tshirt,
	jeans: jeans,
	dress: dress,
	kimono: kimono,
	bikini: bikini,
	womans_clothes: womans_clothes,
	purse: purse,
	handbag: handbag,
	pouch: pouch,
	mans_shoe: mans_shoe,
	shoe: shoe,
	athletic_shoe: athletic_shoe,
	high_heel: high_heel,
	sandal: sandal,
	boot: boot,
	footprints: footprints,
	bust_in_silhouette: bust_in_silhouette,
	busts_in_silhouette: busts_in_silhouette,
	boy: boy,
	girl: girl,
	"male-farmer": "👨‍🌾",
	"male-cook": "👨‍🍳",
	"male-student": "👨‍🎓",
	"male-singer": "👨‍🎤",
	"male-artist": "👨‍🎨",
	"male-teacher": "👨‍🏫",
	"male-factory-worker": "👨‍🏭",
	"man-boy-boy": "👨‍👦‍👦",
	"man-boy": "👨‍👦",
	"man-girl-boy": "👨‍👧‍👦",
	"man-girl-girl": "👨‍👧‍👧",
	"man-girl": "👨‍👧",
	"man-man-boy": "👨‍👨‍👦",
	"man-man-boy-boy": "👨‍👨‍👦‍👦",
	"man-man-girl": "👨‍👨‍👧",
	"man-man-girl-boy": "👨‍👨‍👧‍👦",
	"man-man-girl-girl": "👨‍👨‍👧‍👧",
	"man-woman-boy": "👨‍👩‍👦",
	family: family,
	"man-woman-boy-boy": "👨‍👩‍👦‍👦",
	"man-woman-girl": "👨‍👩‍👧",
	"man-woman-girl-boy": "👨‍👩‍👧‍👦",
	"man-woman-girl-girl": "👨‍👩‍👧‍👧",
	"male-technologist": "👨‍💻",
	"male-office-worker": "👨‍💼",
	"male-mechanic": "👨‍🔧",
	"male-scientist": "👨‍🔬",
	"male-astronaut": "👨‍🚀",
	"male-firefighter": "👨‍🚒",
	"male-doctor": "👨‍⚕️",
	"male-judge": "👨‍⚖️",
	"male-pilot": "👨‍✈️",
	"man-heart-man": "👨‍❤️‍👨",
	"man-kiss-man": "👨‍❤️‍💋‍👨",
	man: man,
	"female-farmer": "👩‍🌾",
	"female-cook": "👩‍🍳",
	"female-student": "👩‍🎓",
	"female-singer": "👩‍🎤",
	"female-artist": "👩‍🎨",
	"female-teacher": "👩‍🏫",
	"female-factory-worker": "👩‍🏭",
	"woman-boy-boy": "👩‍👦‍👦",
	"woman-boy": "👩‍👦",
	"woman-girl-boy": "👩‍👧‍👦",
	"woman-girl-girl": "👩‍👧‍👧",
	"woman-girl": "👩‍👧",
	"woman-woman-boy": "👩‍👩‍👦",
	"woman-woman-boy-boy": "👩‍👩‍👦‍👦",
	"woman-woman-girl": "👩‍👩‍👧",
	"woman-woman-girl-boy": "👩‍👩‍👧‍👦",
	"woman-woman-girl-girl": "👩‍👩‍👧‍👧",
	"female-technologist": "👩‍💻",
	"female-office-worker": "👩‍💼",
	"female-mechanic": "👩‍🔧",
	"female-scientist": "👩‍🔬",
	"female-astronaut": "👩‍🚀",
	"female-firefighter": "👩‍🚒",
	"female-doctor": "👩‍⚕️",
	"female-judge": "👩‍⚖️",
	"female-pilot": "👩‍✈️",
	"woman-heart-man": "👩‍❤️‍👨",
	couple_with_heart: couple_with_heart,
	"woman-heart-woman": "👩‍❤️‍👩",
	"woman-kiss-man": "👩‍❤️‍💋‍👨",
	couplekiss: couplekiss,
	"woman-kiss-woman": "👩‍❤️‍💋‍👩",
	woman: woman,
	couple: couple,
	man_and_woman_holding_hands: man_and_woman_holding_hands,
	two_men_holding_hands: two_men_holding_hands,
	two_women_holding_hands: two_women_holding_hands,
	"female-police-officer": "👮‍♀️",
	"male-police-officer": "👮‍♂️",
	cop: cop,
	"woman-with-bunny-ears-partying": "👯‍♀️",
	dancers: dancers,
	"man-with-bunny-ears-partying": "👯‍♂️",
	bride_with_veil: bride_with_veil,
	"blond-haired-woman": "👱‍♀️",
	"blond-haired-man": "👱‍♂️",
	person_with_blond_hair: person_with_blond_hair,
	man_with_gua_pi_mao: man_with_gua_pi_mao,
	"woman-wearing-turban": "👳‍♀️",
	"man-wearing-turban": "👳‍♂️",
	man_with_turban: man_with_turban,
	older_man: older_man,
	older_woman: older_woman,
	baby: baby,
	"female-construction-worker": "👷‍♀️",
	"male-construction-worker": "👷‍♂️",
	construction_worker: construction_worker,
	princess: princess,
	japanese_ogre: japanese_ogre,
	japanese_goblin: japanese_goblin,
	ghost: ghost,
	angel: angel,
	alien: alien,
	space_invader: space_invader,
	imp: imp,
	skull: skull,
	"woman-tipping-hand": "💁‍♀️",
	information_desk_person: information_desk_person,
	"man-tipping-hand": "💁‍♂️",
	"female-guard": "💂‍♀️",
	"male-guard": "💂‍♂️",
	guardsman: guardsman,
	dancer: dancer,
	lipstick: lipstick,
	nail_care: nail_care,
	"woman-getting-massage": "💆‍♀️",
	massage: massage,
	"man-getting-massage": "💆‍♂️",
	"woman-getting-haircut": "💇‍♀️",
	haircut: haircut,
	"man-getting-haircut": "💇‍♂️",
	barber: barber,
	syringe: syringe,
	pill: pill,
	kiss: kiss,
	love_letter: love_letter,
	ring: ring,
	gem: gem,
	bouquet: bouquet,
	wedding: wedding,
	heartbeat: heartbeat,
	broken_heart: broken_heart,
	two_hearts: two_hearts,
	sparkling_heart: sparkling_heart,
	heartpulse: heartpulse,
	cupid: cupid,
	blue_heart: blue_heart,
	green_heart: green_heart,
	yellow_heart: yellow_heart,
	purple_heart: purple_heart,
	gift_heart: gift_heart,
	revolving_hearts: revolving_hearts,
	heart_decoration: heart_decoration,
	diamond_shape_with_a_dot_inside: diamond_shape_with_a_dot_inside,
	bulb: bulb,
	anger: anger,
	bomb: bomb,
	zzz: zzz,
	boom: boom,
	collision: collision,
	sweat_drops: sweat_drops,
	droplet: droplet,
	dash: dash,
	hankey: hankey,
	poop: poop,
	shit: shit,
	muscle: muscle,
	dizzy: dizzy,
	speech_balloon: speech_balloon,
	thought_balloon: thought_balloon,
	white_flower: white_flower,
	moneybag: moneybag,
	currency_exchange: currency_exchange,
	heavy_dollar_sign: heavy_dollar_sign,
	credit_card: credit_card,
	yen: yen,
	dollar: dollar,
	euro: euro,
	pound: pound,
	money_with_wings: money_with_wings,
	chart: chart,
	seat: seat,
	computer: computer,
	briefcase: briefcase,
	minidisc: minidisc,
	floppy_disk: floppy_disk,
	cd: cd,
	dvd: dvd,
	file_folder: file_folder,
	open_file_folder: open_file_folder,
	page_with_curl: page_with_curl,
	page_facing_up: page_facing_up,
	date: date,
	calendar: calendar,
	card_index: card_index,
	chart_with_upwards_trend: chart_with_upwards_trend,
	chart_with_downwards_trend: chart_with_downwards_trend,
	bar_chart: bar_chart,
	clipboard: clipboard,
	pushpin: pushpin,
	round_pushpin: round_pushpin,
	paperclip: paperclip,
	straight_ruler: straight_ruler,
	triangular_ruler: triangular_ruler,
	bookmark_tabs: bookmark_tabs,
	ledger: ledger,
	notebook: notebook,
	notebook_with_decorative_cover: notebook_with_decorative_cover,
	closed_book: closed_book,
	book: book,
	open_book: open_book,
	green_book: green_book,
	blue_book: blue_book,
	orange_book: orange_book,
	books: books,
	name_badge: name_badge,
	scroll: scroll,
	memo: memo,
	pencil: pencil,
	telephone_receiver: telephone_receiver,
	pager: pager,
	fax: fax,
	satellite_antenna: satellite_antenna,
	loudspeaker: loudspeaker,
	mega: mega,
	outbox_tray: outbox_tray,
	inbox_tray: inbox_tray,
	"package": "📦",
	"e-mail": "📧",
	incoming_envelope: incoming_envelope,
	envelope_with_arrow: envelope_with_arrow,
	mailbox_closed: mailbox_closed,
	mailbox: mailbox,
	mailbox_with_mail: mailbox_with_mail,
	mailbox_with_no_mail: mailbox_with_no_mail,
	postbox: postbox,
	postal_horn: postal_horn,
	newspaper: newspaper,
	iphone: iphone,
	calling: calling,
	vibration_mode: vibration_mode,
	mobile_phone_off: mobile_phone_off,
	no_mobile_phones: no_mobile_phones,
	signal_strength: signal_strength,
	camera: camera,
	camera_with_flash: camera_with_flash,
	video_camera: video_camera,
	tv: tv,
	radio: radio,
	vhs: vhs,
	film_projector: film_projector,
	prayer_beads: prayer_beads,
	twisted_rightwards_arrows: twisted_rightwards_arrows,
	repeat: repeat,
	repeat_one: repeat_one,
	arrows_clockwise: arrows_clockwise,
	arrows_counterclockwise: arrows_counterclockwise,
	low_brightness: low_brightness,
	high_brightness: high_brightness,
	mute: mute,
	speaker: speaker,
	sound: sound,
	loud_sound: loud_sound,
	battery: battery,
	electric_plug: electric_plug,
	mag: mag,
	mag_right: mag_right,
	lock_with_ink_pen: lock_with_ink_pen,
	closed_lock_with_key: closed_lock_with_key,
	key: key,
	lock: lock,
	unlock: unlock,
	bell: bell,
	no_bell: no_bell,
	bookmark: bookmark,
	link: link,
	radio_button: radio_button,
	back: back,
	end: end,
	on: on,
	soon: soon,
	top: top,
	underage: underage,
	keycap_ten: keycap_ten,
	capital_abcd: capital_abcd,
	abcd: abcd,
	symbols: symbols,
	abc: abc,
	fire: fire,
	flashlight: flashlight,
	wrench: wrench,
	hammer: hammer,
	nut_and_bolt: nut_and_bolt,
	hocho: hocho,
	knife: knife,
	gun: gun,
	microscope: microscope,
	telescope: telescope,
	crystal_ball: crystal_ball,
	six_pointed_star: six_pointed_star,
	beginner: beginner,
	trident: trident,
	black_square_button: black_square_button,
	white_square_button: white_square_button,
	red_circle: red_circle,
	large_blue_circle: large_blue_circle,
	large_orange_diamond: large_orange_diamond,
	large_blue_diamond: large_blue_diamond,
	small_orange_diamond: small_orange_diamond,
	small_blue_diamond: small_blue_diamond,
	small_red_triangle: small_red_triangle,
	small_red_triangle_down: small_red_triangle_down,
	arrow_up_small: arrow_up_small,
	arrow_down_small: arrow_down_small,
	om_symbol: om_symbol,
	dove_of_peace: dove_of_peace,
	kaaba: kaaba,
	mosque: mosque,
	synagogue: synagogue,
	menorah_with_nine_branches: menorah_with_nine_branches,
	clock1: clock1,
	clock2: clock2,
	clock3: clock3,
	clock4: clock4,
	clock5: clock5,
	clock6: clock6,
	clock7: clock7,
	clock8: clock8,
	clock9: clock9,
	clock10: clock10,
	clock11: clock11,
	clock12: clock12,
	clock130: clock130,
	clock230: clock230,
	clock330: clock330,
	clock430: clock430,
	clock530: clock530,
	clock630: clock630,
	clock730: clock730,
	clock830: clock830,
	clock930: clock930,
	clock1030: clock1030,
	clock1130: clock1130,
	clock1230: clock1230,
	candle: candle,
	mantelpiece_clock: mantelpiece_clock,
	hole: hole,
	man_in_business_suit_levitating: man_in_business_suit_levitating,
	"female-detective": "🕵️‍♀️",
	"male-detective": "🕵️‍♂️",
	sleuth_or_spy: sleuth_or_spy,
	dark_sunglasses: dark_sunglasses,
	spider: spider,
	spider_web: spider_web,
	joystick: joystick,
	man_dancing: man_dancing,
	linked_paperclips: linked_paperclips,
	lower_left_ballpoint_pen: lower_left_ballpoint_pen,
	lower_left_fountain_pen: lower_left_fountain_pen,
	lower_left_paintbrush: lower_left_paintbrush,
	lower_left_crayon: lower_left_crayon,
	raised_hand_with_fingers_splayed: raised_hand_with_fingers_splayed,
	middle_finger: middle_finger,
	reversed_hand_with_middle_finger_extended: reversed_hand_with_middle_finger_extended,
	"spock-hand": "🖖",
	black_heart: black_heart,
	desktop_computer: desktop_computer,
	printer: printer,
	three_button_mouse: three_button_mouse,
	trackball: trackball,
	frame_with_picture: frame_with_picture,
	card_index_dividers: card_index_dividers,
	card_file_box: card_file_box,
	file_cabinet: file_cabinet,
	wastebasket: wastebasket,
	spiral_note_pad: spiral_note_pad,
	spiral_calendar_pad: spiral_calendar_pad,
	compression: compression,
	old_key: old_key,
	rolled_up_newspaper: rolled_up_newspaper,
	dagger_knife: dagger_knife,
	speaking_head_in_silhouette: speaking_head_in_silhouette,
	left_speech_bubble: left_speech_bubble,
	right_anger_bubble: right_anger_bubble,
	ballot_box_with_ballot: ballot_box_with_ballot,
	world_map: world_map,
	mount_fuji: mount_fuji,
	tokyo_tower: tokyo_tower,
	statue_of_liberty: statue_of_liberty,
	japan: japan,
	moyai: moyai,
	grinning: grinning,
	grin: grin,
	joy: joy,
	smiley: smiley,
	smile: smile,
	sweat_smile: sweat_smile,
	laughing: laughing,
	satisfied: satisfied,
	innocent: innocent,
	smiling_imp: smiling_imp,
	wink: wink,
	blush: blush,
	yum: yum,
	relieved: relieved,
	heart_eyes: heart_eyes,
	sunglasses: sunglasses,
	smirk: smirk,
	neutral_face: neutral_face,
	expressionless: expressionless,
	unamused: unamused,
	sweat: sweat,
	pensive: pensive,
	confused: confused,
	confounded: confounded,
	kissing: kissing,
	kissing_heart: kissing_heart,
	kissing_smiling_eyes: kissing_smiling_eyes,
	kissing_closed_eyes: kissing_closed_eyes,
	stuck_out_tongue: stuck_out_tongue,
	stuck_out_tongue_winking_eye: stuck_out_tongue_winking_eye,
	stuck_out_tongue_closed_eyes: stuck_out_tongue_closed_eyes,
	disappointed: disappointed,
	worried: worried,
	angry: angry,
	rage: rage,
	cry: cry,
	persevere: persevere,
	triumph: triumph,
	disappointed_relieved: disappointed_relieved,
	frowning: frowning,
	anguished: anguished,
	fearful: fearful,
	weary: weary,
	sleepy: sleepy,
	tired_face: tired_face,
	grimacing: grimacing,
	sob: sob,
	open_mouth: open_mouth,
	hushed: hushed,
	cold_sweat: cold_sweat,
	scream: scream,
	astonished: astonished,
	flushed: flushed,
	sleeping: sleeping,
	dizzy_face: dizzy_face,
	no_mouth: no_mouth,
	mask: mask,
	smile_cat: smile_cat,
	joy_cat: joy_cat,
	smiley_cat: smiley_cat,
	heart_eyes_cat: heart_eyes_cat,
	smirk_cat: smirk_cat,
	kissing_cat: kissing_cat,
	pouting_cat: pouting_cat,
	crying_cat_face: crying_cat_face,
	scream_cat: scream_cat,
	slightly_frowning_face: slightly_frowning_face,
	slightly_smiling_face: slightly_smiling_face,
	upside_down_face: upside_down_face,
	face_with_rolling_eyes: face_with_rolling_eyes,
	"woman-gesturing-no": "🙅‍♀️",
	no_good: no_good,
	"man-gesturing-no": "🙅‍♂️",
	"woman-gesturing-ok": "🙆‍♀️",
	ok_woman: ok_woman,
	"man-gesturing-ok": "🙆‍♂️",
	"woman-bowing": "🙇‍♀️",
	"man-bowing": "🙇‍♂️",
	bow: bow,
	see_no_evil: see_no_evil,
	hear_no_evil: hear_no_evil,
	speak_no_evil: speak_no_evil,
	"woman-raising-hand": "🙋‍♀️",
	raising_hand: raising_hand,
	"man-raising-hand": "🙋‍♂️",
	raised_hands: raised_hands,
	"woman-frowning": "🙍‍♀️",
	person_frowning: person_frowning,
	"man-frowning": "🙍‍♂️",
	"woman-pouting": "🙎‍♀️",
	person_with_pouting_face: person_with_pouting_face,
	"man-pouting": "🙎‍♂️",
	pray: pray,
	rocket: rocket,
	helicopter: helicopter,
	steam_locomotive: steam_locomotive,
	railway_car: railway_car,
	bullettrain_side: bullettrain_side,
	bullettrain_front: bullettrain_front,
	train2: train2,
	metro: metro,
	light_rail: light_rail,
	station: station,
	tram: tram,
	train: train,
	bus: bus,
	oncoming_bus: oncoming_bus,
	trolleybus: trolleybus,
	busstop: busstop,
	minibus: minibus,
	ambulance: ambulance,
	fire_engine: fire_engine,
	police_car: police_car,
	oncoming_police_car: oncoming_police_car,
	taxi: taxi,
	oncoming_taxi: oncoming_taxi,
	car: car,
	red_car: red_car,
	oncoming_automobile: oncoming_automobile,
	blue_car: blue_car,
	truck: truck,
	articulated_lorry: articulated_lorry,
	tractor: tractor,
	monorail: monorail,
	mountain_railway: mountain_railway,
	suspension_railway: suspension_railway,
	mountain_cableway: mountain_cableway,
	aerial_tramway: aerial_tramway,
	ship: ship,
	"woman-rowing-boat": "🚣‍♀️",
	"man-rowing-boat": "🚣‍♂️",
	rowboat: rowboat,
	speedboat: speedboat,
	traffic_light: traffic_light,
	vertical_traffic_light: vertical_traffic_light,
	construction: construction,
	rotating_light: rotating_light,
	triangular_flag_on_post: triangular_flag_on_post,
	door: door,
	no_entry_sign: no_entry_sign,
	smoking: smoking,
	no_smoking: no_smoking,
	put_litter_in_its_place: put_litter_in_its_place,
	do_not_litter: do_not_litter,
	potable_water: potable_water,
	"non-potable_water": "🚱",
	bike: bike,
	no_bicycles: no_bicycles,
	"woman-biking": "🚴‍♀️",
	"man-biking": "🚴‍♂️",
	bicyclist: bicyclist,
	"woman-mountain-biking": "🚵‍♀️",
	"man-mountain-biking": "🚵‍♂️",
	mountain_bicyclist: mountain_bicyclist,
	"woman-walking": "🚶‍♀️",
	"man-walking": "🚶‍♂️",
	walking: walking,
	no_pedestrians: no_pedestrians,
	children_crossing: children_crossing,
	mens: mens,
	womens: womens,
	restroom: restroom,
	baby_symbol: baby_symbol,
	toilet: toilet,
	wc: wc,
	shower: shower,
	bath: bath,
	bathtub: bathtub,
	passport_control: passport_control,
	customs: customs,
	baggage_claim: baggage_claim,
	left_luggage: left_luggage,
	couch_and_lamp: couch_and_lamp,
	sleeping_accommodation: sleeping_accommodation,
	shopping_bags: shopping_bags,
	bellhop_bell: bellhop_bell,
	bed: bed,
	place_of_worship: place_of_worship,
	octagonal_sign: octagonal_sign,
	shopping_trolley: shopping_trolley,
	hammer_and_wrench: hammer_and_wrench,
	shield: shield,
	oil_drum: oil_drum,
	motorway: motorway,
	railway_track: railway_track,
	motor_boat: motor_boat,
	small_airplane: small_airplane,
	airplane_departure: airplane_departure,
	airplane_arriving: airplane_arriving,
	satellite: satellite,
	passenger_ship: passenger_ship,
	scooter: scooter,
	motor_scooter: motor_scooter,
	canoe: canoe,
	sled: sled,
	flying_saucer: flying_saucer,
	zipper_mouth_face: zipper_mouth_face,
	money_mouth_face: money_mouth_face,
	face_with_thermometer: face_with_thermometer,
	nerd_face: nerd_face,
	thinking_face: thinking_face,
	face_with_head_bandage: face_with_head_bandage,
	robot_face: robot_face,
	hugging_face: hugging_face,
	the_horns: the_horns,
	sign_of_the_horns: sign_of_the_horns,
	call_me_hand: call_me_hand,
	raised_back_of_hand: raised_back_of_hand,
	"left-facing_fist": "🤛",
	"right-facing_fist": "🤜",
	handshake: handshake,
	crossed_fingers: crossed_fingers,
	hand_with_index_and_middle_fingers_crossed: hand_with_index_and_middle_fingers_crossed,
	i_love_you_hand_sign: i_love_you_hand_sign,
	face_with_cowboy_hat: face_with_cowboy_hat,
	clown_face: clown_face,
	nauseated_face: nauseated_face,
	rolling_on_the_floor_laughing: rolling_on_the_floor_laughing,
	drooling_face: drooling_face,
	lying_face: lying_face,
	"woman-facepalming": "🤦‍♀️",
	"man-facepalming": "🤦‍♂️",
	face_palm: face_palm,
	sneezing_face: sneezing_face,
	face_with_raised_eyebrow: face_with_raised_eyebrow,
	face_with_one_eyebrow_raised: face_with_one_eyebrow_raised,
	"star-struck": "🤩",
	grinning_face_with_star_eyes: grinning_face_with_star_eyes,
	zany_face: zany_face,
	grinning_face_with_one_large_and_one_small_eye: grinning_face_with_one_large_and_one_small_eye,
	shushing_face: shushing_face,
	face_with_finger_covering_closed_lips: face_with_finger_covering_closed_lips,
	face_with_symbols_on_mouth: face_with_symbols_on_mouth,
	serious_face_with_symbols_covering_mouth: serious_face_with_symbols_covering_mouth,
	face_with_hand_over_mouth: face_with_hand_over_mouth,
	smiling_face_with_smiling_eyes_and_hand_covering_mouth: smiling_face_with_smiling_eyes_and_hand_covering_mouth,
	face_vomiting: face_vomiting,
	face_with_open_mouth_vomiting: face_with_open_mouth_vomiting,
	exploding_head: exploding_head,
	shocked_face_with_exploding_head: shocked_face_with_exploding_head,
	pregnant_woman: pregnant_woman,
	"breast-feeding": "🤱",
	palms_up_together: palms_up_together,
	selfie: selfie,
	prince: prince,
	man_in_tuxedo: man_in_tuxedo,
	mrs_claus: mrs_claus,
	mother_christmas: mother_christmas,
	"woman-shrugging": "🤷‍♀️",
	"man-shrugging": "🤷‍♂️",
	shrug: shrug,
	"woman-cartwheeling": "🤸‍♀️",
	"man-cartwheeling": "🤸‍♂️",
	person_doing_cartwheel: person_doing_cartwheel,
	"woman-juggling": "🤹‍♀️",
	"man-juggling": "🤹‍♂️",
	juggling: juggling,
	fencer: fencer,
	"woman-wrestling": "🤼‍♀️",
	"man-wrestling": "🤼‍♂️",
	wrestlers: wrestlers,
	"woman-playing-water-polo": "🤽‍♀️",
	"man-playing-water-polo": "🤽‍♂️",
	water_polo: water_polo,
	"woman-playing-handball": "🤾‍♀️",
	"man-playing-handball": "🤾‍♂️",
	handball: handball,
	wilted_flower: wilted_flower,
	drum_with_drumsticks: drum_with_drumsticks,
	clinking_glasses: clinking_glasses,
	tumbler_glass: tumbler_glass,
	spoon: spoon,
	goal_net: goal_net,
	first_place_medal: first_place_medal,
	second_place_medal: second_place_medal,
	third_place_medal: third_place_medal,
	boxing_glove: boxing_glove,
	martial_arts_uniform: martial_arts_uniform,
	curling_stone: curling_stone,
	croissant: croissant,
	avocado: avocado,
	cucumber: cucumber,
	bacon: bacon,
	potato: potato,
	carrot: carrot,
	baguette_bread: baguette_bread,
	green_salad: green_salad,
	shallow_pan_of_food: shallow_pan_of_food,
	stuffed_flatbread: stuffed_flatbread,
	egg: egg,
	glass_of_milk: glass_of_milk,
	peanuts: peanuts,
	kiwifruit: kiwifruit,
	pancakes: pancakes,
	dumpling: dumpling,
	fortune_cookie: fortune_cookie,
	takeout_box: takeout_box,
	chopsticks: chopsticks,
	bowl_with_spoon: bowl_with_spoon,
	cup_with_straw: cup_with_straw,
	coconut: coconut,
	broccoli: broccoli,
	pie: pie,
	pretzel: pretzel,
	cut_of_meat: cut_of_meat,
	sandwich: sandwich,
	canned_food: canned_food,
	crab: crab,
	lion_face: lion_face,
	scorpion: scorpion,
	turkey: turkey,
	unicorn_face: unicorn_face,
	eagle: eagle,
	duck: duck,
	bat: bat,
	shark: shark,
	owl: owl,
	fox_face: fox_face,
	butterfly: butterfly,
	deer: deer,
	gorilla: gorilla,
	lizard: lizard,
	rhinoceros: rhinoceros,
	shrimp: shrimp,
	squid: squid,
	giraffe_face: giraffe_face,
	zebra_face: zebra_face,
	hedgehog: hedgehog,
	sauropod: sauropod,
	"t-rex": "🦖",
	cricket: cricket,
	cheese_wedge: cheese_wedge,
	face_with_monocle: face_with_monocle,
	adult: adult,
	child: child,
	older_adult: older_adult,
	bearded_person: bearded_person,
	person_with_headscarf: person_with_headscarf,
	woman_in_steamy_room: woman_in_steamy_room,
	man_in_steamy_room: man_in_steamy_room,
	person_in_steamy_room: person_in_steamy_room,
	woman_climbing: woman_climbing,
	person_climbing: person_climbing,
	man_climbing: man_climbing,
	woman_in_lotus_position: woman_in_lotus_position,
	person_in_lotus_position: person_in_lotus_position,
	man_in_lotus_position: man_in_lotus_position,
	female_mage: female_mage,
	mage: mage,
	male_mage: male_mage,
	female_fairy: female_fairy,
	fairy: fairy,
	male_fairy: male_fairy,
	female_vampire: female_vampire,
	vampire: vampire,
	male_vampire: male_vampire,
	mermaid: mermaid,
	merman: merman,
	merperson: merperson,
	female_elf: female_elf,
	male_elf: male_elf,
	elf: elf,
	female_genie: female_genie,
	male_genie: male_genie,
	genie: genie,
	female_zombie: female_zombie,
	male_zombie: male_zombie,
	zombie: zombie,
	brain: brain,
	orange_heart: orange_heart,
	billed_cap: billed_cap,
	scarf: scarf,
	gloves: gloves,
	coat: coat,
	socks: socks,
	bangbang: bangbang,
	interrobang: interrobang,
	tm: tm,
	information_source: information_source,
	left_right_arrow: left_right_arrow,
	arrow_up_down: arrow_up_down,
	arrow_upper_left: arrow_upper_left,
	arrow_upper_right: arrow_upper_right,
	arrow_lower_right: arrow_lower_right,
	arrow_lower_left: arrow_lower_left,
	leftwards_arrow_with_hook: leftwards_arrow_with_hook,
	arrow_right_hook: arrow_right_hook,
	watch: watch,
	hourglass: hourglass,
	keyboard: keyboard,
	eject: eject,
	fast_forward: fast_forward,
	rewind: rewind,
	arrow_double_up: arrow_double_up,
	arrow_double_down: arrow_double_down,
	black_right_pointing_double_triangle_with_vertical_bar: black_right_pointing_double_triangle_with_vertical_bar,
	black_left_pointing_double_triangle_with_vertical_bar: black_left_pointing_double_triangle_with_vertical_bar,
	black_right_pointing_triangle_with_double_vertical_bar: black_right_pointing_triangle_with_double_vertical_bar,
	alarm_clock: alarm_clock,
	stopwatch: stopwatch,
	timer_clock: timer_clock,
	hourglass_flowing_sand: hourglass_flowing_sand,
	double_vertical_bar: double_vertical_bar,
	black_square_for_stop: black_square_for_stop,
	black_circle_for_record: black_circle_for_record,
	m: m,
	black_small_square: black_small_square,
	white_small_square: white_small_square,
	arrow_forward: arrow_forward,
	arrow_backward: arrow_backward,
	white_medium_square: white_medium_square,
	black_medium_square: black_medium_square,
	white_medium_small_square: white_medium_small_square,
	black_medium_small_square: black_medium_small_square,
	sunny: sunny,
	cloud: cloud,
	umbrella: umbrella,
	snowman: snowman,
	comet: comet,
	phone: phone,
	telephone: telephone,
	ballot_box_with_check: ballot_box_with_check,
	shamrock: shamrock,
	point_up: point_up,
	skull_and_crossbones: skull_and_crossbones,
	radioactive_sign: radioactive_sign,
	biohazard_sign: biohazard_sign,
	orthodox_cross: orthodox_cross,
	star_and_crescent: star_and_crescent,
	peace_symbol: peace_symbol,
	yin_yang: yin_yang,
	wheel_of_dharma: wheel_of_dharma,
	white_frowning_face: white_frowning_face,
	relaxed: relaxed,
	female_sign: female_sign,
	male_sign: male_sign,
	gemini: gemini,
	cancer: cancer,
	leo: leo,
	virgo: virgo,
	libra: libra,
	scorpius: scorpius,
	spades: spades,
	clubs: clubs,
	hearts: hearts,
	diamonds: diamonds,
	hotsprings: hotsprings,
	recycle: recycle,
	wheelchair: wheelchair,
	hammer_and_pick: hammer_and_pick,
	crossed_swords: crossed_swords,
	medical_symbol: medical_symbol,
	staff_of_aesculapius: staff_of_aesculapius,
	scales: scales,
	alembic: alembic,
	gear: gear,
	atom_symbol: atom_symbol,
	fleur_de_lis: fleur_de_lis,
	warning: warning,
	zap: zap,
	white_circle: white_circle,
	black_circle: black_circle,
	coffin: coffin,
	funeral_urn: funeral_urn,
	soccer: soccer,
	baseball: baseball,
	snowman_without_snow: snowman_without_snow,
	partly_sunny: partly_sunny,
	thunder_cloud_and_rain: thunder_cloud_and_rain,
	ophiuchus: ophiuchus,
	pick: pick,
	helmet_with_white_cross: helmet_with_white_cross,
	chains: chains,
	no_entry: no_entry,
	shinto_shrine: shinto_shrine,
	church: church,
	mountain: mountain,
	umbrella_on_ground: umbrella_on_ground,
	fountain: fountain,
	golf: golf,
	ferry: ferry,
	boat: boat,
	sailboat: sailboat,
	skier: skier,
	ice_skate: ice_skate,
	"woman-bouncing-ball": "⛹️‍♀️",
	"man-bouncing-ball": "⛹️‍♂️",
	person_with_ball: person_with_ball,
	tent: tent,
	fuelpump: fuelpump,
	scissors: scissors,
	airplane: airplane,
	email: email,
	envelope: envelope,
	fist: fist,
	hand: hand,
	raised_hand: raised_hand,
	v: v,
	writing_hand: writing_hand,
	pencil2: pencil2,
	black_nib: black_nib,
	heavy_check_mark: heavy_check_mark,
	heavy_multiplication_x: heavy_multiplication_x,
	latin_cross: latin_cross,
	star_of_david: star_of_david,
	eight_spoked_asterisk: eight_spoked_asterisk,
	eight_pointed_black_star: eight_pointed_black_star,
	snowflake: snowflake,
	sparkle: sparkle,
	x: x,
	negative_squared_cross_mark: negative_squared_cross_mark,
	heavy_heart_exclamation_mark_ornament: heavy_heart_exclamation_mark_ornament,
	heart: heart,
	arrow_right: arrow_right,
	curly_loop: curly_loop,
	loop: loop,
	arrow_heading_up: arrow_heading_up,
	arrow_heading_down: arrow_heading_down,
	arrow_left: arrow_left,
	arrow_up: arrow_up,
	arrow_down: arrow_down,
	black_large_square: black_large_square,
	white_large_square: white_large_square,
	star: star,
	o: o,
	wavy_dash: wavy_dash,
	part_alternation_mark: part_alternation_mark,
	congratulations: congratulations,
	secret: secret
};

var emoji$1 = /*#__PURE__*/Object.freeze({
    __proto__: null,
    umbrella_with_rain_drops: umbrella_with_rain_drops,
    coffee: coffee,
    aries: aries,
    taurus: taurus,
    sagittarius: sagittarius,
    capricorn: capricorn,
    aquarius: aquarius,
    pisces: pisces,
    anchor: anchor,
    white_check_mark: white_check_mark,
    sparkles: sparkles,
    question: question,
    grey_question: grey_question,
    grey_exclamation: grey_exclamation,
    exclamation: exclamation,
    heavy_exclamation_mark: heavy_exclamation_mark,
    heavy_plus_sign: heavy_plus_sign,
    heavy_minus_sign: heavy_minus_sign,
    heavy_division_sign: heavy_division_sign,
    hash: hash,
    keycap_star: keycap_star,
    zero: zero,
    one: one,
    two: two,
    three: three,
    four: four,
    five: five,
    six: six,
    seven: seven,
    eight: eight,
    nine: nine,
    copyright: copyright,
    registered: registered,
    mahjong: mahjong,
    black_joker: black_joker,
    a: a,
    b: b,
    o2: o2,
    parking: parking,
    ab: ab,
    cl: cl,
    cool: cool,
    free: free,
    id: id,
    ng: ng,
    ok: ok,
    sos: sos,
    up: up,
    vs: vs,
    cn: cn,
    de: de,
    es: es,
    fr: fr,
    gb: gb,
    uk: uk,
    it: it,
    jp: jp,
    kr: kr,
    ru: ru,
    us: us,
    koko: koko,
    sa: sa,
    u7121: u7121,
    u6307: u6307,
    u7981: u7981,
    u7a7a: u7a7a,
    u5408: u5408,
    u6e80: u6e80,
    u6709: u6709,
    u6708: u6708,
    u7533: u7533,
    u5272: u5272,
    u55b6: u55b6,
    ideograph_advantage: ideograph_advantage,
    accept: accept,
    cyclone: cyclone,
    foggy: foggy,
    closed_umbrella: closed_umbrella,
    night_with_stars: night_with_stars,
    sunrise_over_mountains: sunrise_over_mountains,
    sunrise: sunrise,
    city_sunset: city_sunset,
    city_sunrise: city_sunrise,
    rainbow: rainbow,
    bridge_at_night: bridge_at_night,
    ocean: ocean,
    volcano: volcano,
    milky_way: milky_way,
    earth_africa: earth_africa,
    earth_americas: earth_americas,
    earth_asia: earth_asia,
    globe_with_meridians: globe_with_meridians,
    new_moon: new_moon,
    waxing_crescent_moon: waxing_crescent_moon,
    first_quarter_moon: first_quarter_moon,
    moon: moon,
    waxing_gibbous_moon: waxing_gibbous_moon,
    full_moon: full_moon,
    waning_gibbous_moon: waning_gibbous_moon,
    last_quarter_moon: last_quarter_moon,
    waning_crescent_moon: waning_crescent_moon,
    crescent_moon: crescent_moon,
    new_moon_with_face: new_moon_with_face,
    first_quarter_moon_with_face: first_quarter_moon_with_face,
    last_quarter_moon_with_face: last_quarter_moon_with_face,
    full_moon_with_face: full_moon_with_face,
    sun_with_face: sun_with_face,
    star2: star2,
    stars: stars,
    thermometer: thermometer,
    mostly_sunny: mostly_sunny,
    sun_small_cloud: sun_small_cloud,
    barely_sunny: barely_sunny,
    sun_behind_cloud: sun_behind_cloud,
    partly_sunny_rain: partly_sunny_rain,
    sun_behind_rain_cloud: sun_behind_rain_cloud,
    rain_cloud: rain_cloud,
    snow_cloud: snow_cloud,
    lightning: lightning,
    lightning_cloud: lightning_cloud,
    tornado: tornado,
    tornado_cloud: tornado_cloud,
    fog: fog,
    wind_blowing_face: wind_blowing_face,
    hotdog: hotdog,
    taco: taco,
    burrito: burrito,
    chestnut: chestnut,
    seedling: seedling,
    evergreen_tree: evergreen_tree,
    deciduous_tree: deciduous_tree,
    palm_tree: palm_tree,
    cactus: cactus,
    hot_pepper: hot_pepper,
    tulip: tulip,
    cherry_blossom: cherry_blossom,
    rose: rose,
    hibiscus: hibiscus,
    sunflower: sunflower,
    blossom: blossom,
    corn: corn,
    ear_of_rice: ear_of_rice,
    herb: herb,
    four_leaf_clover: four_leaf_clover,
    maple_leaf: maple_leaf,
    fallen_leaf: fallen_leaf,
    leaves: leaves,
    mushroom: mushroom,
    tomato: tomato,
    eggplant: eggplant,
    grapes: grapes,
    melon: melon,
    watermelon: watermelon,
    tangerine: tangerine,
    lemon: lemon,
    banana: banana,
    pineapple: pineapple,
    apple: apple,
    green_apple: green_apple,
    pear: pear,
    peach: peach,
    cherries: cherries,
    strawberry: strawberry,
    hamburger: hamburger,
    pizza: pizza,
    meat_on_bone: meat_on_bone,
    poultry_leg: poultry_leg,
    rice_cracker: rice_cracker,
    rice_ball: rice_ball,
    rice: rice,
    curry: curry,
    ramen: ramen,
    spaghetti: spaghetti,
    bread: bread,
    fries: fries,
    sweet_potato: sweet_potato,
    dango: dango,
    oden: oden,
    sushi: sushi,
    fried_shrimp: fried_shrimp,
    fish_cake: fish_cake,
    icecream: icecream,
    shaved_ice: shaved_ice,
    ice_cream: ice_cream,
    doughnut: doughnut,
    cookie: cookie,
    chocolate_bar: chocolate_bar,
    candy: candy,
    lollipop: lollipop,
    custard: custard,
    honey_pot: honey_pot,
    cake: cake,
    bento: bento,
    stew: stew,
    fried_egg: fried_egg,
    cooking: cooking,
    fork_and_knife: fork_and_knife,
    tea: tea,
    sake: sake,
    wine_glass: wine_glass,
    cocktail: cocktail,
    tropical_drink: tropical_drink,
    beer: beer,
    beers: beers,
    baby_bottle: baby_bottle,
    knife_fork_plate: knife_fork_plate,
    champagne: champagne,
    popcorn: popcorn,
    ribbon: ribbon,
    gift: gift,
    birthday: birthday,
    jack_o_lantern: jack_o_lantern,
    christmas_tree: christmas_tree,
    santa: santa,
    fireworks: fireworks,
    sparkler: sparkler,
    balloon: balloon,
    tada: tada,
    confetti_ball: confetti_ball,
    tanabata_tree: tanabata_tree,
    crossed_flags: crossed_flags,
    bamboo: bamboo,
    dolls: dolls,
    flags: flags,
    wind_chime: wind_chime,
    rice_scene: rice_scene,
    school_satchel: school_satchel,
    mortar_board: mortar_board,
    medal: medal,
    reminder_ribbon: reminder_ribbon,
    studio_microphone: studio_microphone,
    level_slider: level_slider,
    control_knobs: control_knobs,
    film_frames: film_frames,
    admission_tickets: admission_tickets,
    carousel_horse: carousel_horse,
    ferris_wheel: ferris_wheel,
    roller_coaster: roller_coaster,
    fishing_pole_and_fish: fishing_pole_and_fish,
    microphone: microphone,
    movie_camera: movie_camera,
    cinema: cinema,
    headphones: headphones,
    art: art,
    tophat: tophat,
    circus_tent: circus_tent,
    ticket: ticket,
    clapper: clapper,
    performing_arts: performing_arts,
    video_game: video_game,
    dart: dart,
    slot_machine: slot_machine,
    game_die: game_die,
    bowling: bowling,
    flower_playing_cards: flower_playing_cards,
    musical_note: musical_note,
    notes: notes,
    saxophone: saxophone,
    guitar: guitar,
    musical_keyboard: musical_keyboard,
    trumpet: trumpet,
    violin: violin,
    musical_score: musical_score,
    running_shirt_with_sash: running_shirt_with_sash,
    tennis: tennis,
    ski: ski,
    basketball: basketball,
    checkered_flag: checkered_flag,
    snowboarder: snowboarder,
    runner: runner,
    running: running,
    surfer: surfer,
    sports_medal: sports_medal,
    trophy: trophy,
    horse_racing: horse_racing,
    football: football,
    rugby_football: rugby_football,
    swimmer: swimmer,
    weight_lifter: weight_lifter,
    golfer: golfer,
    racing_motorcycle: racing_motorcycle,
    racing_car: racing_car,
    cricket_bat_and_ball: cricket_bat_and_ball,
    volleyball: volleyball,
    field_hockey_stick_and_ball: field_hockey_stick_and_ball,
    ice_hockey_stick_and_puck: ice_hockey_stick_and_puck,
    table_tennis_paddle_and_ball: table_tennis_paddle_and_ball,
    snow_capped_mountain: snow_capped_mountain,
    camping: camping,
    beach_with_umbrella: beach_with_umbrella,
    building_construction: building_construction,
    house_buildings: house_buildings,
    cityscape: cityscape,
    derelict_house_building: derelict_house_building,
    classical_building: classical_building,
    desert: desert,
    desert_island: desert_island,
    national_park: national_park,
    stadium: stadium,
    house: house,
    house_with_garden: house_with_garden,
    office: office,
    post_office: post_office,
    european_post_office: european_post_office,
    hospital: hospital,
    bank: bank,
    atm: atm,
    hotel: hotel,
    love_hotel: love_hotel,
    convenience_store: convenience_store,
    school: school,
    department_store: department_store,
    factory: factory,
    izakaya_lantern: izakaya_lantern,
    lantern: lantern,
    japanese_castle: japanese_castle,
    european_castle: european_castle,
    waving_white_flag: waving_white_flag,
    waving_black_flag: waving_black_flag,
    rosette: rosette,
    label: label,
    badminton_racquet_and_shuttlecock: badminton_racquet_and_shuttlecock,
    bow_and_arrow: bow_and_arrow,
    amphora: amphora,
    rat: rat,
    mouse2: mouse2,
    ox: ox,
    water_buffalo: water_buffalo,
    cow2: cow2,
    tiger2: tiger2,
    leopard: leopard,
    rabbit2: rabbit2,
    cat2: cat2,
    dragon: dragon,
    crocodile: crocodile,
    whale2: whale2,
    snail: snail,
    snake: snake,
    racehorse: racehorse,
    ram: ram,
    goat: goat,
    sheep: sheep,
    monkey: monkey,
    rooster: rooster,
    chicken: chicken,
    dog2: dog2,
    pig2: pig2,
    boar: boar,
    elephant: elephant,
    octopus: octopus,
    shell: shell,
    bug: bug,
    ant: ant,
    bee: bee,
    honeybee: honeybee,
    beetle: beetle,
    fish: fish,
    tropical_fish: tropical_fish,
    blowfish: blowfish,
    turtle: turtle,
    hatching_chick: hatching_chick,
    baby_chick: baby_chick,
    hatched_chick: hatched_chick,
    bird: bird,
    penguin: penguin,
    koala: koala,
    poodle: poodle,
    dromedary_camel: dromedary_camel,
    camel: camel,
    dolphin: dolphin,
    flipper: flipper,
    mouse: mouse,
    cow: cow,
    tiger: tiger,
    rabbit: rabbit,
    cat: cat,
    dragon_face: dragon_face,
    whale: whale,
    horse: horse,
    monkey_face: monkey_face,
    dog: dog,
    pig: pig,
    frog: frog,
    hamster: hamster,
    wolf: wolf,
    bear: bear,
    panda_face: panda_face,
    pig_nose: pig_nose,
    feet: feet,
    paw_prints: paw_prints,
    chipmunk: chipmunk,
    eyes: eyes,
    eye: eye,
    ear: ear,
    nose: nose,
    lips: lips,
    tongue: tongue,
    point_up_2: point_up_2,
    point_down: point_down,
    point_left: point_left,
    point_right: point_right,
    facepunch: facepunch,
    punch: punch,
    wave: wave,
    ok_hand: ok_hand,
    thumbsup: thumbsup,
    thumbsdown: thumbsdown,
    clap: clap,
    open_hands: open_hands,
    crown: crown,
    womans_hat: womans_hat,
    eyeglasses: eyeglasses,
    necktie: necktie,
    shirt: shirt,
    tshirt: tshirt,
    jeans: jeans,
    dress: dress,
    kimono: kimono,
    bikini: bikini,
    womans_clothes: womans_clothes,
    purse: purse,
    handbag: handbag,
    pouch: pouch,
    mans_shoe: mans_shoe,
    shoe: shoe,
    athletic_shoe: athletic_shoe,
    high_heel: high_heel,
    sandal: sandal,
    boot: boot,
    footprints: footprints,
    bust_in_silhouette: bust_in_silhouette,
    busts_in_silhouette: busts_in_silhouette,
    boy: boy,
    girl: girl,
    family: family,
    man: man,
    couple_with_heart: couple_with_heart,
    couplekiss: couplekiss,
    woman: woman,
    couple: couple,
    man_and_woman_holding_hands: man_and_woman_holding_hands,
    two_men_holding_hands: two_men_holding_hands,
    two_women_holding_hands: two_women_holding_hands,
    cop: cop,
    dancers: dancers,
    bride_with_veil: bride_with_veil,
    person_with_blond_hair: person_with_blond_hair,
    man_with_gua_pi_mao: man_with_gua_pi_mao,
    man_with_turban: man_with_turban,
    older_man: older_man,
    older_woman: older_woman,
    baby: baby,
    construction_worker: construction_worker,
    princess: princess,
    japanese_ogre: japanese_ogre,
    japanese_goblin: japanese_goblin,
    ghost: ghost,
    angel: angel,
    alien: alien,
    space_invader: space_invader,
    imp: imp,
    skull: skull,
    information_desk_person: information_desk_person,
    guardsman: guardsman,
    dancer: dancer,
    lipstick: lipstick,
    nail_care: nail_care,
    massage: massage,
    haircut: haircut,
    barber: barber,
    syringe: syringe,
    pill: pill,
    kiss: kiss,
    love_letter: love_letter,
    ring: ring,
    gem: gem,
    bouquet: bouquet,
    wedding: wedding,
    heartbeat: heartbeat,
    broken_heart: broken_heart,
    two_hearts: two_hearts,
    sparkling_heart: sparkling_heart,
    heartpulse: heartpulse,
    cupid: cupid,
    blue_heart: blue_heart,
    green_heart: green_heart,
    yellow_heart: yellow_heart,
    purple_heart: purple_heart,
    gift_heart: gift_heart,
    revolving_hearts: revolving_hearts,
    heart_decoration: heart_decoration,
    diamond_shape_with_a_dot_inside: diamond_shape_with_a_dot_inside,
    bulb: bulb,
    anger: anger,
    bomb: bomb,
    zzz: zzz,
    boom: boom,
    collision: collision,
    sweat_drops: sweat_drops,
    droplet: droplet,
    dash: dash,
    hankey: hankey,
    poop: poop,
    shit: shit,
    muscle: muscle,
    dizzy: dizzy,
    speech_balloon: speech_balloon,
    thought_balloon: thought_balloon,
    white_flower: white_flower,
    moneybag: moneybag,
    currency_exchange: currency_exchange,
    heavy_dollar_sign: heavy_dollar_sign,
    credit_card: credit_card,
    yen: yen,
    dollar: dollar,
    euro: euro,
    pound: pound,
    money_with_wings: money_with_wings,
    chart: chart,
    seat: seat,
    computer: computer,
    briefcase: briefcase,
    minidisc: minidisc,
    floppy_disk: floppy_disk,
    cd: cd,
    dvd: dvd,
    file_folder: file_folder,
    open_file_folder: open_file_folder,
    page_with_curl: page_with_curl,
    page_facing_up: page_facing_up,
    date: date,
    calendar: calendar,
    card_index: card_index,
    chart_with_upwards_trend: chart_with_upwards_trend,
    chart_with_downwards_trend: chart_with_downwards_trend,
    bar_chart: bar_chart,
    clipboard: clipboard,
    pushpin: pushpin,
    round_pushpin: round_pushpin,
    paperclip: paperclip,
    straight_ruler: straight_ruler,
    triangular_ruler: triangular_ruler,
    bookmark_tabs: bookmark_tabs,
    ledger: ledger,
    notebook: notebook,
    notebook_with_decorative_cover: notebook_with_decorative_cover,
    closed_book: closed_book,
    book: book,
    open_book: open_book,
    green_book: green_book,
    blue_book: blue_book,
    orange_book: orange_book,
    books: books,
    name_badge: name_badge,
    scroll: scroll,
    memo: memo,
    pencil: pencil,
    telephone_receiver: telephone_receiver,
    pager: pager,
    fax: fax,
    satellite_antenna: satellite_antenna,
    loudspeaker: loudspeaker,
    mega: mega,
    outbox_tray: outbox_tray,
    inbox_tray: inbox_tray,
    incoming_envelope: incoming_envelope,
    envelope_with_arrow: envelope_with_arrow,
    mailbox_closed: mailbox_closed,
    mailbox: mailbox,
    mailbox_with_mail: mailbox_with_mail,
    mailbox_with_no_mail: mailbox_with_no_mail,
    postbox: postbox,
    postal_horn: postal_horn,
    newspaper: newspaper,
    iphone: iphone,
    calling: calling,
    vibration_mode: vibration_mode,
    mobile_phone_off: mobile_phone_off,
    no_mobile_phones: no_mobile_phones,
    signal_strength: signal_strength,
    camera: camera,
    camera_with_flash: camera_with_flash,
    video_camera: video_camera,
    tv: tv,
    radio: radio,
    vhs: vhs,
    film_projector: film_projector,
    prayer_beads: prayer_beads,
    twisted_rightwards_arrows: twisted_rightwards_arrows,
    repeat: repeat,
    repeat_one: repeat_one,
    arrows_clockwise: arrows_clockwise,
    arrows_counterclockwise: arrows_counterclockwise,
    low_brightness: low_brightness,
    high_brightness: high_brightness,
    mute: mute,
    speaker: speaker,
    sound: sound,
    loud_sound: loud_sound,
    battery: battery,
    electric_plug: electric_plug,
    mag: mag,
    mag_right: mag_right,
    lock_with_ink_pen: lock_with_ink_pen,
    closed_lock_with_key: closed_lock_with_key,
    key: key,
    lock: lock,
    unlock: unlock,
    bell: bell,
    no_bell: no_bell,
    bookmark: bookmark,
    link: link,
    radio_button: radio_button,
    back: back,
    end: end,
    on: on,
    soon: soon,
    top: top,
    underage: underage,
    keycap_ten: keycap_ten,
    capital_abcd: capital_abcd,
    abcd: abcd,
    symbols: symbols,
    abc: abc,
    fire: fire,
    flashlight: flashlight,
    wrench: wrench,
    hammer: hammer,
    nut_and_bolt: nut_and_bolt,
    hocho: hocho,
    knife: knife,
    gun: gun,
    microscope: microscope,
    telescope: telescope,
    crystal_ball: crystal_ball,
    six_pointed_star: six_pointed_star,
    beginner: beginner,
    trident: trident,
    black_square_button: black_square_button,
    white_square_button: white_square_button,
    red_circle: red_circle,
    large_blue_circle: large_blue_circle,
    large_orange_diamond: large_orange_diamond,
    large_blue_diamond: large_blue_diamond,
    small_orange_diamond: small_orange_diamond,
    small_blue_diamond: small_blue_diamond,
    small_red_triangle: small_red_triangle,
    small_red_triangle_down: small_red_triangle_down,
    arrow_up_small: arrow_up_small,
    arrow_down_small: arrow_down_small,
    om_symbol: om_symbol,
    dove_of_peace: dove_of_peace,
    kaaba: kaaba,
    mosque: mosque,
    synagogue: synagogue,
    menorah_with_nine_branches: menorah_with_nine_branches,
    clock1: clock1,
    clock2: clock2,
    clock3: clock3,
    clock4: clock4,
    clock5: clock5,
    clock6: clock6,
    clock7: clock7,
    clock8: clock8,
    clock9: clock9,
    clock10: clock10,
    clock11: clock11,
    clock12: clock12,
    clock130: clock130,
    clock230: clock230,
    clock330: clock330,
    clock430: clock430,
    clock530: clock530,
    clock630: clock630,
    clock730: clock730,
    clock830: clock830,
    clock930: clock930,
    clock1030: clock1030,
    clock1130: clock1130,
    clock1230: clock1230,
    candle: candle,
    mantelpiece_clock: mantelpiece_clock,
    hole: hole,
    man_in_business_suit_levitating: man_in_business_suit_levitating,
    sleuth_or_spy: sleuth_or_spy,
    dark_sunglasses: dark_sunglasses,
    spider: spider,
    spider_web: spider_web,
    joystick: joystick,
    man_dancing: man_dancing,
    linked_paperclips: linked_paperclips,
    lower_left_ballpoint_pen: lower_left_ballpoint_pen,
    lower_left_fountain_pen: lower_left_fountain_pen,
    lower_left_paintbrush: lower_left_paintbrush,
    lower_left_crayon: lower_left_crayon,
    raised_hand_with_fingers_splayed: raised_hand_with_fingers_splayed,
    middle_finger: middle_finger,
    reversed_hand_with_middle_finger_extended: reversed_hand_with_middle_finger_extended,
    black_heart: black_heart,
    desktop_computer: desktop_computer,
    printer: printer,
    three_button_mouse: three_button_mouse,
    trackball: trackball,
    frame_with_picture: frame_with_picture,
    card_index_dividers: card_index_dividers,
    card_file_box: card_file_box,
    file_cabinet: file_cabinet,
    wastebasket: wastebasket,
    spiral_note_pad: spiral_note_pad,
    spiral_calendar_pad: spiral_calendar_pad,
    compression: compression,
    old_key: old_key,
    rolled_up_newspaper: rolled_up_newspaper,
    dagger_knife: dagger_knife,
    speaking_head_in_silhouette: speaking_head_in_silhouette,
    left_speech_bubble: left_speech_bubble,
    right_anger_bubble: right_anger_bubble,
    ballot_box_with_ballot: ballot_box_with_ballot,
    world_map: world_map,
    mount_fuji: mount_fuji,
    tokyo_tower: tokyo_tower,
    statue_of_liberty: statue_of_liberty,
    japan: japan,
    moyai: moyai,
    grinning: grinning,
    grin: grin,
    joy: joy,
    smiley: smiley,
    smile: smile,
    sweat_smile: sweat_smile,
    laughing: laughing,
    satisfied: satisfied,
    innocent: innocent,
    smiling_imp: smiling_imp,
    wink: wink,
    blush: blush,
    yum: yum,
    relieved: relieved,
    heart_eyes: heart_eyes,
    sunglasses: sunglasses,
    smirk: smirk,
    neutral_face: neutral_face,
    expressionless: expressionless,
    unamused: unamused,
    sweat: sweat,
    pensive: pensive,
    confused: confused,
    confounded: confounded,
    kissing: kissing,
    kissing_heart: kissing_heart,
    kissing_smiling_eyes: kissing_smiling_eyes,
    kissing_closed_eyes: kissing_closed_eyes,
    stuck_out_tongue: stuck_out_tongue,
    stuck_out_tongue_winking_eye: stuck_out_tongue_winking_eye,
    stuck_out_tongue_closed_eyes: stuck_out_tongue_closed_eyes,
    disappointed: disappointed,
    worried: worried,
    angry: angry,
    rage: rage,
    cry: cry,
    persevere: persevere,
    triumph: triumph,
    disappointed_relieved: disappointed_relieved,
    frowning: frowning,
    anguished: anguished,
    fearful: fearful,
    weary: weary,
    sleepy: sleepy,
    tired_face: tired_face,
    grimacing: grimacing,
    sob: sob,
    open_mouth: open_mouth,
    hushed: hushed,
    cold_sweat: cold_sweat,
    scream: scream,
    astonished: astonished,
    flushed: flushed,
    sleeping: sleeping,
    dizzy_face: dizzy_face,
    no_mouth: no_mouth,
    mask: mask,
    smile_cat: smile_cat,
    joy_cat: joy_cat,
    smiley_cat: smiley_cat,
    heart_eyes_cat: heart_eyes_cat,
    smirk_cat: smirk_cat,
    kissing_cat: kissing_cat,
    pouting_cat: pouting_cat,
    crying_cat_face: crying_cat_face,
    scream_cat: scream_cat,
    slightly_frowning_face: slightly_frowning_face,
    slightly_smiling_face: slightly_smiling_face,
    upside_down_face: upside_down_face,
    face_with_rolling_eyes: face_with_rolling_eyes,
    no_good: no_good,
    ok_woman: ok_woman,
    bow: bow,
    see_no_evil: see_no_evil,
    hear_no_evil: hear_no_evil,
    speak_no_evil: speak_no_evil,
    raising_hand: raising_hand,
    raised_hands: raised_hands,
    person_frowning: person_frowning,
    person_with_pouting_face: person_with_pouting_face,
    pray: pray,
    rocket: rocket,
    helicopter: helicopter,
    steam_locomotive: steam_locomotive,
    railway_car: railway_car,
    bullettrain_side: bullettrain_side,
    bullettrain_front: bullettrain_front,
    train2: train2,
    metro: metro,
    light_rail: light_rail,
    station: station,
    tram: tram,
    train: train,
    bus: bus,
    oncoming_bus: oncoming_bus,
    trolleybus: trolleybus,
    busstop: busstop,
    minibus: minibus,
    ambulance: ambulance,
    fire_engine: fire_engine,
    police_car: police_car,
    oncoming_police_car: oncoming_police_car,
    taxi: taxi,
    oncoming_taxi: oncoming_taxi,
    car: car,
    red_car: red_car,
    oncoming_automobile: oncoming_automobile,
    blue_car: blue_car,
    truck: truck,
    articulated_lorry: articulated_lorry,
    tractor: tractor,
    monorail: monorail,
    mountain_railway: mountain_railway,
    suspension_railway: suspension_railway,
    mountain_cableway: mountain_cableway,
    aerial_tramway: aerial_tramway,
    ship: ship,
    rowboat: rowboat,
    speedboat: speedboat,
    traffic_light: traffic_light,
    vertical_traffic_light: vertical_traffic_light,
    construction: construction,
    rotating_light: rotating_light,
    triangular_flag_on_post: triangular_flag_on_post,
    door: door,
    no_entry_sign: no_entry_sign,
    smoking: smoking,
    no_smoking: no_smoking,
    put_litter_in_its_place: put_litter_in_its_place,
    do_not_litter: do_not_litter,
    potable_water: potable_water,
    bike: bike,
    no_bicycles: no_bicycles,
    bicyclist: bicyclist,
    mountain_bicyclist: mountain_bicyclist,
    walking: walking,
    no_pedestrians: no_pedestrians,
    children_crossing: children_crossing,
    mens: mens,
    womens: womens,
    restroom: restroom,
    baby_symbol: baby_symbol,
    toilet: toilet,
    wc: wc,
    shower: shower,
    bath: bath,
    bathtub: bathtub,
    passport_control: passport_control,
    customs: customs,
    baggage_claim: baggage_claim,
    left_luggage: left_luggage,
    couch_and_lamp: couch_and_lamp,
    sleeping_accommodation: sleeping_accommodation,
    shopping_bags: shopping_bags,
    bellhop_bell: bellhop_bell,
    bed: bed,
    place_of_worship: place_of_worship,
    octagonal_sign: octagonal_sign,
    shopping_trolley: shopping_trolley,
    hammer_and_wrench: hammer_and_wrench,
    shield: shield,
    oil_drum: oil_drum,
    motorway: motorway,
    railway_track: railway_track,
    motor_boat: motor_boat,
    small_airplane: small_airplane,
    airplane_departure: airplane_departure,
    airplane_arriving: airplane_arriving,
    satellite: satellite,
    passenger_ship: passenger_ship,
    scooter: scooter,
    motor_scooter: motor_scooter,
    canoe: canoe,
    sled: sled,
    flying_saucer: flying_saucer,
    zipper_mouth_face: zipper_mouth_face,
    money_mouth_face: money_mouth_face,
    face_with_thermometer: face_with_thermometer,
    nerd_face: nerd_face,
    thinking_face: thinking_face,
    face_with_head_bandage: face_with_head_bandage,
    robot_face: robot_face,
    hugging_face: hugging_face,
    the_horns: the_horns,
    sign_of_the_horns: sign_of_the_horns,
    call_me_hand: call_me_hand,
    raised_back_of_hand: raised_back_of_hand,
    handshake: handshake,
    crossed_fingers: crossed_fingers,
    hand_with_index_and_middle_fingers_crossed: hand_with_index_and_middle_fingers_crossed,
    i_love_you_hand_sign: i_love_you_hand_sign,
    face_with_cowboy_hat: face_with_cowboy_hat,
    clown_face: clown_face,
    nauseated_face: nauseated_face,
    rolling_on_the_floor_laughing: rolling_on_the_floor_laughing,
    drooling_face: drooling_face,
    lying_face: lying_face,
    face_palm: face_palm,
    sneezing_face: sneezing_face,
    face_with_raised_eyebrow: face_with_raised_eyebrow,
    face_with_one_eyebrow_raised: face_with_one_eyebrow_raised,
    grinning_face_with_star_eyes: grinning_face_with_star_eyes,
    zany_face: zany_face,
    grinning_face_with_one_large_and_one_small_eye: grinning_face_with_one_large_and_one_small_eye,
    shushing_face: shushing_face,
    face_with_finger_covering_closed_lips: face_with_finger_covering_closed_lips,
    face_with_symbols_on_mouth: face_with_symbols_on_mouth,
    serious_face_with_symbols_covering_mouth: serious_face_with_symbols_covering_mouth,
    face_with_hand_over_mouth: face_with_hand_over_mouth,
    smiling_face_with_smiling_eyes_and_hand_covering_mouth: smiling_face_with_smiling_eyes_and_hand_covering_mouth,
    face_vomiting: face_vomiting,
    face_with_open_mouth_vomiting: face_with_open_mouth_vomiting,
    exploding_head: exploding_head,
    shocked_face_with_exploding_head: shocked_face_with_exploding_head,
    pregnant_woman: pregnant_woman,
    palms_up_together: palms_up_together,
    selfie: selfie,
    prince: prince,
    man_in_tuxedo: man_in_tuxedo,
    mrs_claus: mrs_claus,
    mother_christmas: mother_christmas,
    shrug: shrug,
    person_doing_cartwheel: person_doing_cartwheel,
    juggling: juggling,
    fencer: fencer,
    wrestlers: wrestlers,
    water_polo: water_polo,
    handball: handball,
    wilted_flower: wilted_flower,
    drum_with_drumsticks: drum_with_drumsticks,
    clinking_glasses: clinking_glasses,
    tumbler_glass: tumbler_glass,
    spoon: spoon,
    goal_net: goal_net,
    first_place_medal: first_place_medal,
    second_place_medal: second_place_medal,
    third_place_medal: third_place_medal,
    boxing_glove: boxing_glove,
    martial_arts_uniform: martial_arts_uniform,
    curling_stone: curling_stone,
    croissant: croissant,
    avocado: avocado,
    cucumber: cucumber,
    bacon: bacon,
    potato: potato,
    carrot: carrot,
    baguette_bread: baguette_bread,
    green_salad: green_salad,
    shallow_pan_of_food: shallow_pan_of_food,
    stuffed_flatbread: stuffed_flatbread,
    egg: egg,
    glass_of_milk: glass_of_milk,
    peanuts: peanuts,
    kiwifruit: kiwifruit,
    pancakes: pancakes,
    dumpling: dumpling,
    fortune_cookie: fortune_cookie,
    takeout_box: takeout_box,
    chopsticks: chopsticks,
    bowl_with_spoon: bowl_with_spoon,
    cup_with_straw: cup_with_straw,
    coconut: coconut,
    broccoli: broccoli,
    pie: pie,
    pretzel: pretzel,
    cut_of_meat: cut_of_meat,
    sandwich: sandwich,
    canned_food: canned_food,
    crab: crab,
    lion_face: lion_face,
    scorpion: scorpion,
    turkey: turkey,
    unicorn_face: unicorn_face,
    eagle: eagle,
    duck: duck,
    bat: bat,
    shark: shark,
    owl: owl,
    fox_face: fox_face,
    butterfly: butterfly,
    deer: deer,
    gorilla: gorilla,
    lizard: lizard,
    rhinoceros: rhinoceros,
    shrimp: shrimp,
    squid: squid,
    giraffe_face: giraffe_face,
    zebra_face: zebra_face,
    hedgehog: hedgehog,
    sauropod: sauropod,
    cricket: cricket,
    cheese_wedge: cheese_wedge,
    face_with_monocle: face_with_monocle,
    adult: adult,
    child: child,
    older_adult: older_adult,
    bearded_person: bearded_person,
    person_with_headscarf: person_with_headscarf,
    woman_in_steamy_room: woman_in_steamy_room,
    man_in_steamy_room: man_in_steamy_room,
    person_in_steamy_room: person_in_steamy_room,
    woman_climbing: woman_climbing,
    person_climbing: person_climbing,
    man_climbing: man_climbing,
    woman_in_lotus_position: woman_in_lotus_position,
    person_in_lotus_position: person_in_lotus_position,
    man_in_lotus_position: man_in_lotus_position,
    female_mage: female_mage,
    mage: mage,
    male_mage: male_mage,
    female_fairy: female_fairy,
    fairy: fairy,
    male_fairy: male_fairy,
    female_vampire: female_vampire,
    vampire: vampire,
    male_vampire: male_vampire,
    mermaid: mermaid,
    merman: merman,
    merperson: merperson,
    female_elf: female_elf,
    male_elf: male_elf,
    elf: elf,
    female_genie: female_genie,
    male_genie: male_genie,
    genie: genie,
    female_zombie: female_zombie,
    male_zombie: male_zombie,
    zombie: zombie,
    brain: brain,
    orange_heart: orange_heart,
    billed_cap: billed_cap,
    scarf: scarf,
    gloves: gloves,
    coat: coat,
    socks: socks,
    bangbang: bangbang,
    interrobang: interrobang,
    tm: tm,
    information_source: information_source,
    left_right_arrow: left_right_arrow,
    arrow_up_down: arrow_up_down,
    arrow_upper_left: arrow_upper_left,
    arrow_upper_right: arrow_upper_right,
    arrow_lower_right: arrow_lower_right,
    arrow_lower_left: arrow_lower_left,
    leftwards_arrow_with_hook: leftwards_arrow_with_hook,
    arrow_right_hook: arrow_right_hook,
    watch: watch,
    hourglass: hourglass,
    keyboard: keyboard,
    eject: eject,
    fast_forward: fast_forward,
    rewind: rewind,
    arrow_double_up: arrow_double_up,
    arrow_double_down: arrow_double_down,
    black_right_pointing_double_triangle_with_vertical_bar: black_right_pointing_double_triangle_with_vertical_bar,
    black_left_pointing_double_triangle_with_vertical_bar: black_left_pointing_double_triangle_with_vertical_bar,
    black_right_pointing_triangle_with_double_vertical_bar: black_right_pointing_triangle_with_double_vertical_bar,
    alarm_clock: alarm_clock,
    stopwatch: stopwatch,
    timer_clock: timer_clock,
    hourglass_flowing_sand: hourglass_flowing_sand,
    double_vertical_bar: double_vertical_bar,
    black_square_for_stop: black_square_for_stop,
    black_circle_for_record: black_circle_for_record,
    m: m,
    black_small_square: black_small_square,
    white_small_square: white_small_square,
    arrow_forward: arrow_forward,
    arrow_backward: arrow_backward,
    white_medium_square: white_medium_square,
    black_medium_square: black_medium_square,
    white_medium_small_square: white_medium_small_square,
    black_medium_small_square: black_medium_small_square,
    sunny: sunny,
    cloud: cloud,
    umbrella: umbrella,
    snowman: snowman,
    comet: comet,
    phone: phone,
    telephone: telephone,
    ballot_box_with_check: ballot_box_with_check,
    shamrock: shamrock,
    point_up: point_up,
    skull_and_crossbones: skull_and_crossbones,
    radioactive_sign: radioactive_sign,
    biohazard_sign: biohazard_sign,
    orthodox_cross: orthodox_cross,
    star_and_crescent: star_and_crescent,
    peace_symbol: peace_symbol,
    yin_yang: yin_yang,
    wheel_of_dharma: wheel_of_dharma,
    white_frowning_face: white_frowning_face,
    relaxed: relaxed,
    female_sign: female_sign,
    male_sign: male_sign,
    gemini: gemini,
    cancer: cancer,
    leo: leo,
    virgo: virgo,
    libra: libra,
    scorpius: scorpius,
    spades: spades,
    clubs: clubs,
    hearts: hearts,
    diamonds: diamonds,
    hotsprings: hotsprings,
    recycle: recycle,
    wheelchair: wheelchair,
    hammer_and_pick: hammer_and_pick,
    crossed_swords: crossed_swords,
    medical_symbol: medical_symbol,
    staff_of_aesculapius: staff_of_aesculapius,
    scales: scales,
    alembic: alembic,
    gear: gear,
    atom_symbol: atom_symbol,
    fleur_de_lis: fleur_de_lis,
    warning: warning,
    zap: zap,
    white_circle: white_circle,
    black_circle: black_circle,
    coffin: coffin,
    funeral_urn: funeral_urn,
    soccer: soccer,
    baseball: baseball,
    snowman_without_snow: snowman_without_snow,
    partly_sunny: partly_sunny,
    thunder_cloud_and_rain: thunder_cloud_and_rain,
    ophiuchus: ophiuchus,
    pick: pick,
    helmet_with_white_cross: helmet_with_white_cross,
    chains: chains,
    no_entry: no_entry,
    shinto_shrine: shinto_shrine,
    church: church,
    mountain: mountain,
    umbrella_on_ground: umbrella_on_ground,
    fountain: fountain,
    golf: golf,
    ferry: ferry,
    boat: boat,
    sailboat: sailboat,
    skier: skier,
    ice_skate: ice_skate,
    person_with_ball: person_with_ball,
    tent: tent,
    fuelpump: fuelpump,
    scissors: scissors,
    airplane: airplane,
    email: email,
    envelope: envelope,
    fist: fist,
    hand: hand,
    raised_hand: raised_hand,
    v: v,
    writing_hand: writing_hand,
    pencil2: pencil2,
    black_nib: black_nib,
    heavy_check_mark: heavy_check_mark,
    heavy_multiplication_x: heavy_multiplication_x,
    latin_cross: latin_cross,
    star_of_david: star_of_david,
    eight_spoked_asterisk: eight_spoked_asterisk,
    eight_pointed_black_star: eight_pointed_black_star,
    snowflake: snowflake,
    sparkle: sparkle,
    x: x,
    negative_squared_cross_mark: negative_squared_cross_mark,
    heavy_heart_exclamation_mark_ornament: heavy_heart_exclamation_mark_ornament,
    heart: heart,
    arrow_right: arrow_right,
    curly_loop: curly_loop,
    loop: loop,
    arrow_heading_up: arrow_heading_up,
    arrow_heading_down: arrow_heading_down,
    arrow_left: arrow_left,
    arrow_up: arrow_up,
    arrow_down: arrow_down,
    black_large_square: black_large_square,
    white_large_square: white_large_square,
    star: star,
    o: o,
    wavy_dash: wavy_dash,
    part_alternation_mark: part_alternation_mark,
    congratulations: congratulations,
    secret: secret,
    'default': emoji
});

var emojiByName = getCjsExportFromNamespace(emoji$1);

/**
 * regex to parse emoji in a string - finds emoji, e.g. :coffee:
 */
var emojiNameRegex = /:([a-zA-Z0-9_\-\+]+):/g;

/**
 * regex to trim whitespace
 * use instead of String.prototype.trim() for IE8 support
 */
var trimSpaceRegex = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;

/**
 * Removes colons on either side
 * of the string if present
 * @param  {string} str
 * @return {string}
 */
function stripColons(str) {
  var colonIndex = str.indexOf(':');
  if (colonIndex > -1) {
    // :emoji: (http://www.emoji-cheat-sheet.com/)
    if (colonIndex === str.length - 1) {
      str = str.substring(0, colonIndex);
      return stripColons(str);
    } else {
      str = str.substr(colonIndex + 1);
      return stripColons(str);
    }
  }

  return str;
}

/**
 * Adds colons to either side
 * of the string
 * @param {string} str
 * @return {string}
 */
function wrapColons(str) {
  return (typeof str === 'string' && str.length > 0) ? ':' + str + ':' : str;
}

/**
 * Ensure that the word is wrapped in colons
 * by only adding them, if they are not there.
 * @param {string} str
 * @return {string}
 */
function ensureColons(str) {
  return (typeof str === 'string' && str[0] !== ':') ? wrapColons(str) : str;
}

// Remove the non-spacing-mark from the code, never send a stripped version
// to the client, as it kills graphical emoticons.
function stripNSB(code) {
  return code;
}
// Reversed hash table, where as emojiByName contains a { heart: '❤' }
// dictionary emojiByCode contains { ❤: 'heart' }. The codes are normalized
// to the text version.
var emojiByCode = Object.keys(emojiByName).reduce(function (h, k) {
  h[stripNSB(emojiByName[k])] = k;
  return h;
}, {});

/**
 * Emoji namespace
 */
var Emoji = {
  emoji: emojiByName,
};

/**
 * get emoji code from name
 * @param  {string} emoji
 * @return {string}
 */
Emoji._get = function _get(emoji) {
  if (emojiByName.hasOwnProperty(emoji)) {
    return emojiByName[emoji];
  }

  return ensureColons(emoji);
};

/**
 * get emoji code from :emoji: string or name
 * @param  {string} emoji
 * @return {string}
 */
Emoji.get = function get(emoji) {
  emoji = stripColons(emoji);

  return Emoji._get(emoji);
};

/**
 * find the emoji by either code or name
 * @param {string} nameOrCode The emoji to find, either `coffee`, `:coffee:` or `☕`;
 * @return {object}
 */
Emoji.find = function find(nameOrCode) {
  return Emoji.findByName(nameOrCode) || Emoji.findByCode(nameOrCode);
};

/**
 * find the emoji by name
 * @param {string} name The emoji to find either `coffee` or `:coffee:`;
 * @return {object}
 */
Emoji.findByName = function findByName(name) {
  var stripped = stripColons(name);
  var emoji = emojiByName[stripped];

  return emoji ? ({ emoji: emoji, key: stripped }) : undefined;
};

/**
 * find the emoji by code (emoji)
 * @param {string} code The emoji to find; for example `☕` or `☔`
 * @return {object}
 */
Emoji.findByCode = function findByCode(code) {
  var stripped = stripNSB(code);
  var name = emojiByCode[stripped];

  // lookup emoji to ensure the Variant Form is returned
  return name ? ({ emoji: emojiByName[name], key: name }) : undefined;
};


/**
 * Check if an emoji is known by this library
 * @param {string} nameOrCode The emoji to validate, either `coffee`, `:coffee:` or `☕`;
 * @return {object}
 */
Emoji.hasEmoji = function hasEmoji(nameOrCode) {
  return Emoji.hasEmojiByName(nameOrCode) || Emoji.hasEmojiByCode(nameOrCode);
};

/**
 * Check if an emoji with given name is known by this library
 * @param {string} name The emoji to validate either `coffee` or `:coffee:`;
 * @return {object}
 */
Emoji.hasEmojiByName = function hasEmojiByName(name) {
  var result = Emoji.findByName(name);
  return !!result && result.key === stripColons(name);
};

/**
 * Check if a given emoji is known by this library
 * @param {string} code The emoji to validate; for example `☕` or `☔`
 * @return {object}
 */
Emoji.hasEmojiByCode = function hasEmojiByCode(code) {
  var result = Emoji.findByCode(code);
  return !!result && stripNSB(result.emoji) === stripNSB(code);
};

/**
 * get emoji name from code
 * @param  {string} emoji
 * @param  {boolean} includeColons should the result include the ::
 * @return {string}
 */
Emoji.which = function which(emoji_code, includeColons) {
  var code = stripNSB(emoji_code);
  var word = emojiByCode[code];

  return includeColons ? wrapColons(word) : word;
};

/**
 * emojify a string (replace :emoji: with an emoji)
 * @param  {string} str
 * @param  {function} on_missing (gets emoji name without :: and returns a proper emoji if no emoji was found)
 * @param  {function} format (wrap the returned emoji in a custom element)
 * @return {string}
 */
Emoji.emojify = function emojify(str, on_missing, format) {
  if (!str) return '';

  return str.split(emojiNameRegex) // parse emoji via regex
    .map(function parseEmoji(s, i) {
      // every second element is an emoji, e.g. "test :fast_forward:" -> [ "test ", "fast_forward" ]
      if (i % 2 === 0) return s;
      var emoji = Emoji._get(s);
      var isMissing = emoji.indexOf(':') > -1;

      if (isMissing && typeof on_missing === 'function') {
        return on_missing(s);
      }

      if (!isMissing && typeof format === 'function') {
        return format(emoji, s);
      }

      return emoji;
    })
    .join('') // convert back to string
    ;
};

/**
 * return a random emoji
 * @return {string}
 */
Emoji.random = function random() {
  var emojiKeys = Object.keys(emojiByName);
  var randomIndex = Math.floor(Math.random() * emojiKeys.length);
  var key = emojiKeys[randomIndex];
  var emoji = Emoji._get(key);
  return { key: key, emoji: emoji };
};

/**
 *  return an collection of potential emoji matches
 *  @param {string} str
 *  @return {Array.<Object>}
 */
Emoji.search = function search(str) {
  var emojiKeys = Object.keys(emojiByName);
  var matcher = stripColons(str);
  var matchingKeys = emojiKeys.filter(function (key) {
    return key.toString().indexOf(matcher) === 0;
  });
  return matchingKeys.map(function (key) {
    return {
      key: key,
      emoji: Emoji._get(key),
    };
  });
};

/**
 * unemojify a string (replace emoji with :emoji:)
 * @param  {string} str
 * @return {string}
 */
Emoji.unemojify = function unemojify(str) {
  if (!str) return '';
  var words = lodash_toarray(str);

  return words.map(function (word) {
    return Emoji.which(word, true) || word;
  }).join('');
};

/**
 * replace emojis with replacement value
 * @param {string} str
 * @param {function|string} the string or callback function to replace the emoji with
 * @param {boolean} should trailing whitespaces be cleaned? Defaults false
 * @return {string}
 */
Emoji.replace = function replace(str, replacement, cleanSpaces) {
  if (!str) return '';

  var replace = typeof replacement === 'function' ? replacement : function () { return replacement; };
  var words = lodash_toarray(str);

  var replaced = words.map(function (word, idx) {
    var emoji = Emoji.findByCode(word);
    
    if (emoji && cleanSpaces && words[idx + 1] === ' ') {
      words[idx + 1] = '';
    }

    return emoji ? replace(emoji) : word;
  }).join('');

  return cleanSpaces ? replaced.replace(trimSpaceRegex, '') : replaced;
};


/**
 * remove all emojis from a string
 * @param {string} str
 * @return {string}
 */
Emoji.strip = function strip(str) {
  return Emoji.replace(str, '', true);
};

var emoji$2 = Emoji;

var nodeEmoji = emoji$2;

var highlight = createCommonjsModule(function (module, exports) {
/*
Syntax highlighting with language autodetection.
https://highlightjs.org/
*/

(function(factory) {

  // Find the global object for export to both the browser and web workers.
  var globalObject = typeof window === 'object' && window ||
                     typeof self === 'object' && self;

  // Setup highlight.js for different environments. First is Node.js or
  // CommonJS.
  // `nodeType` is checked to ensure that `exports` is not a HTML element.
  if( !exports.nodeType) {
    factory(exports);
  } else if(globalObject) {
    // Export hljs globally even when using AMD for cases when this script
    // is loaded with others that may still expect a global hljs.
    globalObject.hljs = factory({});
  }

}(function(hljs) {
  // Convenience variables for build-in objects
  var ArrayProto = [],
      objectKeys = Object.keys;

  // Global internal variables used within the highlight.js library.
  var languages = {},
      aliases   = {};

  // Regular expressions used throughout the highlight.js library.
  var noHighlightRe    = /^(no-?highlight|plain|text)$/i,
      languagePrefixRe = /\blang(?:uage)?-([\w-]+)\b/i,
      fixMarkupRe      = /((^(<[^>]+>|\t|)+|(?:\n)))/gm;

  var spanEndTag = '</span>';

  // Global options used when within external APIs. This is modified when
  // calling the `hljs.configure` function.
  var options = {
    classPrefix: 'hljs-',
    tabReplace: null,
    useBR: false,
    languages: undefined
  };

  // keywords that should have no default relevance value
  var COMMON_KEYWORDS = 'of and for in not or if then'.split(' ');


  /* Utility functions */

  function escape(value) {
    return value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  }

  function tag(node) {
    return node.nodeName.toLowerCase();
  }

  function testRe(re, lexeme) {
    var match = re && re.exec(lexeme);
    return match && match.index === 0;
  }

  function isNotHighlighted(language) {
    return noHighlightRe.test(language);
  }

  function blockLanguage(block) {
    var i, match, length, _class;
    var classes = block.className + ' ';

    classes += block.parentNode ? block.parentNode.className : '';

    // language-* takes precedence over non-prefixed class names.
    match = languagePrefixRe.exec(classes);
    if (match) {
      return getLanguage(match[1]) ? match[1] : 'no-highlight';
    }

    classes = classes.split(/\s+/);

    for (i = 0, length = classes.length; i < length; i++) {
      _class = classes[i];

      if (isNotHighlighted(_class) || getLanguage(_class)) {
        return _class;
      }
    }
  }

  function inherit(parent) {  // inherit(parent, override_obj, override_obj, ...)
    var key;
    var result = {};
    var objects = Array.prototype.slice.call(arguments, 1);

    for (key in parent)
      result[key] = parent[key];
    objects.forEach(function(obj) {
      for (key in obj)
        result[key] = obj[key];
    });
    return result;
  }

  /* Stream merging */

  function nodeStream(node) {
    var result = [];
    (function _nodeStream(node, offset) {
      for (var child = node.firstChild; child; child = child.nextSibling) {
        if (child.nodeType === 3)
          offset += child.nodeValue.length;
        else if (child.nodeType === 1) {
          result.push({
            event: 'start',
            offset: offset,
            node: child
          });
          offset = _nodeStream(child, offset);
          // Prevent void elements from having an end tag that would actually
          // double them in the output. There are more void elements in HTML
          // but we list only those realistically expected in code display.
          if (!tag(child).match(/br|hr|img|input/)) {
            result.push({
              event: 'stop',
              offset: offset,
              node: child
            });
          }
        }
      }
      return offset;
    })(node, 0);
    return result;
  }

  function mergeStreams(original, highlighted, value) {
    var processed = 0;
    var result = '';
    var nodeStack = [];

    function selectStream() {
      if (!original.length || !highlighted.length) {
        return original.length ? original : highlighted;
      }
      if (original[0].offset !== highlighted[0].offset) {
        return (original[0].offset < highlighted[0].offset) ? original : highlighted;
      }

      /*
      To avoid starting the stream just before it should stop the order is
      ensured that original always starts first and closes last:

      if (event1 == 'start' && event2 == 'start')
        return original;
      if (event1 == 'start' && event2 == 'stop')
        return highlighted;
      if (event1 == 'stop' && event2 == 'start')
        return original;
      if (event1 == 'stop' && event2 == 'stop')
        return highlighted;

      ... which is collapsed to:
      */
      return highlighted[0].event === 'start' ? original : highlighted;
    }

    function open(node) {
      function attr_str(a) {return ' ' + a.nodeName + '="' + escape(a.value).replace('"', '&quot;') + '"';}
      result += '<' + tag(node) + ArrayProto.map.call(node.attributes, attr_str).join('') + '>';
    }

    function close(node) {
      result += '</' + tag(node) + '>';
    }

    function render(event) {
      (event.event === 'start' ? open : close)(event.node);
    }

    while (original.length || highlighted.length) {
      var stream = selectStream();
      result += escape(value.substring(processed, stream[0].offset));
      processed = stream[0].offset;
      if (stream === original) {
        /*
        On any opening or closing tag of the original markup we first close
        the entire highlighted node stack, then render the original tag along
        with all the following original tags at the same offset and then
        reopen all the tags on the highlighted stack.
        */
        nodeStack.reverse().forEach(close);
        do {
          render(stream.splice(0, 1)[0]);
          stream = selectStream();
        } while (stream === original && stream.length && stream[0].offset === processed);
        nodeStack.reverse().forEach(open);
      } else {
        if (stream[0].event === 'start') {
          nodeStack.push(stream[0].node);
        } else {
          nodeStack.pop();
        }
        render(stream.splice(0, 1)[0]);
      }
    }
    return result + escape(value.substr(processed));
  }

  /* Initialization */

  function dependencyOnParent(mode) {
    if (!mode) return false;

    return mode.endsWithParent || dependencyOnParent(mode.starts)
  }

  function expand_or_clone_mode(mode) {
    if (mode.variants && !mode.cached_variants) {
      mode.cached_variants = mode.variants.map(function(variant) {
        return inherit(mode, {variants: null}, variant);
      });
    }

    // EXPAND
    // if we have variants then essentually "replace" the mode with the variants
    // this happens in compileMode, where this function is called from
    if (mode.cached_variants)
      return mode.cached_variants;

    // CLONE
    // if we have dependencies on parents then we need a unique
    // instance of ourselves, so we can be reused with many
    // different parents without issue
    if (dependencyOnParent(mode))
      return [inherit(mode, { starts: mode.starts ? inherit(mode.starts) : null })]

    // no special dependency issues, just return ourselves
    return [mode]
  }

  function compileKeywords(rawKeywords, case_insensitive) {
      var compiled_keywords = {};

      if (typeof rawKeywords === 'string') { // string
        splitAndCompile('keyword', rawKeywords);
      } else {
        objectKeys(rawKeywords).forEach(function (className) {
          splitAndCompile(className, rawKeywords[className]);
        });
      }
    return compiled_keywords;

    // ---

    function splitAndCompile(className, str) {
      if (case_insensitive) {
        str = str.toLowerCase();
      }
      str.split(' ').forEach(function(keyword) {
        var pair = keyword.split('|');
        compiled_keywords[pair[0]] = [className, scoreForKeyword(pair[0], pair[1])];
      });
    }  }

  function scoreForKeyword(keyword, providedScore) {
    // manual scores always win over common keywords
    // so you can force a score of 1 if you really insist
    if (providedScore)
      return Number(providedScore)

    return commonKeyword(keyword) ? 0 : 1;
  }

  function commonKeyword(word) {
    return COMMON_KEYWORDS.indexOf(word.toLowerCase()) != -1
  }

  function compileLanguage(language) {

    function reStr(re) {
        return (re && re.source) || re;
    }

    function langRe(value, global) {
      return new RegExp(
        reStr(value),
        'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '')
      );
    }

    function reCountMatchGroups(re) {
      return (new RegExp(re.toString() + '|')).exec('').length - 1;
    }

    // joinRe logically computes regexps.join(separator), but fixes the
    // backreferences so they continue to match.
    // it also places each individual regular expression into it's own
    // match group, keeping track of the sequencing of those match groups
    // is currently an exercise for the caller. :-)
    function joinRe(regexps, separator) {
      // backreferenceRe matches an open parenthesis or backreference. To avoid
      // an incorrect parse, it additionally matches the following:
      // - [...] elements, where the meaning of parentheses and escapes change
      // - other escape sequences, so we do not misparse escape sequences as
      //   interesting elements
      // - non-matching or lookahead parentheses, which do not capture. These
      //   follow the '(' with a '?'.
      var backreferenceRe = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
      var numCaptures = 0;
      var ret = '';
      for (var i = 0; i < regexps.length; i++) {
        numCaptures += 1;
        var offset = numCaptures;
        var re = reStr(regexps[i]);
        if (i > 0) {
          ret += separator;
        }
        ret += "(";
        while (re.length > 0) {
          var match = backreferenceRe.exec(re);
          if (match == null) {
            ret += re;
            break;
          }
          ret += re.substring(0, match.index);
          re = re.substring(match.index + match[0].length);
          if (match[0][0] == '\\' && match[1]) {
            // Adjust the backreference.
            ret += '\\' + String(Number(match[1]) + offset);
          } else {
            ret += match[0];
            if (match[0] == '(') {
              numCaptures++;
            }
          }
        }
        ret += ")";
      }
      return ret;
    }

    function buildModeRegex(mode) {

      var matchIndexes = {};
      var matcherRe;
      var regexes = [];
      var matcher = {};
      var matchAt = 1;

      function addRule(rule, regex) {
        matchIndexes[matchAt] = rule;
        regexes.push([rule, regex]);
        matchAt += reCountMatchGroups(regex) + 1;
      }

      var term;
      for (var i=0; i < mode.contains.length; i++) {
        var re;
        term = mode.contains[i];
        if (term.beginKeywords) {
          re = '\\.?(?:' + term.begin + ')\\.?';
        } else {
          re = term.begin;
        }
        addRule(term, re);
      }
      if (mode.terminator_end)
        addRule("end", mode.terminator_end);
      if (mode.illegal)
        addRule("illegal", mode.illegal);

      var terminators = regexes.map(function(el) { return el[1] });
      matcherRe = langRe(joinRe(terminators, '|'), true);

      matcher.lastIndex = 0;
      matcher.exec = function(s) {
        var rule;

        if( regexes.length === 0) return null;

        matcherRe.lastIndex = matcher.lastIndex;
        var match = matcherRe.exec(s);
        if (!match) { return null; }

        for(var i = 0; i<match.length; i++) {
          if (match[i] != undefined && matchIndexes["" +i] != undefined ) {
            rule = matchIndexes[""+i];
            break;
          }
        }

        // illegal or end match
        if (typeof rule === "string") {
          match.type = rule;
          match.extra = [mode.illegal, mode.terminator_end];
        } else {
          match.type = "begin";
          match.rule = rule;
        }
        return match;
      };

      return matcher;
    }

    function compileMode(mode, parent) {
      if (mode.compiled)
        return;
      mode.compiled = true;

      mode.keywords = mode.keywords || mode.beginKeywords;
      if (mode.keywords)
        mode.keywords = compileKeywords(mode.keywords, language.case_insensitive);

      mode.lexemesRe = langRe(mode.lexemes || /\w+/, true);

      if (parent) {
        if (mode.beginKeywords) {
          mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')\\b';
        }
        if (!mode.begin)
          mode.begin = /\B|\b/;
        mode.beginRe = langRe(mode.begin);
        if (mode.endSameAsBegin)
          mode.end = mode.begin;
        if (!mode.end && !mode.endsWithParent)
          mode.end = /\B|\b/;
        if (mode.end)
          mode.endRe = langRe(mode.end);
        mode.terminator_end = reStr(mode.end) || '';
        if (mode.endsWithParent && parent.terminator_end)
          mode.terminator_end += (mode.end ? '|' : '') + parent.terminator_end;
      }
      if (mode.illegal)
        mode.illegalRe = langRe(mode.illegal);
      if (mode.relevance == null)
        mode.relevance = 1;
      if (!mode.contains) {
        mode.contains = [];
      }
      mode.contains = Array.prototype.concat.apply([], mode.contains.map(function(c) {
        return expand_or_clone_mode(c === 'self' ? mode : c);
      }));
      mode.contains.forEach(function(c) {compileMode(c, mode);});

      if (mode.starts) {
        compileMode(mode.starts, parent);
      }

      mode.terminators = buildModeRegex(mode);
    }

    compileMode(language);
  }

  /*
  Core highlighting function. Accepts a language name, or an alias, and a
  string with the code to highlight. Returns an object with the following
  properties:

  - relevance (int)
  - value (an HTML string with highlighting markup)

  */
  function highlight(name, value, ignore_illegals, continuation) {

    function escapeRe(value) {
      return new RegExp(value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'm');
    }

    function endOfMode(mode, lexeme) {
      if (testRe(mode.endRe, lexeme)) {
        while (mode.endsParent && mode.parent) {
          mode = mode.parent;
        }
        return mode;
      }
      if (mode.endsWithParent) {
        return endOfMode(mode.parent, lexeme);
      }
    }

    function keywordMatch(mode, match) {
      var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0];
      return mode.keywords.hasOwnProperty(match_str) && mode.keywords[match_str];
    }

    function buildSpan(classname, insideSpan, leaveOpen, noPrefix) {
      if (!leaveOpen && insideSpan === '') return '';
      if (!classname) return insideSpan;

      var classPrefix = noPrefix ? '' : options.classPrefix,
          openSpan    = '<span class="' + classPrefix,
          closeSpan   = leaveOpen ? '' : spanEndTag;

      openSpan += classname + '">';

      return openSpan + insideSpan + closeSpan;
    }

    function processKeywords() {
      var keyword_match, last_index, match, result;

      if (!top.keywords)
        return escape(mode_buffer);

      result = '';
      last_index = 0;
      top.lexemesRe.lastIndex = 0;
      match = top.lexemesRe.exec(mode_buffer);

      while (match) {
        result += escape(mode_buffer.substring(last_index, match.index));
        keyword_match = keywordMatch(top, match);
        if (keyword_match) {
          relevance += keyword_match[1];
          result += buildSpan(keyword_match[0], escape(match[0]));
        } else {
          result += escape(match[0]);
        }
        last_index = top.lexemesRe.lastIndex;
        match = top.lexemesRe.exec(mode_buffer);
      }
      return result + escape(mode_buffer.substr(last_index));
    }

    function processSubLanguage() {
      var explicit = typeof top.subLanguage === 'string';
      if (explicit && !languages[top.subLanguage]) {
        return escape(mode_buffer);
      }

      var result = explicit ?
                   highlight(top.subLanguage, mode_buffer, true, continuations[top.subLanguage]) :
                   highlightAuto(mode_buffer, top.subLanguage.length ? top.subLanguage : undefined);

      // Counting embedded language score towards the host language may be disabled
      // with zeroing the containing mode relevance. Usecase in point is Markdown that
      // allows XML everywhere and makes every XML snippet to have a much larger Markdown
      // score.
      if (top.relevance > 0) {
        relevance += result.relevance;
      }
      if (explicit) {
        continuations[top.subLanguage] = result.top;
      }
      return buildSpan(result.language, result.value, false, true);
    }

    function processBuffer() {
      result += (top.subLanguage != null ? processSubLanguage() : processKeywords());
      mode_buffer = '';
    }

    function startNewMode(mode) {
      result += mode.className? buildSpan(mode.className, '', true): '';
      top = Object.create(mode, {parent: {value: top}});
    }


    function doBeginMatch(match) {
      var lexeme = match[0];
      var new_mode = match.rule;

      if (new_mode && new_mode.endSameAsBegin) {
        new_mode.endRe = escapeRe( lexeme );
      }

      if (new_mode.skip) {
        mode_buffer += lexeme;
      } else {
        if (new_mode.excludeBegin) {
          mode_buffer += lexeme;
        }
        processBuffer();
        if (!new_mode.returnBegin && !new_mode.excludeBegin) {
          mode_buffer = lexeme;
        }
      }
      startNewMode(new_mode);
      return new_mode.returnBegin ? 0 : lexeme.length;
    }

    function doEndMatch(match) {
      var lexeme = match[0];
      var end_mode = endOfMode(top, lexeme);
      if (!end_mode) { return; }

      var origin = top;
      if (origin.skip) {
        mode_buffer += lexeme;
      } else {
        if (!(origin.returnEnd || origin.excludeEnd)) {
          mode_buffer += lexeme;
        }
        processBuffer();
        if (origin.excludeEnd) {
          mode_buffer = lexeme;
        }
      }
      do {
        if (top.className) {
          result += spanEndTag;
        }
        if (!top.skip && !top.subLanguage) {
          relevance += top.relevance;
        }
        top = top.parent;
      } while (top !== end_mode.parent);
      if (end_mode.starts) {
        if (end_mode.endSameAsBegin) {
          end_mode.starts.endRe = end_mode.endRe;
        }
        startNewMode(end_mode.starts);
      }
      return origin.returnEnd ? 0 : lexeme.length;
    }

    var lastMatch = {};
    function processLexeme(text_before_match, match) {

      var lexeme = match && match[0];

      // add non-matched text to the current mode buffer
      mode_buffer += text_before_match;

      if (lexeme == null) {
        processBuffer();
        return 0;
      }

      // we've found a 0 width match and we're stuck, so we need to advance
      // this happens when we have badly behaved rules that have optional matchers to the degree that
      // sometimes they can end up matching nothing at all
      // Ref: https://github.com/highlightjs/highlight.js/issues/2140
      if (lastMatch.type=="begin" && match.type=="end" && lastMatch.index == match.index && lexeme === "") {
        // spit the "skipped" character that our regex choked on back into the output sequence
        mode_buffer += value.slice(match.index, match.index + 1);
        return 1;
      }
      lastMatch = match;

      if (match.type==="begin") {
        return doBeginMatch(match);
      } else if (match.type==="illegal" && !ignore_illegals) {
        // illegal match, we do not continue processing
        throw new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.className || '<unnamed>') + '"');
      } else if (match.type==="end") {
        var processed = doEndMatch(match);
        if (processed != undefined)
          return processed;
      }

      /*
      Why might be find ourselves here?  Only one occasion now.  An end match that was
      triggered but could not be completed.  When might this happen?  When an `endSameasBegin`
      rule sets the end rule to a specific match.  Since the overall mode termination rule that's
      being used to scan the text isn't recompiled that means that any match that LOOKS like
      the end (but is not, because it is not an exact match to the beginning) will
      end up here.  A definite end match, but when `doEndMatch` tries to "reapply"
      the end rule and fails to match, we wind up here, and just silently ignore the end.

      This causes no real harm other than stopping a few times too many.
      */

      mode_buffer += lexeme;
      return lexeme.length;
    }

    var language = getLanguage(name);
    if (!language) {
      throw new Error('Unknown language: "' + name + '"');
    }

    compileLanguage(language);
    var top = continuation || language;
    var continuations = {}; // keep continuations for sub-languages
    var result = '', current;
    for(current = top; current !== language; current = current.parent) {
      if (current.className) {
        result = buildSpan(current.className, '', true) + result;
      }
    }
    var mode_buffer = '';
    var relevance = 0;
    try {
      var match, count, index = 0;
      while (true) {
        top.terminators.lastIndex = index;
        match = top.terminators.exec(value);
        if (!match)
          break;
        count = processLexeme(value.substring(index, match.index), match);
        index = match.index + count;
      }
      processLexeme(value.substr(index));
      for(current = top; current.parent; current = current.parent) { // close dangling modes
        if (current.className) {
          result += spanEndTag;
        }
      }
      return {
        relevance: relevance,
        value: result,
        illegal:false,
        language: name,
        top: top
      };
    } catch (e) {
      if (e.message && e.message.indexOf('Illegal') !== -1) {
        return {
          illegal: true,
          relevance: 0,
          value: escape(value)
        };
      } else {
        throw e;
      }
    }
  }

  /*
  Highlighting with language detection. Accepts a string with the code to
  highlight. Returns an object with the following properties:

  - language (detected language)
  - relevance (int)
  - value (an HTML string with highlighting markup)
  - second_best (object with the same structure for second-best heuristically
    detected language, may be absent)

  */
  function highlightAuto(text, languageSubset) {
    languageSubset = languageSubset || options.languages || objectKeys(languages);
    var result = {
      relevance: 0,
      value: escape(text)
    };
    var second_best = result;
    languageSubset.filter(getLanguage).filter(autoDetection).forEach(function(name) {
      var current = highlight(name, text, false);
      current.language = name;
      if (current.relevance > second_best.relevance) {
        second_best = current;
      }
      if (current.relevance > result.relevance) {
        second_best = result;
        result = current;
      }
    });
    if (second_best.language) {
      result.second_best = second_best;
    }
    return result;
  }

  /*
  Post-processing of the highlighted markup:

  - replace TABs with something more useful
  - replace real line-breaks with '<br>' for non-pre containers

  */
  function fixMarkup(value) {
    return !(options.tabReplace || options.useBR)
      ? value
      : value.replace(fixMarkupRe, function(match, p1) {
          if (options.useBR && match === '\n') {
            return '<br>';
          } else if (options.tabReplace) {
            return p1.replace(/\t/g, options.tabReplace);
          }
          return '';
      });
  }

  function buildClassName(prevClassName, currentLang, resultLang) {
    var language = currentLang ? aliases[currentLang] : resultLang,
        result   = [prevClassName.trim()];

    if (!prevClassName.match(/\bhljs\b/)) {
      result.push('hljs');
    }

    if (prevClassName.indexOf(language) === -1) {
      result.push(language);
    }

    return result.join(' ').trim();
  }

  /*
  Applies highlighting to a DOM node containing code. Accepts a DOM node and
  two optional parameters for fixMarkup.
  */
  function highlightBlock(block) {
    var node, originalStream, result, resultNode, text;
    var language = blockLanguage(block);

    if (isNotHighlighted(language))
        return;

    if (options.useBR) {
      node = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      node.innerHTML = block.innerHTML.replace(/\n/g, '').replace(/<br[ \/]*>/g, '\n');
    } else {
      node = block;
    }
    text = node.textContent;
    result = language ? highlight(language, text, true) : highlightAuto(text);

    originalStream = nodeStream(node);
    if (originalStream.length) {
      resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
      resultNode.innerHTML = result.value;
      result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
    }
    result.value = fixMarkup(result.value);

    block.innerHTML = result.value;
    block.className = buildClassName(block.className, language, result.language);
    block.result = {
      language: result.language,
      re: result.relevance
    };
    if (result.second_best) {
      block.second_best = {
        language: result.second_best.language,
        re: result.second_best.relevance
      };
    }
  }

  /*
  Updates highlight.js global options with values passed in the form of an object.
  */
  function configure(user_options) {
    options = inherit(options, user_options);
  }

  /*
  Applies highlighting to all <pre><code>..</code></pre> blocks on a page.
  */
  function initHighlighting() {
    if (initHighlighting.called)
      return;
    initHighlighting.called = true;

    var blocks = document.querySelectorAll('pre code');
    ArrayProto.forEach.call(blocks, highlightBlock);
  }

  /*
  Attaches highlighting to the page load event.
  */
  function initHighlightingOnLoad() {
    addEventListener('DOMContentLoaded', initHighlighting, false);
    addEventListener('load', initHighlighting, false);
  }

  function registerLanguage(name, language) {
    var lang = languages[name] = language(hljs);
    lang.rawDefinition = language.bind(null,hljs);

    if (lang.aliases) {
      lang.aliases.forEach(function(alias) {aliases[alias] = name;});
    }
  }

  function listLanguages() {
    return objectKeys(languages);
  }

  function getLanguage(name) {
    name = (name || '').toLowerCase();
    return languages[name] || languages[aliases[name]];
  }

  function autoDetection(name) {
    var lang = getLanguage(name);
    return lang && !lang.disableAutodetect;
  }

  /* Interface definition */

  hljs.highlight = highlight;
  hljs.highlightAuto = highlightAuto;
  hljs.fixMarkup = fixMarkup;
  hljs.highlightBlock = highlightBlock;
  hljs.configure = configure;
  hljs.initHighlighting = initHighlighting;
  hljs.initHighlightingOnLoad = initHighlightingOnLoad;
  hljs.registerLanguage = registerLanguage;
  hljs.listLanguages = listLanguages;
  hljs.getLanguage = getLanguage;
  hljs.autoDetection = autoDetection;
  hljs.inherit = inherit;

  // Common regexps
  hljs.IDENT_RE = '[a-zA-Z]\\w*';
  hljs.UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*';
  hljs.NUMBER_RE = '\\b\\d+(\\.\\d+)?';
  hljs.C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float
  hljs.BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b...
  hljs.RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~';

  // Common modes
  hljs.BACKSLASH_ESCAPE = {
    begin: '\\\\[\\s\\S]', relevance: 0
  };
  hljs.APOS_STRING_MODE = {
    className: 'string',
    begin: '\'', end: '\'',
    illegal: '\\n',
    contains: [hljs.BACKSLASH_ESCAPE]
  };
  hljs.QUOTE_STRING_MODE = {
    className: 'string',
    begin: '"', end: '"',
    illegal: '\\n',
    contains: [hljs.BACKSLASH_ESCAPE]
  };
  hljs.PHRASAL_WORDS_MODE = {
    begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
  };
  hljs.COMMENT = function (begin, end, inherits) {
    var mode = hljs.inherit(
      {
        className: 'comment',
        begin: begin, end: end,
        contains: []
      },
      inherits || {}
    );
    mode.contains.push(hljs.PHRASAL_WORDS_MODE);
    mode.contains.push({
      className: 'doctag',
      begin: '(?:TODO|FIXME|NOTE|BUG|XXX):',
      relevance: 0
    });
    return mode;
  };
  hljs.C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$');
  hljs.C_BLOCK_COMMENT_MODE = hljs.COMMENT('/\\*', '\\*/');
  hljs.HASH_COMMENT_MODE = hljs.COMMENT('#', '$');
  hljs.NUMBER_MODE = {
    className: 'number',
    begin: hljs.NUMBER_RE,
    relevance: 0
  };
  hljs.C_NUMBER_MODE = {
    className: 'number',
    begin: hljs.C_NUMBER_RE,
    relevance: 0
  };
  hljs.BINARY_NUMBER_MODE = {
    className: 'number',
    begin: hljs.BINARY_NUMBER_RE,
    relevance: 0
  };
  hljs.CSS_NUMBER_MODE = {
    className: 'number',
    begin: hljs.NUMBER_RE + '(' +
      '%|em|ex|ch|rem'  +
      '|vw|vh|vmin|vmax' +
      '|cm|mm|in|pt|pc|px' +
      '|deg|grad|rad|turn' +
      '|s|ms' +
      '|Hz|kHz' +
      '|dpi|dpcm|dppx' +
      ')?',
    relevance: 0
  };
  hljs.REGEXP_MODE = {
    className: 'regexp',
    begin: /\//, end: /\/[gimuy]*/,
    illegal: /\n/,
    contains: [
      hljs.BACKSLASH_ESCAPE,
      {
        begin: /\[/, end: /\]/,
        relevance: 0,
        contains: [hljs.BACKSLASH_ESCAPE]
      }
    ]
  };
  hljs.TITLE_MODE = {
    className: 'title',
    begin: hljs.IDENT_RE,
    relevance: 0
  };
  hljs.UNDERSCORE_TITLE_MODE = {
    className: 'title',
    begin: hljs.UNDERSCORE_IDENT_RE,
    relevance: 0
  };
  hljs.METHOD_GUARD = {
    // excludes method names from keyword processing
    begin: '\\.\\s*' + hljs.UNDERSCORE_IDENT_RE,
    relevance: 0
  };

  return hljs;
}));
});

var yaml = function(hljs) {
  var LITERALS = 'true false yes no null';

  // Define keys as starting with a word character
  // ...containing word chars, spaces, colons, forward-slashes, hyphens and periods
  // ...and ending with a colon followed immediately by a space, tab or newline.
  // The YAML spec allows for much more than this, but this covers most use-cases.
  var KEY = {
    className: 'attr',
    variants: [
      { begin: '\\w[\\w :\\/.-]*:(?=[ \t]|$)' },
      { begin: '"\\w[\\w :\\/.-]*":(?=[ \t]|$)' }, //double quoted keys
      { begin: '\'\\w[\\w :\\/.-]*\':(?=[ \t]|$)' } //single quoted keys
    ]
  };

  var TEMPLATE_VARIABLES = {
    className: 'template-variable',
    variants: [
      { begin: '\{\{', end: '\}\}' }, // jinja templates Ansible
      { begin: '%\{', end: '\}' } // Ruby i18n
    ]
  };
  var STRING = {
    className: 'string',
    relevance: 0,
    variants: [
      {begin: /'/, end: /'/},
      {begin: /"/, end: /"/},
      {begin: /\S+/}
    ],
    contains: [
      hljs.BACKSLASH_ESCAPE,
      TEMPLATE_VARIABLES
    ]
  };

  return {
    case_insensitive: true,
    aliases: ['yml', 'YAML', 'yaml'],
    contains: [
      KEY,
      {
        className: 'meta',
        begin: '^---\s*$',
        relevance: 10
      },
      { // multi line string
        // Blocks start with a | or > followed by a newline
        //
        // Indentation of subsequent lines must be the same to
        // be considered part of the block
        className: 'string',
        begin: '[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*',
      },
      { // Ruby/Rails erb
        begin: '<%[%=-]?', end: '[%-]?%>',
        subLanguage: 'ruby',
        excludeBegin: true,
        excludeEnd: true,
        relevance: 0
      },
      { // local tags
        className: 'type',
        begin: '!' + hljs.UNDERSCORE_IDENT_RE,
      },
      { // data type
        className: 'type',
        begin: '!!' + hljs.UNDERSCORE_IDENT_RE,
      },
      { // fragment id &ref
        className: 'meta',
        begin: '&' + hljs.UNDERSCORE_IDENT_RE + '$',
      },
      { // fragment reference *ref
        className: 'meta',
        begin: '\\*' + hljs.UNDERSCORE_IDENT_RE + '$'
      },
      { // array listing
        className: 'bullet',
      // TODO: remove |$ hack when we have proper look-ahead support
      begin: '\\-(?=[ ]|$)',
        relevance: 0
      },
      hljs.HASH_COMMENT_MODE,
      {
        beginKeywords: LITERALS,
        keywords: {literal: LITERALS}
      },
      // numbers are any valid C-style number that
      // sit isolated from other words
      {
        className: 'number',
        begin: hljs.C_NUMBER_RE + '\\b'
      },
      STRING
    ]
  };
};

// from https://raw.githubusercontent.com/highlightjs/highlight.js/master/src/styles/github.css
const HLJS = css `
  /*

github.com style (c) Vasily Polovnyov <vast@whiteants.net>

*/

  .hljs {
    display: block;
    overflow-x: auto;
    padding: 0.5em;
    color: #333;
    background: #f8f8f8;
  }

  .hljs-comment,
  .hljs-quote {
    color: #998;
    font-style: italic;
  }

  .hljs-keyword,
  .hljs-selector-tag,
  .hljs-subst {
    color: #333;
    font-weight: bold;
  }

  .hljs-number,
  .hljs-literal,
  .hljs-variable,
  .hljs-template-variable,
  .hljs-tag .hljs-attr {
    color: #008080;
  }

  .hljs-string,
  .hljs-doctag {
    color: #d14;
  }

  .hljs-title,
  .hljs-section,
  .hljs-selector-id {
    color: #900;
    font-weight: bold;
  }

  .hljs-subst {
    font-weight: normal;
  }

  .hljs-type,
  .hljs-class .hljs-title {
    color: #458;
    font-weight: bold;
  }

  .hljs-tag,
  .hljs-name,
  .hljs-attribute {
    color: #000080;
    font-weight: normal;
  }

  .hljs-regexp,
  .hljs-link {
    color: #009926;
  }

  .hljs-symbol,
  .hljs-bullet {
    color: #990073;
  }

  .hljs-built_in,
  .hljs-builtin-name {
    color: #0086b3;
  }

  .hljs-meta {
    color: #999;
    font-weight: bold;
  }

  .hljs-deletion {
    background: #fdd;
  }

  .hljs-addition {
    background: #dfd;
  }

  .hljs-emphasis {
    font-style: italic;
  }

  .hljs-strong {
    font-weight: bold;
  }
`;
// From https://github.com/sindresorhus/github-markdown-css/blob/gh-pages/github-markdown.css
const GFM1 = css `
  @font-face {
    font-family: octicons-link;
    src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==)
      format('woff');
  }
`;
const GFM2 = css `
  .markdown-body .octicon {
    display: inline-block;
    fill: currentColor;
    vertical-align: text-bottom;
  }

  .markdown-body .anchor {
    float: left;
    line-height: 1;
    margin-left: -20px;
    padding-right: 4px;
  }

  .markdown-body .anchor:focus {
    outline: none;
  }

  .markdown-body h1 .octicon-link,
  .markdown-body h2 .octicon-link,
  .markdown-body h3 .octicon-link,
  .markdown-body h4 .octicon-link,
  .markdown-body h5 .octicon-link,
  .markdown-body h6 .octicon-link {
    color: #1b1f23;
    vertical-align: middle;
    visibility: hidden;
  }

  .markdown-body h1:hover .anchor,
  .markdown-body h2:hover .anchor,
  .markdown-body h3:hover .anchor,
  .markdown-body h4:hover .anchor,
  .markdown-body h5:hover .anchor,
  .markdown-body h6:hover .anchor {
    text-decoration: none;
  }

  .markdown-body h1:hover .anchor .octicon-link,
  .markdown-body h2:hover .anchor .octicon-link,
  .markdown-body h3:hover .anchor .octicon-link,
  .markdown-body h4:hover .anchor .octicon-link,
  .markdown-body h5:hover .anchor .octicon-link,
  .markdown-body h6:hover .anchor .octicon-link {
    visibility: visible;
  }
  .markdown-body {
    -ms-text-size-adjust: 100%;
    -webkit-text-size-adjust: 100%;
    line-height: 1.5;
    font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji,
      Segoe UI Emoji;
    font-size: 16px;
    line-height: 1.5;
    word-wrap: break-word;
  }

  .markdown-body .pl-c {
    color: #6a737d;
  }

  .markdown-body .pl-c1,
  .markdown-body .pl-s .pl-v {
    color: #005cc5;
  }

  .markdown-body .pl-e,
  .markdown-body .pl-en {
    color: #6f42c1;
  }

  .markdown-body .pl-s .pl-s1,
  .markdown-body .pl-smi {
    color: #24292e;
  }

  .markdown-body .pl-ent {
    color: #22863a;
  }

  .markdown-body .pl-k {
    color: #d73a49;
  }

  .markdown-body .pl-pds,
  .markdown-body .pl-s,
  .markdown-body .pl-s .pl-pse .pl-s1,
  .markdown-body .pl-sr,
  .markdown-body .pl-sr .pl-cce,
  .markdown-body .pl-sr .pl-sra,
  .markdown-body .pl-sr .pl-sre {
    color: #032f62;
  }

  .markdown-body .pl-smw,
  .markdown-body .pl-v {
    color: #e36209;
  }

  .markdown-body .pl-bu {
    color: #b31d28;
  }

  .markdown-body .pl-ii {
    color: #fafbfc;
    background-color: #b31d28;
  }

  .markdown-body .pl-c2 {
    color: #fafbfc;
    background-color: #d73a49;
  }

  .markdown-body .pl-c2:before {
    content: '^M';
  }

  .markdown-body .pl-sr .pl-cce {
    font-weight: 700;
    color: #22863a;
  }

  .markdown-body .pl-ml {
    color: #735c0f;
  }

  .markdown-body .pl-mh,
  .markdown-body .pl-mh .pl-en,
  .markdown-body .pl-ms {
    font-weight: 700;
    color: #005cc5;
  }

  .markdown-body .pl-mi {
    font-style: italic;
    color: #24292e;
  }

  .markdown-body .pl-mb {
    font-weight: 700;
    color: #24292e;
  }

  .markdown-body .pl-md {
    color: #b31d28;
    background-color: #ffeef0;
  }

  .markdown-body .pl-mi1 {
    color: #22863a;
    background-color: #f0fff4;
  }

  .markdown-body .pl-mc {
    color: #e36209;
    background-color: #ffebda;
  }

  .markdown-body .pl-mi2 {
    color: #f6f8fa;
    background-color: #005cc5;
  }

  .markdown-body .pl-mdr {
    font-weight: 700;
    color: #6f42c1;
  }

  .markdown-body .pl-ba {
    color: #586069;
  }

  .markdown-body .pl-sg {
    color: #959da5;
  }

  .markdown-body .pl-corl {
    text-decoration: underline;
    color: #032f62;
  }

  .markdown-body details {
    display: block;
  }

  .markdown-body summary {
    display: list-item;
  }

  .markdown-body a {
    background-color: initial;
  }

  .markdown-body a:active,
  .markdown-body a:hover {
    outline-width: 0;
  }

  .markdown-body strong {
    font-weight: inherit;
    font-weight: bolder;
  }

  .markdown-body h1 {
    font-size: 2em;
    margin: 0.67em 0;
  }

  .markdown-body img {
    border-style: none;
  }

  .markdown-body code,
  .markdown-body kbd,
  .markdown-body pre {
    font-family: monospace, monospace;
    font-size: 1em;
  }

  .markdown-body hr {
    box-sizing: initial;
    height: 0;
    overflow: visible;
  }

  .markdown-body input {
    font: inherit;
    margin: 0;
  }

  .markdown-body input {
    overflow: visible;
  }

  .markdown-body [type='checkbox'] {
    box-sizing: border-box;
    padding: 0;
  }

  .markdown-body * {
    box-sizing: border-box;
  }

  .markdown-body input {
    font-family: inherit;
    font-size: inherit;
    line-height: inherit;
  }

  .markdown-body a {
    color: var(--link-color);
    font-weight: 600;
    text-decoration: none;
  }

  .markdown-body a:hover {
    text-decoration: underline;
  }

  .markdown-body strong {
    font-weight: 600;
  }

  .markdown-body hr {
    height: 0;
    margin: 15px 0;
    overflow: hidden;
    background: transparent;
    border: 0;
    border-bottom: 1px solid #dfe2e5;
  }

  .markdown-body hr:after,
  .markdown-body hr:before {
    display: table;
    content: '';
  }

  .markdown-body hr:after {
    clear: both;
  }

  .markdown-body table {
    border-spacing: 0;
    border-collapse: collapse;
  }

  .markdown-body td,
  .markdown-body th {
    padding: 0;
  }

  .markdown-body details summary {
    cursor: pointer;
  }

  .markdown-body kbd {
    display: inline-block;
    padding: 3px 5px;
    font: 11px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
    line-height: 10px;
    color: #444d56;
    vertical-align: middle;
    background-color: #fafbfc;
    border: 1px solid #d1d5da;
    border-radius: 3px;
    box-shadow: inset 0 -1px 0 #d1d5da;
  }

  .markdown-body h1,
  .markdown-body h2,
  .markdown-body h3,
  .markdown-body h4,
  .markdown-body h5,
  .markdown-body h6 {
    margin-top: 0;
    margin-bottom: 0;
  }

  .markdown-body h1 {
    font-size: 32px;
  }

  .markdown-body h1,
  .markdown-body h2 {
    font-weight: 600;
  }

  .markdown-body h2 {
    font-size: 24px;
  }

  .markdown-body h3 {
    font-size: 20px;
  }

  .markdown-body h3,
  .markdown-body h4 {
    font-weight: 600;
  }

  .markdown-body h4 {
    font-size: 16px;
  }

  .markdown-body h5 {
    font-size: 14px;
  }

  .markdown-body h5,
  .markdown-body h6 {
    font-weight: 600;
  }

  .markdown-body h6 {
    font-size: 12px;
  }

  .markdown-body p {
    margin-top: 0;
    margin-bottom: 10px;
  }

  .markdown-body blockquote {
    margin: 0;
  }

  .markdown-body ol,
  .markdown-body ul {
    padding-left: 0;
    margin-top: 0;
    margin-bottom: 0;
  }

  .markdown-body ol ol,
  .markdown-body ul ol {
    list-style-type: lower-roman;
  }

  .markdown-body ol ol ol,
  .markdown-body ol ul ol,
  .markdown-body ul ol ol,
  .markdown-body ul ul ol {
    list-style-type: lower-alpha;
  }

  .markdown-body dd {
    margin-left: 0;
  }

  .markdown-body code,
  .markdown-body pre {
    font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
    font-size: 12px;
  }

  .markdown-body pre {
    margin-top: 0;
    margin-bottom: 0;
  }

  .markdown-body input::-webkit-inner-spin-button,
  .markdown-body input::-webkit-outer-spin-button {
    margin: 0;
    -webkit-appearance: none;
    appearance: none;
  }

  .markdown-body .border {
    border: 1px solid #e1e4e8 !important;
  }

  .markdown-body .border-0 {
    border: 0 !important;
  }

  .markdown-body .border-bottom {
    border-bottom: 1px solid #e1e4e8 !important;
  }

  .markdown-body .rounded-1 {
    border-radius: 3px !important;
  }

  .markdown-body .bg-white {
    background-color: #fff !important;
  }

  .markdown-body .bg-gray-light {
    background-color: #fafbfc !important;
  }

  .markdown-body .text-gray-light {
    color: #6a737d !important;
  }

  .markdown-body .mb-0 {
    margin-bottom: 0 !important;
  }

  .markdown-body .my-2 {
    margin-top: 8px !important;
    margin-bottom: 8px !important;
  }

  .markdown-body .pl-0 {
    padding-left: 0 !important;
  }

  .markdown-body .py-0 {
    padding-top: 0 !important;
    padding-bottom: 0 !important;
  }

  .markdown-body .pl-1 {
    padding-left: 4px !important;
  }

  .markdown-body .pl-2 {
    padding-left: 8px !important;
  }

  .markdown-body .py-2 {
    padding-top: 8px !important;
    padding-bottom: 8px !important;
  }

  .markdown-body .pl-3,
  .markdown-body .px-3 {
    padding-left: 16px !important;
  }

  .markdown-body .px-3 {
    padding-right: 16px !important;
  }

  .markdown-body .pl-4 {
    padding-left: 24px !important;
  }

  .markdown-body .pl-5 {
    padding-left: 32px !important;
  }

  .markdown-body .pl-6 {
    padding-left: 40px !important;
  }

  .markdown-body .f6 {
    font-size: 12px !important;
  }

  .markdown-body .lh-condensed {
    line-height: 1.25 !important;
  }

  .markdown-body .text-bold {
    font-weight: 600 !important;
  }

  .markdown-body .pl-7 {
    padding-left: 48px !important;
  }

  .markdown-body .pl-8 {
    padding-left: 64px !important;
  }

  .markdown-body .pl-9 {
    padding-left: 80px !important;
  }

  .markdown-body .pl-10 {
    padding-left: 96px !important;
  }

  .markdown-body .pl-11 {
    padding-left: 112px !important;
  }

  .markdown-body .pl-12 {
    padding-left: 128px !important;
  }

  .markdown-body hr {
    border-bottom-color: #eee;
  }

  .markdown-body kbd {
    display: inline-block;
    padding: 3px 5px;
    font: 11px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
    line-height: 10px;
    color: #444d56;
    vertical-align: middle;
    background-color: #fafbfc;
    border: 1px solid #d1d5da;
    border-radius: 3px;
    box-shadow: inset 0 -1px 0 #d1d5da;
  }

  .markdown-body:after,
  .markdown-body:before {
    display: table;
    content: '';
  }

  .markdown-body:after {
    clear: both;
  }

  .markdown-body > :first-child {
    margin-top: 0 !important;
  }

  .markdown-body > :last-child {
    margin-bottom: 0 !important;
  }

  .markdown-body a:not([href]) {
    color: inherit;
    text-decoration: none;
  }
`;
const GFM3 = css `
  .markdown-body blockquote,
  .markdown-body details,
  .markdown-body dl,
  .markdown-body ol,
  .markdown-body p,
  .markdown-body pre,
  .markdown-body table,
  .markdown-body ul {
    margin-top: 0;
    margin-bottom: 16px;
  }

  .markdown-body hr {
    height: 0.25em;
    padding: 0;
    margin: 24px 0;
    background-color: #e1e4e8;
    border: 0;
  }

  .markdown-body blockquote {
    padding: 0 1em;
    color: #6a737d;
    border-left: 0.25em solid #dfe2e5;
  }

  .markdown-body blockquote > :first-child {
    margin-top: 0;
  }

  .markdown-body blockquote > :last-child {
    margin-bottom: 0;
  }

  .markdown-body h1,
  .markdown-body h2,
  .markdown-body h3,
  .markdown-body h4,
  .markdown-body h5,
  .markdown-body h6 {
    margin-top: 24px;
    margin-bottom: 16px;
    font-weight: 600;
    line-height: 1.25;
  }

  .markdown-body h1 {
    font-size: 2em;
  }

  .markdown-body h1,
  .markdown-body h2 {
    padding-bottom: 0.3em;
    border-bottom: 1px solid #eaecef;
  }

  .markdown-body h2 {
    font-size: 1.5em;
  }

  .markdown-body h3 {
    font-size: 1.25em;
  }

  .markdown-body h4 {
    font-size: 1em;
  }

  .markdown-body h5 {
    font-size: 0.875em;
  }

  .markdown-body h6 {
    font-size: 0.85em;
    color: #6a737d;
  }

  .markdown-body ol,
  .markdown-body ul {
    padding-left: 2em;
  }

  .markdown-body ol ol,
  .markdown-body ol ul,
  .markdown-body ul ol,
  .markdown-body ul ul {
    margin-top: 0;
    margin-bottom: 0;
  }

  .markdown-body li {
    word-wrap: break-all;
  }

  .markdown-body li > p {
    margin-top: 16px;
  }

  .markdown-body li + li {
    margin-top: 0.25em;
  }

  .markdown-body dl {
    padding: 0;
  }

  .markdown-body dl dt {
    padding: 0;
    margin-top: 16px;
    font-size: 1em;
    font-style: italic;
    font-weight: 600;
  }

  .markdown-body dl dd {
    padding: 0 16px;
    margin-bottom: 16px;
  }

  .markdown-body table {
    display: block;
    width: 100%;
    overflow: auto;
  }

  .markdown-body table th {
    font-weight: 600;
  }

  .markdown-body table td,
  .markdown-body table th {
    padding: 6px 13px;
    border: 1px solid #dfe2e5;
  }

  .markdown-body table th {
    background-color: var(--primary-background-color, #fff);
  }

  .markdown-body table tr {
    background-color: hsla(var(--primary-background-color, #fff), .1);
    border-top: 1px solid #c6cbd1;
  }

  .markdown-body table tr:nth-child(2n) {
    background-color: var(--primary-background-color, #fff);
  }

  .markdown-body img {
    max-width: 100%;
    box-sizing: initial;
    background-color: #fff;
  }

  .markdown-body img[align='right'] {
    padding-left: 20px;
  }

  .markdown-body img[align='left'] {
    padding-right: 20px;
  }

  .markdown-body code {
    padding: 0.2em 0.4em;
    margin: 0;
    font-size: 85%;
    background-color: rgba(27, 31, 35, 0.05);
    border-radius: 3px;
  }

  .markdown-body pre {
    word-wrap: normal;
  }

  .markdown-body pre > code {
    padding: 0;
    margin: 0;
    font-size: 100%;
    word-break: normal;
    white-space: pre;
    background: transparent;
    border: 0;
  }

  .markdown-body .highlight {
    margin-bottom: 16px;
  }

  .markdown-body .highlight pre {
    margin-bottom: 0;
    word-break: normal;
  }

  .markdown-body .highlight pre,
  .markdown-body pre {
    padding: 16px;
    overflow: auto;
    font-size: 85%;
    line-height: 1.45;
    background-color: var(--primary-background-color, #f6f8fa);
    border-radius: 3px;
  }

  .markdown-body pre code {
    display: inline;
    max-width: auto;
    padding: 0;
    margin: 0;
    overflow: visible;
    line-height: inherit;
    word-wrap: normal;
    background-color: initial;
    border: 0;
  }

  .markdown-body .commit-tease-sha {
    display: inline-block;
    font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
    font-size: 90%;
    color: #444d56;
  }

  .markdown-body .full-commit .btn-outline:not(:disabled):hover {
    color: #005cc5;
    border-color: #005cc5;
  }

  .markdown-body .blob-wrapper {
    overflow-x: auto;
    overflow-y: hidden;
  }

  .markdown-body .blob-wrapper-embedded {
    max-height: 240px;
    overflow-y: auto;
  }

  .markdown-body .blob-num {
    width: 1%;
    min-width: 50px;
    padding-right: 10px;
    padding-left: 10px;
    font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
    font-size: 12px;
    line-height: 20px;
    color: rgba(27, 31, 35, 0.3);
    text-align: right;
    white-space: nowrap;
    vertical-align: top;
    cursor: pointer;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }

  .markdown-body .blob-num:hover {
    color: rgba(27, 31, 35, 0.6);
  }

  .markdown-body .blob-num:before {
    content: attr(data-line-number);
  }

  .markdown-body .blob-code {
    position: relative;
    padding-right: 10px;
    padding-left: 10px;
    line-height: 20px;
    vertical-align: top;
  }

  .markdown-body .blob-code-inner {
    overflow: visible;
    font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
    font-size: 12px;
    color: #24292e;
    word-wrap: normal;
    white-space: pre;
  }

  .markdown-body .pl-token.active,
  .markdown-body .pl-token:hover {
    cursor: pointer;
    background: #ffea7f;
  }

  .markdown-body :checked + .radio-label {
    position: relative;
    z-index: 1;
    border-color: var(--link-color);
  }

  .markdown-body .select-menu-item input[type='radio']:not(:checked) + .octicon-check,
  .markdown-body .select-menu-item input[type='radio']:not(:checked) + .octicon-circle-slash {
    visibility: hidden;
  }

  .markdown-body .pl-7 {
    padding-left: 48px !important;
  }

  .markdown-body .pl-8 {
    padding-left: 64px !important;
  }

  .markdown-body .pl-9 {
    padding-left: 80px !important;
  }

  .markdown-body .pl-10 {
    padding-left: 96px !important;
  }

  .markdown-body .pl-11 {
    padding-left: 112px !important;
  }

  .markdown-body .pl-12 {
    padding-left: 128px !important;
  }

  .markdown-body .tab-size[data-tab-size='1'] {
    -moz-tab-size: 1;
    tab-size: 1;
  }

  .markdown-body .tab-size[data-tab-size='2'] {
    -moz-tab-size: 2;
    tab-size: 2;
  }

  .markdown-body .tab-size[data-tab-size='3'] {
    -moz-tab-size: 3;
    tab-size: 3;
  }

  .markdown-body .tab-size[data-tab-size='4'] {
    -moz-tab-size: 4;
    tab-size: 4;
  }

  .markdown-body .tab-size[data-tab-size='5'] {
    -moz-tab-size: 5;
    tab-size: 5;
  }

  .markdown-body .tab-size[data-tab-size='6'] {
    -moz-tab-size: 6;
    tab-size: 6;
  }

  .markdown-body .tab-size[data-tab-size='7'] {
    -moz-tab-size: 7;
    tab-size: 7;
  }

  .markdown-body .tab-size[data-tab-size='8'] {
    -moz-tab-size: 8;
    tab-size: 8;
  }

  .markdown-body .tab-size[data-tab-size='9'] {
    -moz-tab-size: 9;
    tab-size: 9;
  }

  .markdown-body .tab-size[data-tab-size='10'] {
    -moz-tab-size: 10;
    tab-size: 10;
  }

  .markdown-body .tab-size[data-tab-size='11'] {
    -moz-tab-size: 11;
    tab-size: 11;
  }

  .markdown-body .tab-size[data-tab-size='12'] {
    -moz-tab-size: 12;
    tab-size: 12;
  }

  .markdown-body .task-list-item {
    list-style-type: none;
  }

  .markdown-body .task-list-item + .task-list-item {
    margin-top: 3px;
  }

  .markdown-body .task-list-item input {
    margin: 0 0.2em 0.25em -1.6em;
    vertical-align: middle;
  }
`;
const GFM = [GFM1, GFM2, GFM3];

highlight.registerLanguage('yaml', yaml);
const hljs = highlight, marked$1 = marked;
marked$1.setOptions({
    highlight: function (code, lang) {
        if (lang && hljs.getLanguage(lang)) {
            return hljs.highlight(lang, code, true).value;
        }
        else {
            return hljs.highlightAuto(code).value;
        }
    },
    breaks: true,
    gfm: true,
    tables: true,
    langPrefix: '',
});
class markdown {
    static html(input) {
        input = nodeEmoji.emojify(input);
        const content = document.createElement("div");
        content.innerHTML = lib_1$1(marked$1(input));
        content.style.cssText = `${GFM} ${HLJS}`;
        return html `${content}`;
    }
}

let Authors = class Authors extends LitElement {
    render() {
        if (String(this.authors.length) === "0")
            return html ``;
        return html `
            <div class="MobileGrid">
                <p><b>${this.hass.localize("component.hacs.repository.authors")}: </b>

                    ${this.authors.map(author => html `
                        <a href="https://github.com/${author.replace("@", "")}"
                                target="_blank" rel='noreferrer'>
                            ${author.replace("@", "")}
                        </a>`)}

                </p>
            </div>
            `;
    }
    static get styles() {
        return [HacsStyle, css `
            .autors {

            }
        `];
    }
};
__decorate([
    property()
], Authors.prototype, "hass", void 0);
__decorate([
    property()
], Authors.prototype, "authors", void 0);
Authors = __decorate([
    customElement("hacs-authors")
], Authors);

let HacsRepositoryMenu = class HacsRepositoryMenu extends LitElement {
    render() {
        return html `
        <paper-menu-button no-animations horizontal-align="right" role="group" aria-haspopup="true" vertical-align="top" aria-disabled="false">
        <paper-icon-button icon="hass:dots-vertical" slot="dropdown-trigger" role="button"></paper-icon-button>
            <paper-listbox slot="dropdown-content" role="listbox" tabindex="0">


                <paper-item @click=${this.RepositoryReload}>
                    ${this.hass.localize(`component.hacs.repository.update_information`)}
                </paper-item>


                ${(this.repository.version_or_commit === "version" ? html `
                <paper-item @click=${this.RepositoryBeta}>
                    ${(this.repository.beta ?
            this.hass.localize(`component.hacs.repository.hide_beta`)
            : this.hass.localize(`component.hacs.repository.show_beta`))}
                </paper-item>`
            : "")}


                ${(!this.repository.custom && !this.repository.installed ? html `
                <paper-item @click=${this.RepositoryHide}>
                    ${this.hass.localize(`component.hacs.repository.hide`)}
                </paper-item>`
            : "")}


                <a href="https://github.com/${this.repository.full_name}" rel='noreferrer' target="_blank">
                <paper-item>
                    <ha-icon class="link-icon" icon="mdi:open-in-new"></ha-icon>
                    ${this.hass.localize(`component.hacs.repository.open_issue`)}
                </paper-item>
                </a>


                <a href="https://github.com/hacs/default/issues/new?assignees=ludeeus&labels=flag&template=flag.md&title=${this.repository.full_name}" rel='noreferrer' target="_blank">
                <paper-item>
                    <ha-icon class="link-icon" icon="mdi:open-in-new"></ha-icon>
                    ${this.hass.localize(`component.hacs.repository.flag_this`)}
                </paper-item>
                </a>


            </paper-listbox>
        </paper-menu-button>
        `;
    }
    static get styles() {
        return [HacsStyle, css `
        paper-dropdown-menu {
            width: 250px;
            margin-top: -24px;

          }
          paper-menu-button {
            float: right;
            top: -65px;
          }
        `];
    }
    RepositoryReload() {
        RepositoryWebSocketAction(this.hass, this.repository.id, "set_state", "other");
        RepositoryWebSocketAction(this.hass, this.repository.id, "update");
    }
    RepositoryBeta() {
        RepositoryWebSocketAction(this.hass, this.repository.id, "set_state", "other");
        if (this.repository.beta) {
            RepositoryWebSocketAction(this.hass, this.repository.id, "hide_beta");
        }
        else {
            RepositoryWebSocketAction(this.hass, this.repository.id, "show_beta");
        }
    }
    RepositoryHide() {
        RepositoryWebSocketAction(this.hass, this.repository.id, "set_state", "other");
        if (this.repository.hide) {
            RepositoryWebSocketAction(this.hass, this.repository.id, "unhide");
        }
        else {
            RepositoryWebSocketAction(this.hass, this.repository.id, "hide");
        }
    }
};
__decorate([
    property()
], HacsRepositoryMenu.prototype, "hass", void 0);
__decorate([
    property()
], HacsRepositoryMenu.prototype, "repository", void 0);
HacsRepositoryMenu = __decorate([
    customElement("hacs-repository-menu")
], HacsRepositoryMenu);

let HacsButtonOpenPlugin = class HacsButtonOpenPlugin extends HacsRepositoryButton {
    render() {
        if (this.repository.category != "plugin")
            return html ``;
        if (!this.repository.installed)
            return html ``;
        const path = this.repository.local_path.split("/");
        return html `
            <a href="/community_plugin/${path.pop()}/${this.repository.file_name}" target="_blank">
                <mwc-button>
                    ${this.hass.localize(`component.hacs.repository.open_plugin`)}
                </mwc-button>
            </a>
        `;
    }
};
HacsButtonOpenPlugin = __decorate([
    customElement("hacs-button-open-plugin")
], HacsButtonOpenPlugin);

let HacsButtonOpenRepository = class HacsButtonOpenRepository extends HacsRepositoryButton {
    render() {
        return html `
            <a href="https://github.com/${this.repository.full_name}" rel='noreferrer' target="_blank">
                <mwc-button>
                    ${this.hass.localize(`component.hacs.repository.repository`)}
                </mwc-button>
            </a>
        `;
    }
};
HacsButtonOpenRepository = __decorate([
    customElement("hacs-button-open-repository")
], HacsButtonOpenRepository);

let HacsButtonUninstall = class HacsButtonUninstall extends HacsRepositoryButton {
    render() {
        if (!this.repository.installed)
            return html ``;
        const label = this.hass.localize('component.hacs.repository.uninstall');
        if (this.status.background_task) {
            return html `
                <mwc-button disabled>
                    ${label}
                </mwc-button>
            `;
        }
        return html `
            <mwc-button @click=${this.RepositoryUnInstall}">
                ${(this.repository.state == "uninstalling"
            ? html `<paper-spinner active></paper-spinner>`
            : html `${label}`)}
            </mwc-button>
        `;
    }
    static get styles() {
        return [HacsStyle, css `
          mwc-button {
            --mdc-theme-primary: var(--google-red-500);
          }
        `];
    }
    RepositoryUnInstall() {
        if (window.confirm(this.hass.localize("component.hacs.confirm.uninstall", "item", this.repository.name)))
            this.ExecuteAction();
    }
    ExecuteAction() {
        RepositoryWebSocketAction(this.hass, this.repository.id, "set_state", "uninstalling");
        RepositoryWebSocketAction(this.hass, this.repository.id, "uninstall");
    }
};
HacsButtonUninstall = __decorate([
    customElement("hacs-button-uninstall")
], HacsButtonUninstall);

let HacsButtonMainAction = class HacsButtonMainAction extends HacsRepositoryButton {
    constructor() {
        super(...arguments);
        this.pathExists = false;
    }
    firstUpdated() {
        this.hass.connection.sendMessagePromise({
            type: "hacs/check_path",
            path: this.repository.local_path
        }).then((resp) => {
            this.pathExists = resp["exist"];
        }, (err) => {
            console.error('[hacs/check_path] Message failed!', err);
        });
    }
    render() {
        const label = this.hass.localize(`component.hacs.repository.${this.repository.main_action.toLowerCase()}`);
        if (this.status.background_task) {
            return html `
                <mwc-button disabled>
                    ${label}
                </mwc-button>
            `;
        }
        return html `
            <mwc-button
            @click=${this.RepositoryInstall}>
                ${(this.repository.state == "installing"
            ? html `<paper-spinner active></paper-spinner>`
            : html `${label}`)}
            </mwc-button>
        `;
    }
    RepositoryInstall() {
        if (!this.repository.can_install) {
            window.alert(`This repository version requires Home Assistant version ${this.repository.homeassistant}`);
            return;
        }
        if (this.pathExists && !this.repository.installed) {
            if (window.confirm(this.hass.localize("component.hacs.confirm.exsist", "item", this.repository.local_path)
                + "\n" + this.hass.localize("component.hacs.confirm.overwrite")
                + "\n" + this.hass.localize("component.hacs.confirm.continue")))
                this.ExecuteAction();
        }
        else
            this.ExecuteAction();
    }
    ExecuteAction() {
        RepositoryWebSocketAction(this.hass, this.repository.id, "set_state", "installing");
        RepositoryWebSocketAction(this.hass, this.repository.id, "install");
    }
};
__decorate([
    property()
], HacsButtonMainAction.prototype, "pathExists", void 0);
HacsButtonMainAction = __decorate([
    customElement("hacs-button-main-action")
], HacsButtonMainAction);

let HacsButtonChangelog = class HacsButtonChangelog extends HacsRepositoryButton {
    render() {
        if (!this.repository.pending_upgrade)
            return html ``;
        var URL = `https://github.com/${this.repository.full_name}/releases`;
        if (this.repository.version_or_commit === "commit") {
            URL = `https://github.com/${this.repository.full_name}/compare/${this.repository.installed_version}...${this.repository.available_version}`;
        }
        return html `
        <a href="${URL}" rel='noreferrer' target="_blank">
          <mwc-button>
          ${this.hass.localize(`component.hacs.repository.changelog`)}
          </mwc-button>
        </a>
        `;
    }
    RepositoryInstall() {
        RepositoryWebSocketAction(this.hass, this.repository.id, "set_state", "installing");
        RepositoryWebSocketAction(this.hass, this.repository.id, "uninstall");
    }
};
HacsButtonChangelog = __decorate([
    customElement("hacs-button-changelog")
], HacsButtonChangelog);

let LoveLaceHint = class LoveLaceHint extends LitElement {
    render() {
        return html `
            <div class="lovelace-hint markdown-body">
                <p class="example-title">${this.hass.localize(`component.hacs.repository.lovelace_instruction`)}:</p>
                <pre id="LovelaceExample" class="yaml">
  - url: /community_plugin/${this.repository.full_name.split("/")[1]}/${this.repository.file_name}
    type: ${(this.repository.javascript_type !== undefined
            ? html `${this.repository.javascript_type}`
            : html `${this.hass.localize(`component.hacs.repository.lovelace_no_js_type`)}`)}</pre>

                <paper-icon-button
                    title="${this.hass.localize(`component.hacs.repository.lovelace_copy_example`)}"
                    icon="mdi:content-copy"
                    @click="${this.CopyToLovelaceExampleToClipboard}"
                    role="button"
                ></paper-icon-button>
            </div>
            `;
    }
    CopyToLovelaceExampleToClipboard(ev) {
        var LLConfig = ev.composedPath()[4].children[0].children[1].innerText;
        document.addEventListener('copy', (e) => {
            e.clipboardData.setData('text/plain', (LLConfig));
            e.preventDefault();
            document.removeEventListener('copy', null);
        });
        document.execCommand('copy');
    }
    static get styles() {
        return [HacsStyle, GFM, css `
            .lovelace-hint {

            }
            .example-title {
                margin-block-end: 0em;
            }
            .yaml {
                overflow: auto;
                display: inline-flex;
                width: calc(100% - 46px);
                white-space: pre-wrap;
            }

        `];
    }
};
__decorate([
    property()
], LoveLaceHint.prototype, "hass", void 0);
__decorate([
    property()
], LoveLaceHint.prototype, "configuration", void 0);
__decorate([
    property()
], LoveLaceHint.prototype, "repository", void 0);
LoveLaceHint = __decorate([
    customElement("hacs-lovelace-hint")
], LoveLaceHint);

let RepositoryNote = class RepositoryNote extends LitElement {
    render() {
        return html `
            <div class="repository-note">
            <p>${this.hass.localize(`component.hacs.repository.note_installed`)} '${this.repository.local_path}'

            ${(this.repository.category === "appdaemon" ? html `,
            ${this.hass.localize(`component.hacs.repository.note_${this.repository.category}`)}` : "")}

            ${(this.repository.category === "integration" ? html `,
            ${this.hass.localize(`component.hacs.repository.note_${this.repository.category}`)}` : "")}

            ${(this.repository.category === "plugin" ? html `,
            ${this.hass.localize(`component.hacs.repository.note_${this.repository.category}`)}` : "")}

            .</p>

                ${(this.repository.category === "plugin" ? html `
                    <hacs-lovelace-hint
                        .hass=${this.hass}
                        .configuration=${this.configuration}
                        .repository=${this.repository}
                    ></hacs-lovelace-hint>
                ` : "")}
            </div>
            `;
    }
    static get styles() {
        return [HacsStyle, css `
            .repository-note {
                border-top: 1px solid var(--primary-text-color);
            }
            p {
                font-style: italic;
            }
        `];
    }
};
__decorate([
    property()
], RepositoryNote.prototype, "hass", void 0);
__decorate([
    property()
], RepositoryNote.prototype, "configuration", void 0);
__decorate([
    property()
], RepositoryNote.prototype, "repository", void 0);
RepositoryNote = __decorate([
    customElement("hacs-repository-note")
], RepositoryNote);

let HacsButtonAddToLovelace = class HacsButtonAddToLovelace extends HacsRepositoryButton {
    render() {
        if (!this.repository.installed)
            return html ``;
        if (this.repository.javascript_type === null)
            return html ``;
        return html `
            <mwc-button @click=${this.RepositoryAddToLovelace}>
                Add to Lovelace
            </mwc-button>
        `;
    }
    RepositoryAddToLovelace() {
        if (!window.confirm("Do you want to add this to your lovelace resources?"))
            return;
        this.hass.connection.sendMessagePromise({
            type: 'lovelace/config', force: false
        }).then((resp) => {
            var currentConfig = resp;
            const cardConfig = {
                "type": this.repository.javascript_type,
                "url": `/community_plugin/${this.repository.full_name.split("/")[1]}/${this.repository.file_name}`
            };
            if (currentConfig.resources)
                currentConfig.resources.push(cardConfig);
            else
                currentConfig.resources = [cardConfig];
            this.hass.callWS({ type: 'lovelace/config/save', config: currentConfig });
        }, (err) => {
            console.error(err);
        });
    }
};
__decorate([
    property()
], HacsButtonAddToLovelace.prototype, "lovelaceconfig", void 0);
__decorate([
    property()
], HacsButtonAddToLovelace.prototype, "configuration", void 0);
HacsButtonAddToLovelace = __decorate([
    customElement("hacs-button-add-to-lovelace")
], HacsButtonAddToLovelace);

let RepositoryBannerNote = class RepositoryBannerNote extends LitElement {
    render() {
        if (!this.repository.installed)
            return html ``;
        var message = "";
        var title = "";
        var type = "";
        if (this.repository.status == "pending-restart") {
            type = "alert";
            title = "Restart pending";
            message = `
            You need to restart Home Assistant.
            `;
        }
        else if (this.repository.category == "plugin") {
            if (this.lovelaceconfig !== undefined && !this.status.background_task) {
                var loaded = AddedToLovelace(this.repository, this.lovelaceconfig, this.status);
                if (!loaded) {
                    type = "warning";
                    title = "Not Loaded";
                    message = `
                    This plugin is not added to your Lovelace resources.
                    `;
                }
            }
        }
        if (message.length == 0)
            return html ``;
        if (this.repository.category !== "plugin")
            return html `
            <ha-card header="${title}" class="${type}">
                <div class="card-content">
                    ${message}
                </div>
            </ha-card>
            `;
        return html `
            <ha-card header="${title}" class="${type}">
                <div class="card-content">
                    ${message}
                </div>
                <div class="card-actions">
                    <hacs-button-add-to-lovelace
                        .hass=${this.hass}
                        .configuration=${this.configuration}
                        .repository=${this.repository}
                        .lovelaceconfig=${this.lovelaceconfig}>
                    </hacs-button-add-to-lovelace>
                </div>
            </ha-card>
        `;
    }
    static get styles() {
        return [HacsStyle, css `
            ha-card {
                width: 90%;
                margin-left: 5%;
            }
            .alert {
                background-color: var(--hacs-status-pending-restart);
                color: var(--text-primary-color);
            }
            .warning {
                background-color: var(--hacs-status-pending-update)
                color: var(--primary-text-color);
            }
            .info {
                background-color: var(--primary-background-color)
                color: var(--primary-text-color);
            }
        `];
    }
};
__decorate([
    property()
], RepositoryBannerNote.prototype, "hass", void 0);
__decorate([
    property()
], RepositoryBannerNote.prototype, "repository", void 0);
__decorate([
    property()
], RepositoryBannerNote.prototype, "status", void 0);
__decorate([
    property()
], RepositoryBannerNote.prototype, "configuration", void 0);
__decorate([
    property()
], RepositoryBannerNote.prototype, "lovelaceconfig", void 0);
RepositoryBannerNote = __decorate([
    customElement("hacs-repository-banner-note")
], RepositoryBannerNote);

let HacsPanelRepository = class HacsPanelRepository extends LitElement {
    constructor() {
        super(...arguments);
        this.repository_view = false;
    }
    firstUpdated() {
        if (this.repo === undefined || !this.repo.updated_info) {
            RepositoryWebSocketAction(this.hass, this.repository, "set_state", "other");
            RepositoryWebSocketAction(this.hass, this.repository, "update");
        }
    }
    render() {
        if (this.repository === undefined) {
            return html `
      <hacs-panel
        .hass=${this.hass}
        .configuration=${this.configuration}
        .repositories=${this.repositories}
        .panel=${this.panel}
        .route=${this.route}
        .status=${this.status}
        .repository_view=${this.repository_view}
        .repository=${this.repository}
        .lovelaceconfig=${this.lovelaceconfig}
      >
      </hacs-panel>
      `;
        }
        var _repository = this.repository;
        var _repositories = this.repositories.filter(function (repo) {
            return repo.id === _repository;
        });
        this.repo = _repositories[0];
        if (this.repo === undefined)
            return html `<div class="loader"><paper-spinner active></paper-spinner></div>`;
        if (this.repo.installed) {
            var back = this.hass.localize(`component.hacs.common.installed`);
        }
        else {
            if (this.repo.category === "appdaemon") {
                var FE_cat = "appdaemon_apps";
            }
            else {
                FE_cat = `${this.repo.category}s`;
            }
            var back = this.hass.localize(`component.hacs.common.${FE_cat}`);
        }
        return html `

    <div class="getBack">
      <mwc-button @click=${this.GoBackToStore} title="${back}">
      <ha-icon  icon="mdi:arrow-left"></ha-icon>
        ${this.hass.localize(`component.hacs.repository.back_to`)}
        ${back}
      </mwc-button>
      ${(this.repo.state == "other" ? html `<div class="loader"><paper-spinner active></paper-spinner></div>` : "")}
    </div>

    <hacs-repository-banner-note
      .hass=${this.hass}
      .status=${this.status}
      .repository=${this.repo}
      .lovelaceconfig=${this.lovelaceconfig}
      .configuration=${this.configuration}>
    </hacs-repository-banner-note>

    <ha-card header="${this.repo.name}">
      <hacs-repository-menu .hass=${this.hass} .repository=${this.repo}></hacs-repository-menu>


      <div class="card-content">

        <div class="description addition">
          ${this.repo.description}
        </div>

        <div class="information MobileGrid">
          ${(this.repo.installed ?
            html `
          <div class="version installed">
            <b>${this.hass.localize(`component.hacs.repository.installed`)}: </b> ${this.repo.installed_version}
          </div>
          ` :
            "")}

        ${(String(this.repo.releases.length) === "0" ? html `
              <div class="version-available">
                  <b>${this.hass.localize(`component.hacs.repository.available`)}: </b> ${this.repo.available_version}
              </div>
          ` : html `
              <div class="version-available">
                  <paper-dropdown-menu @value-changed="${this.SetVersion}"
                    label="${this.hass.localize(`component.hacs.repository.available`)}:
                     (${this.hass.localize(`component.hacs.repository.newest`)}: ${this.repo.releases[0]})">
                      <paper-listbox slot="dropdown-content" selected="${this.repo.selected_tag}" attr-for-selected="value">
                          ${this.repo.releases.map(release => html `<paper-item value="${release}">${release}</paper-item>`)}
                          ${(this.repo.full_name !== "hacs/integration" ? html `
                          <paper-item value="${this.repo.default_branch}">${this.repo.default_branch}</paper-item>
                          ` : "")}
                      </paper-listbox>
                  </paper-dropdown-menu>
              </div>`)}
        </div>
        <hacs-authors .hass=${this.hass} .authors=${this.repo.authors}></hacs-authors>
      </div>


      <div class="card-actions MobileGrid">
        <hacs-button-main-action .hass=${this.hass} .repository=${this.repo} .status=${this.status}></hacs-button-main-action>
        <hacs-button-changelog .hass=${this.hass} .repository=${this.repo}></hacs-button-changelog>
        <hacs-button-open-repository .hass=${this.hass} .repository=${this.repo}></hacs-button-open-repository>
        ${(this.repo.category === "plugin" ? html `
          <hacs-button-open-plugin .hass=${this.hass} .repository=${this.repo}></hacs-button-open-plugin>
        ` : "")}
        <hacs-button-uninstall class="right" .hass=${this.hass} .repository=${this.repo} .status=${this.status}></hacs-button-uninstall>
      </div>

    </ha-card>

    <ha-card class="additional">
      <div class="card-content">
        <div class="more_info markdown-body">
        <style>${GFM} ${HLJS}</style>
          ${markdown.html(this.repo.additional_info || "")}
        </div>
      <hacs-repository-note
        .hass=${this.hass}
        .configuration=${this.configuration}
        .repository=${this.repo}
      ></hacs-repository-note>
      </div>
    </ha-card>
        `;
    }
    SetVersion(e) {
        if (e.detail.value.length > 0) {
            RepositoryWebSocketAction(this.hass, this.repo.id, "set_state", "other");
            RepositoryWebSocketAction(this.hass, this.repo.id, "set_version", e.detail.value);
        }
    }
    GoBackToStore() {
        this.repository = undefined;
        if (this.repo.installed) {
            this.panel = "installed";
        }
        else {
            this.panel = this.repo.category;
        }
        navigate(this, `/${this._rootPath}/${this.panel}`);
        this.requestUpdate();
    }
    get _rootPath() {
        if (this.route.prefix.split("/")[1] === undefined)
            return "hacs";
        return this.route.prefix.split("/")[1];
    }
    static get styles() {
        return [HacsStyle, css `
      .loader {
        background-color: var(--primary-background-color);
        height: 100%;
        width: 100%;
      }
      paper-spinner {
        position: absolute;
        top: 30%;
        left: 50%;
        transform: translate(-50%, -50%);
        z-index: 99;
        width: 150px;
        height: 150px;
    }
     paper-dropdown-menu {
        width: 80%;
     }
      .description {
        padding-bottom: 16px;
      }
      .version {
        padding-bottom: 8px;
      }
      .options {
        float: right;
        width: 40%;
      }
      .information {
        width: 60%;
      }
      .additional {
        margin-bottom: 108px;
      }
      .getBack {
        margin-top: 8px;
        margin-bottom: 4px;
        margin-left: 5%;
      }
      .right {
        float: right;
      }
      .loading {
        text-align: center;
        width: 100%;
      }
      ha-card {
        width: 90%;
        margin-left: 5%;
      }
      .link-icon {
        color: var(--dark-primary-color);
        margin-right: 8px;
      }

    `];
    }
};
__decorate([
    property()
], HacsPanelRepository.prototype, "hass", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "repositories", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "configuration", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "repository", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "panel", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "route", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "status", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "repository_view", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "repo", void 0);
__decorate([
    property()
], HacsPanelRepository.prototype, "lovelaceconfig", void 0);
HacsPanelRepository = __decorate([
    customElement("hacs-panel-repository")
], HacsPanelRepository);

let CustomRepositories = class CustomRepositories extends LitElement {
    Delete(ev) {
        if (!window.confirm(this.hass.localize("component.hacs.confirm.delete", "item", ev.composedPath()[3].innerText)))
            return;
        var repo = ev.composedPath()[4].repoID;
        RepositoryWebSocketAction(this.hass, repo, "delete");
    }
    Save(ev) {
        var category = ev.composedPath()[2].children[1].selectedItem.category;
        var repo = ev.composedPath()[2].children[0].value;
        RepositoryWebSocketAction(this.hass, repo, "add", category);
    }
    render() {
        this.custom = this.repositories.filter(function (repo) {
            if (!repo.custom)
                return false;
            return true;
        });
        return html `
        <ha-card header="${this.hass.localize("component.hacs.settings.custom_repositories")}">
            <div class="card-content">
            <div class="custom-repositories-list">

            ${(this.status.background_task ? html `

            ` : html `
            ${this.custom.sort((a, b) => (a.full_name > b.full_name) ? 1 : -1).map(repo => html `
                <div class="row" .repoID=${repo.id}>
                    <paper-item>
                        ${repo.full_name}
                        <ha-icon
                        title="${(this.hass.localize("component.hacs.settings.delete"))}"
                        class="listicon" icon="mdi:delete"
                        @click=${this.Delete}
                        ></ha-icon>
                    </paper-item>
                </div>
                `)}
            `)}

            </div>
            </div>

            <div class="card-actions">
                <paper-input class="inputfield MobileGrid" placeholder=${(this.hass.localize("component.hacs.settings.add_custom_repository"))} type="text"></paper-input>
                <paper-dropdown-menu class="category MobileGrid"
                label="${this.hass.localize(`component.hacs.settings.category`)}">
                  <paper-listbox slot="dropdown-content" selected="-1">
                      ${this.configuration.categories.map(category => html `
                      <paper-item .category=${category}>
                        ${this.hass.localize(`component.hacs.common.${category}`)}
                      </paper-item>`)}
                  </paper-listbox>
              </paper-dropdown-menu>

              <div class="save">
                <ha-icon title="${(this.hass.localize("component.hacs.settings.save"))}"
                    icon="mdi:content-save"
                    class="saveicon MobileGrid"
                    @click=${this.Save}>
                </ha-icon>
            </div>

        </ha-card>
            `;
    }
    static get styles() {
        return [HacsStyle, css `
            ha-card {
                width: 90%;
                margin-left: 5%;
            }
            .custom-repositories {

            }
            .add-repository {

            }
            .inputfield {
                width: 60%;
            }
            .category {
                position: absolute;
                width: 30%;
                right: 54px;
                bottom: 5px;
            }
            .saveicon {
                color: var(--primary-color);
                position: absolute;
                right: 0;
                bottom: 24px;
                cursor: pointer;
            }
            .listicon {
                color: var(--primary-color);
                right: 0px;
                position: absolute;
                cursor: pointer;
            }
            .loading {
                position: absolute;
                right: 10px;
                bottom: 22px;
            }

            @media screen and (max-width: 600px) and (min-width: 0) {
                .saveicon {
                    height: 64px;
                }
                .save {
                    padding-bottom: 64px;
                }
            }
        `];
    }
};
__decorate([
    property()
], CustomRepositories.prototype, "hass", void 0);
__decorate([
    property()
], CustomRepositories.prototype, "repositories", void 0);
__decorate([
    property()
], CustomRepositories.prototype, "custom", void 0);
__decorate([
    property()
], CustomRepositories.prototype, "status", void 0);
__decorate([
    property()
], CustomRepositories.prototype, "configuration", void 0);
CustomRepositories = __decorate([
    customElement("hacs-custom-repositories")
], CustomRepositories);

let HiddenRepositories = class HiddenRepositories extends LitElement {
    UnHide(ev) {
        var repo = ev.composedPath()[4].repoID;
        RepositoryWebSocketAction(this.hass, repo, "unhide");
    }
    render() {
        this._hidden = this.repositories.filter(function (repo) { return repo.hide; });
        if (this._hidden.length === 0)
            return html ``;
        return html `
        <ha-card header="${this.hass.localize("component.hacs.settings.hidden_repositories").toUpperCase()}">
            <div class="card-content">
            <div class="custom-repositories-list">

            ${this._hidden.sort((a, b) => (a.full_name > b.full_name) ? 1 : -1).map(repo => html `
                <div class="row" .repoID=${repo.id}>
                    <paper-item>
                    <ha-icon
                    title="${this.hass.localize("component.hacs.settings.unhide")}"
                    class="listicon" icon="mdi:restore"
                    @click=${this.UnHide}
                    ></ha-icon>
                        ${repo.full_name}
                    </paper-item>
                </div>
                `)}
            </div>
            </div>
        </ha-card>
            `;
    }
    static get styles() {
        return [HacsStyle, css `
            ha-card {
                width: 90%;
                margin-left: 5%;
            }
            .listicon {
                color: var(--primary-color);
                left: 0px;
            }
        `];
    }
};
__decorate([
    property()
], HiddenRepositories.prototype, "hass", void 0);
__decorate([
    property()
], HiddenRepositories.prototype, "repositories", void 0);
__decorate([
    property()
], HiddenRepositories.prototype, "_hidden", void 0);
HiddenRepositories = __decorate([
    customElement("hacs-hidden-repositories")
], HiddenRepositories);

let HacsPanelSettings = class HacsPanelSettings extends LitElement {
    render() {
        return html `

    <ha-card header="${this.hass.localize("component.hacs.config.title")}">
      <div class="card-content">
        <p><b>${this.hass.localize("component.hacs.common.version")}:</b> ${this.configuration.version}</p>
        <p><b>${this.hass.localize("component.hacs.common.repositories")}:</b> ${this.repositories.length}</p>
        <div class="version-available">
        <ha-switch
          .checked=${this.configuration.frontend_mode === "Table"}
          @change=${this.SetFeStyle}
        >${this.hass.localize(`component.hacs.settings.table_view`)}</ha-switch>
        ${(this.configuration.experimental ? html `
          <ha-switch
            .checked=${this.configuration.frontend_compact}
            @change=${this.SetFeCompact}
          >${this.hass.localize(`component.hacs.settings.compact_mode`)}</ha-switch>
        ` : "")}

    </div>
      </div>
      <div class="card-actions MobileGrid">

      ${(this.status.reloading_data ? html `
        <mwc-button  disabled>
          <paper-spinner active></paper-spinner>
        </mwc-button>
      ` : html `
      ${(this.status.background_task ? html `
        <mwc-button disabled>
          ${this.hass.localize(`component.hacs.settings.reload_data`)}
        </mwc-button>
      ` : html `
        <mwc-button @click=${this.UpgradeAll}>
          ${this.hass.localize(`component.hacs.settings.reload_data`)}
        </mwc-button>
      `)}
      `)}


      ${(this.status.upgrading_all ? html `
          <mwc-button  disabled>
            <paper-spinner active></paper-spinner>
          </mwc-button>
      ` : html `
      ${(this.status.background_task ? html `
        <mwc-button disabled>
          ${this.hass.localize(`component.hacs.settings.upgrade_all`)}
        </mwc-button>
      ` : html `
        <mwc-button @click=${this.UpgradeAll}>
          ${this.hass.localize(`component.hacs.settings.upgrade_all`)}
        </mwc-button>
      `)}
      `)}

      <a href="https://github.com/hacs/integration" target="_blank" rel="noreferrer">
        <mwc-button >
          ${this.hass.localize(`component.hacs.settings.hacs_repo`)}
        </mwc-button>
      </a>

      <a href="https://github.com/hacs/integration/issues" target="_blank" rel="noreferrer">
        <mwc-button >
          ${this.hass.localize(`component.hacs.repository.open_issue`)}
        </mwc-button>
      </a>
      </div>
    </ha-card>
    <hacs-custom-repositories
      .hass=${this.hass}
      .status=${this.status}
      .configuration=${this.configuration}
      .repositories=${this.repositories}
    >
    </hacs-custom-repositories>
    <hacs-hidden-repositories
    .hass=${this.hass}
    .status=${this.status}
    .configuration=${this.configuration}
    .repositories=${this.repositories}
    >
    </hacs-hidden-repositories
          `;
    }
    SetFeStyle() {
        this.hass.connection.sendMessage({
            type: "hacs/settings",
            action: `set_fe_${(this.configuration.frontend_mode !== "Table" ? "table" : "grid")}`
        });
    }
    SetFeCompact() {
        this.hass.connection.sendMessage({
            type: "hacs/settings",
            action: `set_fe_compact_${String(this.configuration.frontend_compact).toLocaleLowerCase()}`
        });
    }
    ReloadData() {
        this.hass.connection.sendMessage({
            type: "hacs/settings",
            action: "reload_data"
        });
    }
    UpgradeAll() {
        var elements = [];
        this.repositories.forEach(element => {
            if (element.pending_upgrade)
                elements.push(element);
        });
        if (elements.length > 0) {
            var msg = "This will upgrade all of these repositores, make sure that you have read the release notes for all of them before proceeding.";
            msg += "\n";
            msg += "\n";
            elements.forEach(element => {
                msg += `${element.name} ${element.installed_version} -> ${element.available_version}\n`;
            });
            if (!window.confirm(msg))
                return;
            this.hass.connection.sendMessage({
                type: "hacs/settings",
                action: "upgrade_all"
            });
        }
        else {
            window.alert("No upgrades pending");
        }
    }
    static get styles() {
        return [HacsStyle, css `
    ha-card {
      width: 90%;
      margin-left: 5%;
    }
    ha-switch {
      margin-bottom: 8px;
    }
    mwc-button {
      margin: 0 8px 0 8px;
    }
    `];
    }
};
__decorate([
    property()
], HacsPanelSettings.prototype, "hass", void 0);
__decorate([
    property()
], HacsPanelSettings.prototype, "repositories", void 0);
__decorate([
    property()
], HacsPanelSettings.prototype, "configuration", void 0);
__decorate([
    property()
], HacsPanelSettings.prototype, "status", void 0);
HacsPanelSettings = __decorate([
    customElement("hacs-panel-settings")
], HacsPanelSettings);

let HacsProgressbar = class HacsProgressbar extends LitElement {
    render() {
        if (!this.status.background_task)
            return html ``;
        return html `
            <paper-progress indeterminate></paper-progress>
        `;
    }
    static get styles() {
        return [HacsStyle, css `
            paper-progress {
                width: 100%;
                --paper-progress-active-color: var(--accent-color);
            }
        `];
    }
};
__decorate([
    property()
], HacsProgressbar.prototype, "status", void 0);
HacsProgressbar = __decorate([
    customElement("hacs-progressbar")
], HacsProgressbar);

let HacsError = class HacsError extends LitElement {
    constructor() {
        super(...arguments);
        this.error = undefined;
    }
    clearError() {
        this.error = undefined;
    }
    firstUpdated() {
        this.hass.connection.subscribeEvents((msg) => this.error = msg.data, "hacs/error");
    }
    render() {
        if (this.error === undefined)
            return html ``;
        var message = this.error.message;
        var additional = "";
        if (this.error.action === "add_repository") {
            additional = "Could not add this repository, make sure it is compliant with HACS.";
        }
        return html `
            <ha-card header="An error ocoured while prosessing" class="alert">
                <div class="card-content">
                    ${message} </br>
                    ${additional}
                </div>
            <div class="card-actions">
                <mwc-button @click=${this.clearError}>
                    Acknowledge
                </mwc-button>
            ${(this.error.action === "add_repository" ? html `
            <a href="https://hacs.xyz/docs/publish/start" rel='noreferrer' target="_blank">
                <mwc-button>
                    Documentation
                </mwc-button>
            </a>
            ` : "")}
            </div>
            </ha-card>
            `;
    }
    static get styles() {
        return [HacsStyle, css `
            ha-card {
                width: 90%;
                margin-left: 5%;
            }
            .alert {
                background-color: var(--hacs-status-pending-restart);
                color: var(--text-primary-color);
            }
        `];
    }
};
__decorate([
    property()
], HacsError.prototype, "hass", void 0);
__decorate([
    property()
], HacsError.prototype, "error", void 0);
HacsError = __decorate([
    customElement("hacs-error")
], HacsError);

let HacsCritical = class HacsCritical extends LitElement {
    async Acknowledge(ev) {
        var repository = ev.composedPath()[3].repository;
        const resp = await this.hass.connection.sendMessagePromise({
            type: "hacs/critical",
            repository: repository
        });
        this.critical = resp.data;
    }
    render() {
        if (this.critical === undefined)
            return html ``;
        var _critical = [];
        this.critical.forEach(element => {
            if (!element.acknowledged)
                _critical.push(element);
        });
        return html `
            ${_critical.map(repo => html `
            <ha-card header="Critical Issue!" class="alert">
                <div class="card-content">
                    The repository "${repo.repository}" has been flagged as a critical repository.</br>
                    The repository has now been uninstalled and removed.</br>
                    For information about how and why these are handled, see
                    <a href="https://hacs.xyz/docs/developer/maintaner#critical-repositories">
                        https://hacs.xyz/docs/developer/maintaner#critical-repositories
                    </a></br>
                    As a result of this Home Assistant was also restarted.</br></br>

                    <b>Reason: </b>${repo.reason}
                </div>
                <div class="card-actions">
                    <mwc-button @click=${this.Acknowledge} .repository=${repo.repository}>
                        Acknowledge
                    </mwc-button>
                    <a href="${repo.link}" rel='noreferrer' target="_blank">
                        <mwc-button>
                            More information about this incident
                        </mwc-button>
                    </a>
                </div>
            </ha-card>`)}
            `;
    }
    static get styles() {
        return [HacsStyle, css `
            ha-card {
                width: 90%;
                margin-left: 5%;
            }
            .alert {
                background-color: var(--hacs-status-pending-restart);
                color: var(--text-primary-color);
            }
        `];
    }
};
__decorate([
    property()
], HacsCritical.prototype, "hass", void 0);
__decorate([
    property()
], HacsCritical.prototype, "critical", void 0);
HacsCritical = __decorate([
    customElement("hacs-critical")
], HacsCritical);

let HacsFrontendBase = class HacsFrontendBase extends LitElement {
    constructor() {
        super(...arguments);
        this.repository_view = false;
    }
    getRepositories() {
        this.hass.connection.sendMessagePromise({
            type: "hacs/repositories"
        }).then((resp) => {
            this.repositories = resp;
            this.requestUpdate();
        }, (err) => {
            console.error('[hacs/repositories] Message failed!', err);
        });
    }
    getConfig() {
        this.hass.connection.sendMessagePromise({
            type: "hacs/config"
        }).then((resp) => {
            this.configuration = resp;
            this.requestUpdate();
        }, (err) => {
            console.error('[hacs/config] Message failed!', err);
        });
    }
    getCritical() {
        this.hass.connection.sendMessagePromise({
            type: "hacs/get_critical"
        }).then((resp) => {
            this.critical = resp;
            this.requestUpdate();
        }, (err) => {
            console.error('[hacs/get_critical] Message failed!', err);
        });
    }
    getStatus() {
        this.hass.connection.sendMessagePromise({
            type: "hacs/status"
        }).then((resp) => {
            this.status = resp;
            this.requestUpdate();
        }, (err) => {
            console.error('[hacs/status] Message failed!', err);
        });
    }
    getLovelaceConfig() {
        this.hass.connection.sendMessagePromise({
            type: 'lovelace/config', force: false
        }).then((resp) => {
            this.lovelaceconfig = resp;
        }, () => {
            this.lovelaceconfig = undefined;
        });
    }
    firstUpdated() {
        window.onpopstate = function () {
            window.location.reload();
        };
        localStorage.setItem("hacs-search", "");
        this.panel = this._page;
        this.getRepositories();
        this.getConfig();
        this.getStatus();
        this.getCritical();
        this.getLovelaceConfig();
        if (/repository\//i.test(this.route.path)) {
            // How fun, this is a repository!
            this.repository_view = true;
            this.repository = this.route.path.split("/")[2];
        }
        else
            this.repository_view = false;
        // "steal" LL elements
        load_lovelace();
        // Event subscription
        this.hass.connection.subscribeEvents(() => this.getRepositories(), "hacs/repository");
        this.hass.connection.subscribeEvents(() => this.getConfig(), "hacs/config");
        this.hass.connection.subscribeEvents(() => this.getStatus(), "hacs/status");
        this.hass.connection.subscribeEvents((e) => this._reload(e), "hacs/reload");
        this.hass.connection.subscribeEvents(() => this.getLovelaceConfig(), "lovelace_updated");
    }
    _reload(e) {
        window.location.reload(e.data.force);
    }
    render() {
        // Handle access to root
        if (this.panel === "") {
            navigate(this, `/${this._rootPath}/installed`);
            this.panel = "installed";
        }
        if (this.repositories === undefined || this.configuration === undefined || this.status === undefined) {
            return html `<div  class="loader"><paper-spinner active></paper-spinner></div>`;
        }
        if (/repository\//i.test(this.route.path)) {
            this.repository_view = true;
            this.repository = this.route.path.split("/")[2];
            this.panel = "repository";
        }
        else
            this.repository_view = false;
        const page = this.panel;
        return html `
    <app-header-layout has-scrolling-region>
      <app-header slot="header" fixed>
        <app-toolbar>
        <ha-menu-button .hass="${this.hass}" .narrow="${this.narrow}"></ha-menu-button>
          <div main-title>Home Assistant Community Store
          ${(this._rootPath === "hacs_dev" ? html `(DEVELOPMENT)` : "")}
          </div>
        </app-toolbar>
      <paper-tabs scrollable attr-for-selected="page-name" .selected=${page} @iron-activate=${this.handlePageSelected}>

        <paper-tab page-name="installed">${this.hass.localize(`component.hacs.common.installed`)}</paper-tab>

        <paper-tab page-name="integration">${this.hass.localize(`component.hacs.common.integrations`)}</paper-tab>

        <paper-tab page-name="plugin">${this.hass.localize(`component.hacs.common.plugins`)}</paper-tab>

        ${(this.configuration.appdaemon
            ? html `<paper-tab page-name="appdaemon">
            ${this.hass.localize(`component.hacs.common.appdaemon_apps`)}
        </paper-tab>` : "")}

        ${(this.configuration.python_script
            ? html `<paper-tab page-name="python_script">
            ${this.hass.localize(`component.hacs.common.python_scripts`)}
        </paper-tab>` : "")}

        ${(this.configuration.theme
            ? html `<paper-tab page-name="theme">
            ${this.hass.localize(`component.hacs.common.themes`)}
        </paper-tab>` : "")}

        <paper-tab page-name="settings">${this.hass.localize("component.hacs.common.settings")}</paper-tab>
      </paper-tabs>
    </app-header>

    <hacs-progressbar .status=${this.status}></hacs-progressbar>

    <hacs-critical .hass=${this.hass} .critical=${this.critical}></hacs-critical>
    <hacs-error .hass=${this.hass}></hacs-error>

    ${(this.panel !== "settings" ? html `
      <hacs-panel
        .hass=${this.hass}
        .configuration=${this.configuration}
        .repositories=${this.repositories}
        .panel=${this.panel}
        .route=${this.route}
        .status=${this.status}
        .repository_view=${this.repository_view}
        .repository=${this.repository}
        .lovelaceconfig=${this.lovelaceconfig}
      >
      </hacs-panel>`
            : html `
      <hacs-panel-settings
        .hass=${this.hass}
        .status=${this.status}
        .configuration=${this.configuration}
        .repositories=${this.repositories}>
      </hacs-panel-settings>`)}
      <hacs-help-button></hacs-help-button>
    </app-header-layout>`;
    }
    handlePageSelected(e) {
        this.repository_view = false;
        const newPage = e.detail.selected;
        this.panel = newPage;
        this.route.path = `/${newPage}`;
        navigate(this, `${this.route.prefix}${this.route.path}`);
        scrollToTarget(this, 
        // @ts-ignore
        this.shadowRoot.querySelector("app-header-layout").header.scrollTarget);
    }
    get _page() {
        if (this.route.path.split("/")[1] === undefined)
            return "installed";
        return this.route.path.split("/")[1];
    }
    get _rootPath() {
        if (this.route.prefix.split("/")[1] === undefined)
            return "hacs";
        return this.route.prefix.split("/")[1];
    }
    static get styles() {
        return [HacsStyle, css `
    .loader {
      background-color: var(--primary-background-color);
      height: 100%;
      width: 100%;
    }
    paper-spinner {
      position: absolute;
      top: 30%;
      left: 50%;
      transform: translate(-50%, -50%);
      z-index: 99;
      width: 150px;
      height: 150px;
   }
    `];
    }
};
__decorate([
    property()
], HacsFrontendBase.prototype, "hass", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "repositories", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "configuration", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "status", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "route", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "critical", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "narrow", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "panel", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "repository", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "repository_view", void 0);
__decorate([
    property()
], HacsFrontendBase.prototype, "lovelaceconfig", void 0);
HacsFrontendBase = __decorate([
    customElement("hacs-frontend")
], HacsFrontendBase);
